Merge m-c to b-s.

This commit is contained in:
Kyle Huey 2011-08-31 07:52:43 -04:00
commit 134b8fad07
900 changed files with 62744 additions and 11638 deletions

View File

@ -1170,8 +1170,7 @@ nsXULTreeGridCellAccessible::GetAttributesInternal(nsIPersistentProperties *aAtt
if (!grandParent)
return NS_OK;
nsCOMPtr<nsIAccessibleTable> tableAccessible =
do_QueryInterface(static_cast<nsIAccessible*>(grandParent));
nsCOMPtr<nsIAccessibleTable> tableAccessible = do_QueryObject(grandParent);
// XXX - temp fix for crash bug 516047
if (!tableAccessible)

View File

@ -798,12 +798,6 @@ pref("accessibility.blockautorefresh", false);
// Whether history is enabled or not.
pref("places.history.enabled", true);
// The percentage of system memory that the Places database can use. Out of the
// allowed cache size it will at most use the size of the database file.
// Changes to this value are effective after an application restart.
// Acceptable values are between 0 and 50.
pref("places.database.cache_to_memory_percentage", 6);
// the (maximum) number of the recent visits to sample
// when calculating frecency
pref("places.frecency.numVisits", 10);

View File

@ -2213,8 +2213,12 @@ var gLastOpenDirectory = {
return this._lastDir;
},
set path(val) {
if (!val || !val.exists() || !val.isDirectory())
try {
if (!val || !val.isDirectory())
return;
} catch(e) {
return;
}
this._lastDir = val.clone();
// Don't save the last open directory pref inside the Private Browsing mode
@ -2239,8 +2243,11 @@ function BrowserOpenFileWindow()
fp.displayDirectory = gLastOpenDirectory.path;
if (fp.show() == nsIFilePicker.returnOK) {
if (fp.file && fp.file.exists())
gLastOpenDirectory.path = fp.file.parent.QueryInterface(Ci.nsILocalFile);
try {
if (fp.file)
gLastOpenDirectory.path = fp.file.parent.QueryInterface(Ci.nsILocalFile);
} catch(e) {
}
openTopWin(fp.fileURL.spec);
}
} catch (ex) {
@ -7331,7 +7338,8 @@ var FeedHandler = {
* a page is loaded or the user switches tabs to a page that has feeds.
*/
updateFeeds: function() {
clearTimeout(this._updateFeedTimeout);
if (this._updateFeedTimeout)
clearTimeout(this._updateFeedTimeout);
var feeds = gBrowser.selectedBrowser.feeds;
var haveFeeds = feeds && feeds.length > 0;

View File

@ -540,6 +540,7 @@ var InspectorUI = {
inspecting: false,
treeLoaded: false,
prefEnabledName: "devtools.inspector.enabled",
isDirty: false,
/**
* Toggle the inspector interface elements on or off.
@ -585,7 +586,7 @@ var InspectorUI = {
get defaultSelection()
{
let doc = this.win.document;
return doc.documentElement.lastElementChild;
return doc.documentElement ? doc.documentElement.lastElementChild : null;
},
initializeTreePanel: function IUI_initializeTreePanel()
@ -779,6 +780,8 @@ var InspectorUI = {
this.toolbar.hidden = false;
this.inspectCmd.setAttribute("checked", true);
gBrowser.addProgressListener(InspectorProgressListener);
},
/**
@ -838,6 +841,8 @@ var InspectorUI = {
this.closing = true;
this.toolbar.hidden = true;
gBrowser.removeProgressListener(InspectorProgressListener);
if (!aKeepStore) {
InspectorStore.deleteStore(this.winID);
this.win.removeEventListener("pagehide", this, true);
@ -1315,6 +1320,8 @@ var InspectorUI = {
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
this.isDirty = true;
// event notification
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
null);
@ -1741,9 +1748,122 @@ var InspectorStore = {
}
};
/**
* The InspectorProgressListener object is an nsIWebProgressListener which
* handles onStateChange events for the inspected browser. If the user makes
* changes to the web page and he tries to navigate away, he is prompted to
* confirm page navigation, such that he's given the chance to prevent the loss
* of edits.
*/
var InspectorProgressListener = {
onStateChange:
function IPL_onStateChange(aProgress, aRequest, aFlag, aStatus)
{
// Remove myself if the Inspector is no longer open.
if (!InspectorUI.isTreePanelOpen) {
gBrowser.removeProgressListener(InspectorProgressListener);
return;
}
// Skip non-start states.
if (!(aFlag & Ci.nsIWebProgressListener.STATE_START)) {
return;
}
// If the request is about to happen in a new window, we are not concerned
// about the request.
if (aProgress.DOMWindow != InspectorUI.win) {
return;
}
if (InspectorUI.isDirty) {
this.showNotification(aRequest);
} else {
InspectorUI.closeInspectorUI();
}
},
/**
* Show an asynchronous notification which asks the user to confirm or cancel
* the page navigation request.
*
* @param nsIRequest aRequest
* The request initiated by the user or by the page itself.
* @returns void
*/
showNotification: function IPL_showNotification(aRequest)
{
aRequest.suspend();
let notificationBox = gBrowser.getNotificationBox(InspectorUI.browser);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
if (notification) {
notificationBox.removeNotification(notification, true);
}
let cancelRequest = function onCancelRequest() {
if (aRequest) {
aRequest.cancel(Cr.NS_BINDING_ABORTED);
aRequest.resume(); // needed to allow the connection to be cancelled.
aRequest = null;
}
};
let eventCallback = function onNotificationCallback(aEvent) {
if (aEvent == "removed") {
cancelRequest();
}
};
let buttons = [
{
id: "inspector.confirmNavigationAway.buttonLeave",
label: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonLeave"),
accessKey: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonLeaveAccesskey"),
callback: function onButtonLeave() {
if (aRequest) {
aRequest.resume();
aRequest = null;
InspectorUI.closeInspectorUI();
}
},
},
{
id: "inspector.confirmNavigationAway.buttonStay",
label: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonStay"),
accessKey: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonStayAccesskey"),
callback: cancelRequest
},
];
let message = InspectorUI.strings.
GetStringFromName("confirmNavigationAway.message");
notification = notificationBox.appendNotification(message,
"inspector-page-navigation", "chrome://browser/skin/Info.png",
notificationBox.PRIORITY_WARNING_HIGH, buttons, eventCallback);
// Make sure this not a transient notification, to avoid the automatic
// transient notification removal.
notification.persistence = -1;
},
};
/////////////////////////////////////////////////////////////////////////
//// Initializors
//// Initializers
XPCOMUtils.defineLazyGetter(InspectorUI, "inspectCmd", function () {
return document.getElementById("Tools:Inspect");
});
XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () {
return Services.strings.
createBundle("chrome://browser/locale/inspector.properties");
});

View File

@ -75,8 +75,11 @@ function deleteLocalstore() {
var directoryService = Components.classes[nsIDirectoryServiceContractID]
.getService(nsIProperties);
var localstoreFile = directoryService.get("LStoreS", Components.interfaces.nsIFile);
if (localstoreFile.exists())
try {
localstoreFile.remove(false);
} catch(e) {
Components.utils.reportError(e);
}
}
function disableAddons() {

View File

@ -16,12 +16,6 @@
display: -moz-box;
}
.tab-close-button[selected="true"] {
/* Make this button focusable so clicking on it will not focus the tab while
it's getting closed */
-moz-user-focus: normal;
}
.tab-label[pinned] {
width: 0;
margin-left: 0 !important;

View File

@ -4002,7 +4002,6 @@
role="presentation"/>
<xul:toolbarbutton anonid="close-button"
xbl:inherits="fadein,pinned,selected"
tabindex="-1"
clickthrough="never"
class="tab-close-button"/>
</xul:hbox>
@ -4040,25 +4039,14 @@
<handler event="dragstart" phase="capturing">
this.style.MozUserFocus = '';
</handler>
<handler event="mousedown" button="0" phase="capturing">
<handler event="mousedown">
<![CDATA[
if (this.mOverCloseButton) {
event.stopPropagation();
}
else if (this.selected) {
if (this.selected) {
this.style.MozUserFocus = 'ignore';
this.clientTop; // just using this to flush style updates
}
]]>
</handler>
<handler event="mousedown" button="1">
this.style.MozUserFocus = 'ignore';
this.clientTop;
</handler>
<handler event="mousedown" button="2">
this.style.MozUserFocus = 'ignore';
this.clientTop;
</handler>
<handler event="mouseup">
this.style.MozUserFocus = '';
</handler>

View File

@ -57,6 +57,7 @@ _BROWSER_FILES = \
browser_inspector_registertools.js \
browser_inspector_bug_665880.js \
browser_inspector_editor.js \
browser_inspector_bug_566084_location_changed.js \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let notificationBox = null;
function startLocationTests() {
ok(window.InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null);
InspectorUI.toggleInspectorUI();
}
function runInspectorTests() {
Services.obs.removeObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null);
let para = content.document.querySelector("p");
ok(para, "found the paragraph element");
is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
InspectorUI.isDirty = true;
notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
notificationBox.addEventListener("AlertActive", alertActive1, false);
gBrowser.selectedBrowser.addEventListener("load", onPageLoad, true);
content.location = "data:text/html,<div>location change test 1 for " +
"inspector</div><p>test1</p>";
}
function alertActive1() {
notificationBox.removeEventListener("AlertActive", alertActive1, false);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
ok(notification, "found the inspector-page-navigation notification");
// By closing the notification it is expected that page navigation is
// canceled.
executeSoon(function() {
notification.close();
locationTest2();
});
}
function onPageLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onPageLoad, true);
isnot(content.location.href.indexOf("test2"), -1,
"page navigated to the correct location");
let para = content.document.querySelector("p");
ok(para, "found the paragraph element, third time");
is(para.textContent, "test2", "paragraph content is correct");
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isTreePanelOpen, "Inspector Panel is not open");
testEnd();
}
function locationTest2() {
// Location did not change.
let para = content.document.querySelector("p");
ok(para, "found the paragraph element, second time");
is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
notificationBox.addEventListener("AlertActive", alertActive2, false);
content.location = "data:text/html,<div>location change test 2 for " +
"inspector</div><p>test2</p>";
}
function alertActive2() {
notificationBox.removeEventListener("AlertActive", alertActive2, false);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
ok(notification, "found the inspector-page-navigation notification");
let buttons = notification.querySelectorAll("button");
let buttonLeave = null;
for (let i = 0; i < buttons.length; i++) {
if (buttons[i].buttonInfo.id == "inspector.confirmNavigationAway.buttonLeave") {
buttonLeave = buttons[i];
break;
}
}
ok(buttonLeave, "the Leave page button was found");
// Accept page navigation.
executeSoon(function(){
buttonLeave.doCommand();
});
}
function testEnd() {
notificationBox = null;
InspectorUI.isDirty = false;
gBrowser.removeCurrentTab();
executeSoon(finish);
}
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
waitForFocus(startLocationTests, content);
}, true);
content.location = "data:text/html,<div>location change tests for " +
"inspector.</div><p>init</p>";
}

View File

@ -344,9 +344,11 @@ nsWindowsShellService::IsDefaultBrowserVista(PRBool* aIsDefaultBrowser)
(void**)&pAAR);
if (SUCCEEDED(hr)) {
BOOL res;
hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
APP_REG_NAME,
aIsDefaultBrowser);
&res);
*aIsDefaultBrowser = res;
pAAR->Release();
return PR_TRUE;

View File

@ -280,7 +280,7 @@ var Scratchpad = {
scriptError.initWithWindowID(ex.message + "\n" + ex.stack, ex.fileName,
"", ex.lineNumber, 0, scriptError.errorFlag,
"content javascript",
this.getWindowId(contentWindow));
this.getInnerWindowId(contentWindow));
Services.console.logMessage(scriptError);
}
@ -633,16 +633,16 @@ var Scratchpad = {
},
/**
* Gets the ID of the outer window of the given DOM window object.
* Gets the ID of the inner window of the given DOM window object.
*
* @param nsIDOMWindow aWindow
* @return integer
* the outer window ID
* the inner window ID
*/
getWindowId: function SP_getWindowId(aWindow)
getInnerWindowId: function SP_getInnerWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
},
/**

View File

@ -90,7 +90,7 @@ XPCOMUtils.defineLazyGetter(this, "PropertyPanel", function () {
XPCOMUtils.defineLazyGetter(this, "AutocompletePopup", function () {
var obj = {};
try {
Cu.import("resource://gre/modules/AutocompletePopup.jsm", obj);
Cu.import("resource:///modules/AutocompletePopup.jsm", obj);
}
catch (err) {
Cu.reportError(err);

View File

@ -6,7 +6,7 @@
// Tests that document.body autocompletes in the web console.
Cu.import("resource://gre/modules/PropertyPanel.jsm");
Cu.import("resource:///modules/PropertyPanel.jsm");
function test() {
addTab("data:text/html,Web Console autocompletion bug in document.body");

View File

@ -36,7 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
Cu.import("resource://gre/modules/HUDService.jsm");
Cu.import("resource:///modules/HUDService.jsm");
function log(aMsg)
{

View File

@ -0,0 +1,9 @@
# LOCALIZATION NOTE (confirmNavigationAway): Used in the Inspector tool, when
# the user tries to navigate away from a web page, to confirm the change of
# page.
confirmNavigationAway.message=Leaving this page will close the Inspector and the changes you have made will be lost.
confirmNavigationAway.buttonLeave=Leave Page
confirmNavigationAway.buttonLeaveAccesskey=L
confirmNavigationAway.buttonStay=Stay on Page
confirmNavigationAway.buttonStayAccesskey=S

View File

@ -16,6 +16,7 @@
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties)
locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd)
locale/browser/inspector.properties (%chrome/browser/inspector.properties)
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)
locale/browser/openLocation.properties (%chrome/browser/openLocation.properties)
* locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd)

View File

@ -1868,10 +1868,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
-moz-image-region: rect(0, 16px, 16px, 0);
}
.tab-close-button:focus {
outline: none !important;
}
/* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */
@media all and (-moz-touch-enabled) {

View File

@ -336,6 +336,7 @@ user_pref("browser.console.showInPanel", true);
user_pref("browser.dom.window.dump.enabled", true);
user_pref("browser.firstrun.show.localepicker", false);
user_pref("browser.firstrun.show.uidiscovery", false);
user_pref("browser.ui.layout.tablet", 0); // force tablet UI off
user_pref("dom.allow_scripts_to_close_windows", true);
user_pref("dom.disable_open_during_load", false);
user_pref("dom.max_script_run_time", 0); // no slow script dialogs

View File

@ -3,6 +3,7 @@
package="com.mozilla.watcher"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".WatcherMain"
android:label="@string/app_name">

View File

@ -58,6 +58,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
@ -65,9 +66,12 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.BatteryManager;
import android.os.Debug;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
@ -134,11 +138,26 @@ public class WatcherService extends Service
this.sPingTarget = GetIniData("watcher", "PingTarget", sIniFile, "www.mozilla.org");
sHold = GetIniData("watcher", "delay", sIniFile, "60000");
this.lDelay = Long.parseLong(sHold.trim());
this.lDelay = Long.parseLong(sHold.trim());
sHold = GetIniData("watcher", "period", sIniFile,"300000");
this.lPeriod = Long.parseLong(sHold.trim());
this.lPeriod = Long.parseLong(sHold.trim());
sHold = GetIniData("watcher", "strikes", sIniFile,"3");
this.nMaxStrikes = Integer.parseInt(sHold.trim());
this.nMaxStrikes = Integer.parseInt(sHold.trim());
sHold = GetIniData("watcher", "stayon", sIniFile,"0");
int nStayOn = Integer.parseInt(sHold.trim());
try {
if (nStayOn != 0) {
if (!Settings.System.putInt(getContentResolver(), Settings.System.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC | BatteryManager.BATTERY_PLUGGED_USB)) {
doToast("Screen couldn't be set to Always On [stay on while plugged in]");
}
}
} catch (Exception e) {
e.printStackTrace();
String sExcept = e.getMessage();
doToast("Screen couldn't be set to Always On [exception " + sExcept + "]");
}
doToast("WatcherService created");
}

View File

@ -0,0 +1,68 @@
# -*- makefile -*-
# vim:set ts=8 sw=8 sts=8 noet:
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chase Phillips <chase@mozilla.org>
# Benjamin Smedberg <benjamin@smedbergs.us>
# Jeff Walden <jwalden+code@mit.edu>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
.PHONY: export $(PARALLEL_DIRS_export)
###############
## TIER targets
###############
export_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
#################
## Common targets
#################
ifdef PARALLEL_DIRS
export:: $(PARALLEL_DIRS_export)
$(PARALLEL_DIRS_export): %_export: %/Makefile
+@$(call SUBMAKE,export,$*)
endif
export:: $(SUBMAKEFILES) $(MAKE_DIRS) $(if $(XPIDLSRCS),$(IDL_DIR))
$(LOOP_OVER_DIRS)
$(LOOP_OVER_TOOL_DIRS)

View File

@ -0,0 +1,141 @@
# -*- makefile -*-
# vim:set ts=8 sw=8 sts=8 noet:
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chase Phillips <chase@mozilla.org>
# Benjamin Smedberg <benjamin@smedbergs.us>
# Jeff Walden <jwalden+code@mit.edu>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
.PHONY: libs $(PARALLEL_DIRS_libs)
###############
## TIER targets
###############
libs_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
#################
## Common targets
#################
ifdef PARALLEL_DIRS
libs:: $(PARALLEL_DIRS_libs)
$(PARALLEL_DIRS_libs): %_libs: %/Makefile
+@$(call SUBMAKE,libs,$*)
endif
####################
##
####################
ifdef EXPORT_LIBRARY
ifeq ($(EXPORT_LIBRARY),1)
ifdef IS_COMPONENT
EXPORT_LIBRARY = $(DEPTH)/staticlib/components
else
EXPORT_LIBRARY = $(DEPTH)/staticlib
endif
else
# If EXPORT_LIBRARY has a value, we'll be installing there. We also need to cleanup there
GARBAGE += $(foreach lib,$(LIBRARY),$(EXPORT_LIBRARY)/$(lib))
endif
endif # EXPORT_LIBRARY
libs:: $(SUBMAKEFILES) $(MAKE_DIRS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) $(HOST_PROGRAM) $(PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(SIMPLE_PROGRAMS) $(JAVA_LIBRARY)
ifndef NO_DIST_INSTALL
ifdef LIBRARY
ifdef EXPORT_LIBRARY # Stage libs that will be linked into a static build
$(INSTALL) $(IFLAGS1) $(LIBRARY) $(EXPORT_LIBRARY)
endif # EXPORT_LIBRARY
ifdef DIST_INSTALL
ifdef IS_COMPONENT
$(error Shipping static component libs makes no sense.)
else
$(INSTALL) $(IFLAGS1) $(LIBRARY) $(DIST)/lib
endif
endif # DIST_INSTALL
endif # LIBRARY
ifdef SHARED_LIBRARY
ifdef IS_COMPONENT
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
ifndef NO_COMPONENTS_MANIFEST
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest"
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)"
endif
else # ! IS_COMPONENT
ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
ifndef NO_INSTALL_IMPORT_LIBRARY
$(INSTALL) $(IFLAGS2) $(IMPORT_LIBRARY) $(DIST)/lib
endif
else
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DIST)/lib
endif
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)
endif # IS_COMPONENT
endif # SHARED_LIBRARY
ifdef PROGRAM
$(INSTALL) $(IFLAGS2) $(PROGRAM) $(FINAL_TARGET)
endif
ifdef SIMPLE_PROGRAMS
$(INSTALL) $(IFLAGS2) $(SIMPLE_PROGRAMS) $(FINAL_TARGET)
endif
ifdef HOST_PROGRAM
$(INSTALL) $(IFLAGS2) $(HOST_PROGRAM) $(DIST)/host/bin
endif
ifdef HOST_SIMPLE_PROGRAMS
$(INSTALL) $(IFLAGS2) $(HOST_SIMPLE_PROGRAMS) $(DIST)/host/bin
endif
ifdef HOST_LIBRARY
$(INSTALL) $(IFLAGS1) $(HOST_LIBRARY) $(DIST)/host/lib
endif
ifdef JAVA_LIBRARY
ifdef IS_COMPONENT
$(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)/components
else
$(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)
endif
endif # JAVA_LIBRARY
endif # !NO_DIST_INSTALL
$(LOOP_OVER_DIRS)
# EOF

View File

@ -0,0 +1,72 @@
# -*- makefile -*-
# vim:set ts=8 sw=8 sts=8 noet:
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# The Mozilla Foundation
# Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chase Phillips <chase@mozilla.org>
# Benjamin Smedberg <benjamin@smedbergs.us>
# Jeff Walden <jwalden+code@mit.edu>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
.PHONY: tools $(PARALLEL_DIRS_tools)
###############
## TIER targets
###############
tools_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
#################
## Common targets
#################
ifdef PARALLEL_DIRS
tools:: $(PARALLEL_DIRS_tools)
$(PARALLEL_DIRS_tools): %_tools: %/Makefile
+@$(call SUBMAKE,tools,$*)
endif
tools:: $(SUBMAKEFILES) $(MAKE_DIRS)
$(LOOP_OVER_DIRS)
ifneq (,$(strip $(TOOL_DIRS)))
$(foreach dir,$(TOOL_DIRS),$(call SUBMAKE,libs,$(dir)))
endif
# EOF

View File

@ -1,3 +1,4 @@
# -*- makefile -*-
# vim:set ts=8 sw=8 sts=8 noet:
#
# ***** BEGIN LICENSE BLOCK *****
@ -24,6 +25,7 @@
# Chase Phillips <chase@mozilla.org>
# Benjamin Smedberg <benjamin@smedbergs.us>
# Jeff Walden <jwalden+code@mit.edu>
# Joey Armstrong <joey@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
@ -489,15 +491,6 @@ LOOP_OVER_TOOL_DIRS = \
$(foreach dir,$(TOOL_DIRS),$(call SUBMAKE,$@,$(dir)))
endif
ifdef PARALLEL_DIRS
# create a bunch of fake targets for order-only processing
PARALLEL_DIRS_export = $(addsuffix _export,$(PARALLEL_DIRS))
PARALLEL_DIRS_libs = $(addsuffix _libs,$(PARALLEL_DIRS))
PARALLEL_DIRS_tools = $(addsuffix _tools,$(PARALLEL_DIRS))
.PHONY: $(PARALLEL_DIRS_export) $(PARALLEL_DIRS_libs) $(PARALLEL_DIRS_tools)
endif
#
# Now we can differentiate between objects used to build a library, and
# objects used to build an executable in the same directory.
@ -736,21 +729,6 @@ endif
MAKE_TIER_SUBMAKEFILES = +$(if $(tier_$*_dirs),$(MAKE) $(addsuffix /Makefile,$(tier_$*_dirs)))
export_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,export,$(dir)))
libs_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,libs,$(dir)))
tools_tier_%:
@$(ECHO) "$@"
@$(MAKE_TIER_SUBMAKEFILES)
$(foreach dir,$(tier_$*_dirs),$(call SUBMAKE,tools,$(dir)))
$(foreach tier,$(TIERS),tier_$(tier))::
@$(ECHO) "$@: $($@_staticdirs) $($@_dirs)"
$(foreach dir,$($@_staticdirs),$(call SUBMAKE,,$(dir)))
@ -774,29 +752,8 @@ ifneq (,$(DIRS)$(TOOL_DIRS)$(PARALLEL_DIRS))
$(LOOP_OVER_TOOL_DIRS)
endif
ifdef PARALLEL_DIRS
export:: $(PARALLEL_DIRS_export)
$(PARALLEL_DIRS_export): %_export: %/Makefile
+@$(call SUBMAKE,export,$*)
endif
export:: $(SUBMAKEFILES) $(MAKE_DIRS) $(if $(XPIDLSRCS),$(IDL_DIR))
$(LOOP_OVER_DIRS)
$(LOOP_OVER_TOOL_DIRS)
ifdef PARALLEL_DIRS
tools:: $(PARALLEL_DIRS_tools)
$(PARALLEL_DIRS_tools): %_tools: %/Makefile
+@$(call SUBMAKE,tools,$*)
endif
tools:: $(SUBMAKEFILES) $(MAKE_DIRS)
$(LOOP_OVER_DIRS)
ifneq (,$(strip $(TOOL_DIRS)))
$(foreach dir,$(TOOL_DIRS),$(call SUBMAKE,libs,$(dir)))
endif
include $(topsrcdir)/config/makefiles/target_export.mk
include $(topsrcdir)/config/makefiles/target_tools.mk
#
# Rule to create list of libraries for final link
@ -826,86 +783,9 @@ DSO_LDOPTS_DEPS = $(call DO_EXPAND_LIBS,$(EXTRA_DSO_LIBS) $(filter %.$(LIB_SUFFI
GLOBAL_DEPS += Makefile Makefile.in $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
##############################################
ifdef PARALLEL_DIRS
libs:: $(PARALLEL_DIRS_libs)
$(PARALLEL_DIRS_libs): %_libs: %/Makefile
+@$(call SUBMAKE,libs,$*)
endif
ifdef EXPORT_LIBRARY
ifeq ($(EXPORT_LIBRARY),1)
ifdef IS_COMPONENT
EXPORT_LIBRARY = $(DEPTH)/staticlib/components
else
EXPORT_LIBRARY = $(DEPTH)/staticlib
endif
else
# If EXPORT_LIBRARY has a value, we'll be installing there. We also need to cleanup there
GARBAGE += $(foreach lib,$(LIBRARY),$(EXPORT_LIBRARY)/$(lib))
endif
endif # EXPORT_LIBRARY
libs:: $(SUBMAKEFILES) $(MAKE_DIRS) $(HOST_LIBRARY) $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) $(HOST_PROGRAM) $(PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(SIMPLE_PROGRAMS) $(JAVA_LIBRARY)
ifndef NO_DIST_INSTALL
ifdef LIBRARY
ifdef EXPORT_LIBRARY # Stage libs that will be linked into a static build
$(INSTALL) $(IFLAGS1) $(LIBRARY) $(EXPORT_LIBRARY)
endif # EXPORT_LIBRARY
ifdef DIST_INSTALL
ifdef IS_COMPONENT
$(error Shipping static component libs makes no sense.)
else
$(INSTALL) $(IFLAGS1) $(LIBRARY) $(DIST)/lib
endif
endif # DIST_INSTALL
endif # LIBRARY
ifdef SHARED_LIBRARY
ifdef IS_COMPONENT
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
ifndef NO_COMPONENTS_MANIFEST
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest"
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)"
endif
else # ! IS_COMPONENT
ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
ifndef NO_INSTALL_IMPORT_LIBRARY
$(INSTALL) $(IFLAGS2) $(IMPORT_LIBRARY) $(DIST)/lib
endif
else
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DIST)/lib
endif
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)
endif # IS_COMPONENT
endif # SHARED_LIBRARY
ifdef PROGRAM
$(INSTALL) $(IFLAGS2) $(PROGRAM) $(FINAL_TARGET)
endif
ifdef SIMPLE_PROGRAMS
$(INSTALL) $(IFLAGS2) $(SIMPLE_PROGRAMS) $(FINAL_TARGET)
endif
ifdef HOST_PROGRAM
$(INSTALL) $(IFLAGS2) $(HOST_PROGRAM) $(DIST)/host/bin
endif
ifdef HOST_SIMPLE_PROGRAMS
$(INSTALL) $(IFLAGS2) $(HOST_SIMPLE_PROGRAMS) $(DIST)/host/bin
endif
ifdef HOST_LIBRARY
$(INSTALL) $(IFLAGS1) $(HOST_LIBRARY) $(DIST)/host/lib
endif
ifdef JAVA_LIBRARY
ifdef IS_COMPONENT
$(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)/components
else
$(INSTALL) $(IFLAGS1) $(JAVA_LIBRARY) $(FINAL_TARGET)
endif
endif # JAVA_LIBRARY
endif # !NO_DIST_INSTALL
$(LOOP_OVER_DIRS)
include $(topsrcdir)/config/makefiles/target_libs.mk
##############################################
ifndef NO_PROFILE_GUIDED_OPTIMIZE
ifdef MOZ_PROFILE_USE
ifeq ($(OS_ARCH)_$(GNU_CC), WINNT_)

View File

@ -743,8 +743,8 @@ public:
* @param aColumnNumber Column number within resource containing error.
* @param aErrorFlags See nsIScriptError.
* @param aCategory Name of module reporting error.
* @param [aWindowId=0] (Optional) The window ID of the outer window the
* message originates from.
* @param [aInnerWindowId=0] (Optional) The window ID of the inner window
* the message originates from.
*/
enum PropertiesFile {
eCSS_PROPERTIES,
@ -769,7 +769,7 @@ public:
PRUint32 aColumnNumber,
PRUint32 aErrorFlags,
const char *aCategory,
PRUint64 aWindowId = 0);
PRUint64 aInnerWindowId = 0);
/**
* Report a localized error message to the error console.

View File

@ -720,6 +720,15 @@ public:
return window ? window->WindowID() : 0;
}
/**
* Return the inner window ID.
*/
PRUint64 InnerWindowID()
{
nsPIDOMWindow *window = GetInnerWindow();
return window ? window->WindowID() : 0;
}
/**
* Get the script loader for this document
*/

View File

@ -2733,7 +2733,7 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
PRUint32 aColumnNumber,
PRUint32 aErrorFlags,
const char *aCategory,
PRUint64 aWindowId)
PRUint64 aInnerWindowId)
{
NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
"Supply either both parameters and their number or no"
@ -2767,7 +2767,8 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
NS_ConvertUTF8toUTF16(spec).get(), // file name
aSourceLine.get(),
aLineNumber, aColumnNumber,
aErrorFlags, aCategory, aWindowId);
aErrorFlags, aCategory,
aInnerWindowId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(errorObject);
@ -2788,17 +2789,17 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
nsIDocument* aDocument)
{
nsIURI* uri = aURI;
PRUint64 windowID = 0;
PRUint64 innerWindowID = 0;
if (aDocument) {
if (!uri) {
uri = aDocument->GetDocumentURI();
}
windowID = aDocument->OuterWindowID();
innerWindowID = aDocument->InnerWindowID();
}
return ReportToConsole(aFile, aMessageName, aParams, aParamsLength, uri,
aSourceLine, aLineNumber, aColumnNumber, aErrorFlags,
aCategory, windowID);
aCategory, innerWindowID);
}
PRBool

View File

@ -2739,8 +2739,7 @@ nsDocument::GetActiveElement(nsIDOMElement **aElement)
}
// No focused element anywhere in this document. Try to get the BODY.
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc =
do_QueryInterface(static_cast<nsIDocument*>(this));
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryObject(this);
if (htmlDoc) {
nsCOMPtr<nsIDOMHTMLElement> bodyElement;
htmlDoc->GetBody(getter_AddRefs(bodyElement));

View File

@ -85,7 +85,7 @@ nsEventSource::nsEventSource() :
mLastConvertionResult(NS_OK),
mReadyState(nsIEventSource::CONNECTING),
mScriptLine(0),
mWindowID(0)
mInnerWindowID(0)
{
}
@ -253,7 +253,7 @@ nsEventSource::Init(nsIPrincipal* aPrincipal,
mScriptFile.AssignASCII(filename);
}
mWindowID = nsJSUtils::GetCurrentlyRunningCodeWindowID(cx);
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
}
// Get the load group for the page. When requesting we'll add ourselves to it.
@ -1072,7 +1072,7 @@ nsEventSource::PrintErrorOnConsole(const char *aBundleURI,
nsnull,
mScriptLine, 0,
nsIScriptError::errorFlag,
"Event Source", mWindowID);
"Event Source", mInnerWindowID);
// print the error message directly to the JS console
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(errObj);

View File

@ -252,12 +252,12 @@ protected:
// Event Source owner information:
// - the script file name
// - source code line number where the Event Source object was constructed.
// - the window ID of the outer window where the script lives. Note that this
// may not be the same as the Event Source owner window.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Event Source owner window.
// These attributes are used for error reporting.
nsString mScriptFile;
PRUint32 mScriptLine;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
private:
nsEventSource(const nsEventSource& x); // prevent bad usage

View File

@ -457,8 +457,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
// messageManager is wrapped in TabChildGlobal.
nsCOMPtr<nsISupports> defaultThisValue;
if (mChrome) {
defaultThisValue =
do_QueryInterface(static_cast<nsIContentFrameMessageManager*>(this));
defaultThisValue = do_QueryObject(this);
} else {
defaultThisValue = aTarget;
}

View File

@ -4874,8 +4874,7 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
NS_ENSURE_SUCCESS(rv, rv);
if (hasMutationListeners) {
nsCOMPtr<nsIDOMEventTarget> node =
do_QueryInterface(static_cast<nsIContent *>(this));
nsCOMPtr<nsIDOMEventTarget> node = do_QueryObject(this);
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED);
mutation.mRelatedNode = attrNode;

View File

@ -357,7 +357,7 @@ nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI,
NS_ConvertUTF8toUTF16(mOwner->GetScriptFile()).get(),
nsnull,
mOwner->GetScriptLine(), 0, nsIScriptError::errorFlag,
"Web Socket", mOwner->WindowID()
"Web Socket", mOwner->InnerWindowID()
);
// print the error message directly to the JS console
@ -631,7 +631,7 @@ nsWebSocket::nsWebSocket() : mKeepingAlive(PR_FALSE),
mReadyState(nsIMozWebSocket::CONNECTING),
mOutgoingBufferedAmount(0),
mScriptLine(0),
mWindowID(0)
mInnerWindowID(0)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
}
@ -1428,7 +1428,7 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
}
}
mWindowID = nsJSUtils::GetCurrentlyRunningCodeWindowID(cx);
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
}
// parses the url

View File

@ -99,7 +99,7 @@ public:
// Determine if preferences allow WebSocket
static PRBool PrefEnabled();
const PRUint64 WindowID() const { return mWindowID; }
const PRUint64 InnerWindowID() const { return mInnerWindowID; }
const nsCString& GetScriptFile() const { return mScriptFile; }
const PRUint32 GetScriptLine() const { return mScriptLine; }
@ -164,12 +164,12 @@ protected:
// Web Socket owner information:
// - the script file name, UTF8 encoded.
// - source code line number where the Web Socket object was constructed.
// - the window ID of the outer window where the script lives. Note that this
// may not be the same as the Web Socket owner window.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Web Socket owner window.
// These attributes are used for error reporting.
nsCString mScriptFile;
PRUint32 mScriptLine;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
private:
nsWebSocket(const nsWebSocket& x); // prevent bad usage

View File

@ -3969,6 +3969,7 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
SH_WEBGL_SPEC,
gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,
&resources);
nsPromiseFlatCString src(shader->Source());

View File

@ -339,7 +339,9 @@ public:
// nsICanvasRenderingContextInternal
NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
void Initialize(nsIDocShell *shell, PRInt32 width, PRInt32 height);
NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
PRBool EnsureSurface();
NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions,
@ -380,7 +382,7 @@ public:
{
public:
PathAutoSaveRestore(nsCanvasRenderingContext2D* aCtx) :
mContext(aCtx->mThebes)
mContext(aCtx->mThebes)
{
if (aCtx->mHasPath) {
mPath = mContext->CopyPath();
@ -460,12 +462,16 @@ protected:
return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
}
// Initialize the Thebes rendering context
void CreateThebes();
// If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell;
// our drawing surfaces, contexts, and layers
nsRefPtr<gfxContext> mThebes;
nsRefPtr<gfxASurface> mSurface;
PRPackedBool mSurfaceCreated;
PRUint32 mSaveCount;
@ -527,6 +533,11 @@ protected:
*/
PRBool NeedToUseIntermediateSurface()
{
if (!mThebes) {
// Haven't created a surface yet, default is OVER.
return OperatorAffectsUncoveredAreas(gfxContext::OPERATOR_OVER);
}
// certain operators always need an intermediate surface, except
// with quartz since quartz does compositing differently than cairo
return OperatorAffectsUncoveredAreas(mThebes->CurrentOperator());
@ -541,6 +552,11 @@ protected:
*/
void ClearSurfaceForUnboundedSource()
{
if (!mThebes) {
// Haven't created a surface yet, default is OVER.
return;
}
gfxContext::GraphicsOperator current = mThebes->CurrentOperator();
if (current != gfxContext::OPERATOR_SOURCE)
return;
@ -597,8 +613,7 @@ protected:
* Gets the pres shell from either the canvas element or the doc shell
*/
nsIPresShell *GetPresShell() {
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
if (content) {
nsIDocument* ownerDoc = content->GetOwnerDoc();
return ownerDoc ? ownerDoc->GetShell() : nsnull;
@ -965,6 +980,10 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
return;
}
if (!EnsureSurface()) {
return;
}
// if not using global alpha, don't optimize with dirty bit
if (aUseGlobalAlpha)
mDirtyStyle[aWhichStyle] = PR_FALSE;
@ -1059,70 +1078,13 @@ nsCanvasRenderingContext2D::RedrawUser(const gfxRect& r)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
{
nsRefPtr<gfxASurface> surface;
// Check that the dimensions are sane
gfxIntSize size(width, height);
if (gfxASurface::CheckSurfaceSize(size, 0xffff)) {
// Zero sized surfaces have problems, so just use a 1 by 1.
if (height == 0 || width == 0) {
mZero = PR_TRUE;
height = 1;
width = 1;
} else {
mZero = PR_FALSE;
}
gfxASurface::gfxImageFormat format = GetImageFormat();
if (!PR_GetEnv("MOZ_CANVAS_IMAGE_SURFACE")) {
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
nsIDocument* ownerDoc = nsnull;
if (content)
ownerDoc = content->GetOwnerDoc();
nsRefPtr<LayerManager> layerManager = nsnull;
if (ownerDoc)
layerManager =
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
if (layerManager) {
surface = layerManager->CreateOptimalSurface(gfxIntSize(width, height), format);
} else {
surface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(width, height), gfxASurface::ContentFromFormat(format));
}
}
if (!surface || surface->CairoStatus()) {
// If we couldn't create a surface of the type we want, fall back
// to an image surface. This lets us handle surface sizes that
// the underlying cairo backend might not handle.
surface = new gfxImageSurface(gfxIntSize(width, height), format);
if (!surface || surface->CairoStatus()) {
surface = nsnull;
}
}
}
if (surface) {
if (gCanvasMemoryReporter == nsnull) {
gCanvasMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasMemory);
NS_RegisterMemoryReporter(gCanvasMemoryReporter);
}
gCanvasMemoryUsed += width * height * 4;
JSContext* context = nsContentUtils::GetCurrentJSContext();
if (context) {
JS_updateMallocCounter(context, width * height * 4);
}
}
return InitializeWithSurface(NULL, surface, width, height);
Initialize(NULL, width, height);
return NS_OK;
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) {
void
nsCanvasRenderingContext2D::Initialize(nsIDocShell *docShell, PRInt32 width, PRInt32 height)
{
Reset();
NS_ASSERTION(!docShell ^ !mCanvasElement, "Cannot set both docshell and canvas element");
@ -1131,19 +1093,9 @@ nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASur
mWidth = width;
mHeight = height;
mSurface = surface;
mThebes = surface ? new gfxContext(mSurface) : nsnull;
mResetLayer = PR_TRUE;
/* Create dummy surfaces here */
if (mSurface == nsnull || mSurface->CairoStatus() != 0 ||
mThebes == nsnull || mThebes->HasError())
{
mSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
mThebes = new gfxContext(mSurface);
} else {
mValid = PR_TRUE;
}
mValid = PR_TRUE;
mSurfaceCreated = PR_FALSE;
// set up the initial canvas defaults
mStyleStack.Clear();
@ -1157,6 +1109,19 @@ nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASur
state->colorStyles[STYLE_SHADOW] = NS_RGBA(0,0,0,0);
DirtyAllStyles();
// always force a redraw, because if the surface dimensions were reset
// then the surface became cleared, and we need to redraw everything.
Redraw();
return;
}
void
nsCanvasRenderingContext2D::CreateThebes()
{
mThebes = new gfxContext(mSurface);
mSurfaceCreated = PR_TRUE;
mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
mThebes->NewPath();
mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
@ -1167,17 +1132,105 @@ nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASur
mThebes->SetMiterLimit(10.0);
mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
mThebes->SetFillRule(gfxContext::FILL_RULE_WINDING);
mThebes->NewPath();
}
// always force a redraw, because if the surface dimensions were reset
// then the surface became cleared, and we need to redraw everything.
Redraw();
NS_IMETHODIMP
nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell,
gfxASurface *surface,
PRInt32 width,
PRInt32 height)
{
Initialize(docShell, width, height);
mSurface = surface;
CreateThebes();
return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
PRBool
nsCanvasRenderingContext2D::EnsureSurface()
{
if (!mValid) {
return PR_FALSE;
}
if (mSurface && mThebes && mSurfaceCreated) {
if (mSurface->CairoStatus()) {
return PR_FALSE;
}
return PR_TRUE;
}
nsRefPtr<gfxASurface> surface;
// Check that the dimensions are sane
if (gfxASurface::CheckSurfaceSize(gfxIntSize(mWidth, mHeight), 0xffff)) {
// Zero sized surfaces have problems, so just use a 1 by 1.
if (mHeight == 0 || mWidth == 0) {
mZero = PR_TRUE;
mHeight = 1;
mWidth = 1;
} else {
mZero = PR_FALSE;
}
gfxASurface::gfxImageFormat format = GetImageFormat();
if (!PR_GetEnv("MOZ_CANVAS_IMAGE_SURFACE")) {
nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
nsIDocument* ownerDoc = nsnull;
if (content)
ownerDoc = content->GetOwnerDoc();
nsRefPtr<LayerManager> layerManager = nsnull;
if (ownerDoc)
layerManager =
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
if (layerManager) {
surface = layerManager->CreateOptimalSurface(gfxIntSize(mWidth, mHeight), format);
} else {
surface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(mWidth, mHeight), gfxASurface::ContentFromFormat(format));
}
}
if (!surface || surface->CairoStatus()) {
// If we couldn't create a surface of the type we want, fall back
// to an image surface. This lets us handle surface sizes that
// the underlying cairo backend might not handle.
surface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
if (!surface || surface->CairoStatus()) {
surface = nsnull;
}
}
}
if (surface) {
if (gCanvasMemoryReporter == nsnull) {
gCanvasMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasMemory);
NS_RegisterMemoryReporter(gCanvasMemoryReporter);
}
gCanvasMemoryUsed += mWidth * mHeight * 4;
JSContext* context = nsContentUtils::GetCurrentJSContext();
if (context) {
JS_updateMallocCounter(context, mWidth * mHeight * 4);
}
} else {
return PR_FALSE;
}
mSurface = surface;
CreateThebes();
if (mSurface->CairoStatus()) {
return PR_FALSE;
}
return PR_TRUE;
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetIsOpaque(PRBool isOpaque)
{
@ -1219,9 +1272,7 @@ nsCanvasRenderingContext2D::Render(gfxContext *ctx, gfxPattern::GraphicsFilter a
{
nsresult rv = NS_OK;
if (!mValid || !mSurface ||
mSurface->CairoStatus() ||
mThebes->HasError())
if (!EnsureSurface())
return NS_ERROR_FAILURE;
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
@ -1250,9 +1301,7 @@ nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
{
if (!mValid || !mSurface ||
mSurface->CairoStatus() ||
mThebes->HasError())
if (!EnsureSurface())
return NS_ERROR_FAILURE;
nsresult rv;
@ -1337,6 +1386,9 @@ nsCanvasRenderingContext2D::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Save()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
ContextState state = CurrentState();
mStyleStack.AppendElement(state);
mThebes->Save();
@ -1347,6 +1399,9 @@ nsCanvasRenderingContext2D::Save()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Restore()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (mSaveCount == 0)
return NS_OK;
@ -1367,6 +1422,9 @@ nsCanvasRenderingContext2D::Restore()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Scale(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -1377,6 +1435,9 @@ nsCanvasRenderingContext2D::Scale(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Rotate(float angle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(angle))
return NS_OK;
@ -1387,6 +1448,9 @@ nsCanvasRenderingContext2D::Rotate(float angle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Translate(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -1397,6 +1461,9 @@ nsCanvasRenderingContext2D::Translate(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22, float dx, float dy)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(m11,m12,m21,m22,dx,dy))
return NS_OK;
@ -1409,6 +1476,9 @@ nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(m11,m12,m21,m22,dx,dy))
return NS_OK;
@ -1424,6 +1494,9 @@ nsCanvasRenderingContext2D::SetMozCurrentTransform(JSContext* cx,
{
nsresult rv;
gfxMatrix newCTM;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!JSValToMatrix(cx, matrix, &newCTM, &rv)) {
return rv;
@ -1438,6 +1511,9 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozCurrentTransform(JSContext* cx,
jsval* matrix)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
return MatrixToJSVal(mThebes->CurrentMatrix(), cx, matrix);
}
@ -1447,6 +1523,9 @@ nsCanvasRenderingContext2D::SetMozCurrentTransformInverse(JSContext* cx,
{
nsresult rv;
gfxMatrix newCTMInverse;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!JSValToMatrix(cx, matrix, &newCTMInverse, &rv)) {
return rv;
@ -1648,6 +1727,9 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozFillRule(const nsAString& aString)
{
gfxContext::FillRule rule;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (aString.EqualsLiteral("evenodd"))
rule = gfxContext::FILL_RULE_EVEN_ODD;
@ -1664,6 +1746,9 @@ nsCanvasRenderingContext2D::SetMozFillRule(const nsAString& aString)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozFillRule(nsAString& aString)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
switch (mThebes->CurrentFillRule()) {
case gfxContext::FILL_RULE_WINDING:
aString.AssignLiteral("nonzero"); break;
@ -1888,6 +1973,9 @@ nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBox
void
nsCanvasRenderingContext2D::ShadowFinalize(gfxAlphaBoxBlur& blur)
{
if (!EnsureSurface())
return;
ApplyStyle(STYLE_SHADOW);
// canvas matrix was already applied, don't apply it twice, but do
// apply the shadow offset
@ -1902,6 +1990,9 @@ nsCanvasRenderingContext2D::ShadowFinalize(gfxAlphaBoxBlur& blur)
nsresult
nsCanvasRenderingContext2D::DrawPath(Style style, gfxRect *dirtyRect)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
PRBool doUseIntermediateSurface = PR_FALSE;
if (mSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
@ -2029,6 +2120,9 @@ nsCanvasRenderingContext2D::DrawPath(Style style, gfxRect *dirtyRect)
NS_IMETHODIMP
nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
{
if (!mSurfaceCreated)
return NS_OK;
if (!FloatValidate(x,y,w,h))
return NS_OK;
@ -2046,6 +2140,9 @@ nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
nsresult
nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(rect.X(), rect.Y(), rect.Width(), rect.Height()))
return NS_OK;
@ -2084,6 +2181,9 @@ nsCanvasRenderingContext2D::StrokeRect(float x, float y, float w, float h)
NS_IMETHODIMP
nsCanvasRenderingContext2D::BeginPath()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mHasPath = PR_FALSE;
mThebes->NewPath();
return NS_OK;
@ -2092,6 +2192,9 @@ nsCanvasRenderingContext2D::BeginPath()
NS_IMETHODIMP
nsCanvasRenderingContext2D::ClosePath()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mThebes->ClosePath();
return NS_OK;
}
@ -2119,6 +2222,9 @@ nsCanvasRenderingContext2D::Stroke()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Clip()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mThebes->Clip();
return NS_OK;
}
@ -2126,6 +2232,9 @@ nsCanvasRenderingContext2D::Clip()
NS_IMETHODIMP
nsCanvasRenderingContext2D::MoveTo(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -2137,6 +2246,9 @@ nsCanvasRenderingContext2D::MoveTo(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::LineTo(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -2148,6 +2260,9 @@ nsCanvasRenderingContext2D::LineTo(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::QuadraticCurveTo(float cpx, float cpy, float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(cpx,cpy,x,y))
return NS_OK;
@ -2168,6 +2283,9 @@ nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
float cp2x, float cp2y,
float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(cp1x,cp1y,cp2x,cp2y,x,y))
return NS_OK;
@ -2182,6 +2300,9 @@ nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
NS_IMETHODIMP
nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float radius)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x1,y1,x2,y2,radius))
return NS_OK;
@ -2241,6 +2362,9 @@ nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float
NS_IMETHODIMP
nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, float endAngle, PRBool ccw)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y,r,startAngle,endAngle))
return NS_OK;
@ -2260,6 +2384,9 @@ nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, flo
NS_IMETHODIMP
nsCanvasRenderingContext2D::Rect(float x, float y, float w, float h)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y,w,h))
return NS_OK;
@ -2772,7 +2899,13 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, NULL);
processor.mPt = gfxPoint(aX, aY);
processor.mThebes = mThebes;
nsRefPtr<nsRenderingContext> ctx;
if (mThebes) {
processor.mThebes = mThebes;
} else {
ctx = presShell->GetReferenceRenderingContext();
processor.mThebes = ctx->ThebesContext();
}
processor.mOp = aOp;
processor.mBoundingBox = gfxRect(0, 0, 0, 0);
processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid;
@ -2806,6 +2939,11 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
if (aOp==TEXT_DRAW_OPERATION_MEASURE)
return NS_OK;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
processor.mThebes = mThebes;
// offset pt.x based on text align
gfxFloat anchorX;
@ -3026,6 +3164,9 @@ nsCanvasRenderingContext2D::MakeTextRun(const PRUnichar* aText,
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineWidth(float width)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(width) || width <= 0.0)
return NS_OK;
@ -3036,6 +3177,9 @@ nsCanvasRenderingContext2D::SetLineWidth(float width)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineWidth(float *width)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxFloat d = mThebes->CurrentLineWidth();
*width = static_cast<float>(d);
return NS_OK;
@ -3044,6 +3188,9 @@ nsCanvasRenderingContext2D::GetLineWidth(float *width)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineCap cap;
if (capstyle.EqualsLiteral("butt"))
@ -3063,6 +3210,9 @@ nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineCap cap = mThebes->CurrentLineCap();
if (cap == gfxContext::LINE_CAP_BUTT)
@ -3080,6 +3230,9 @@ nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineJoin j;
if (joinstyle.EqualsLiteral("round"))
@ -3099,6 +3252,9 @@ nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineJoin j = mThebes->CurrentLineJoin();
if (j == gfxContext::LINE_JOIN_ROUND)
@ -3116,6 +3272,9 @@ nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMiterLimit(float miter)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(miter) || miter <= 0.0)
return NS_OK;
@ -3126,6 +3285,9 @@ nsCanvasRenderingContext2D::SetMiterLimit(float miter)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxFloat d = mThebes->CurrentMiterLimit();
*miter = static_cast<float>(d);
return NS_OK;
@ -3134,6 +3296,9 @@ nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozDash(JSContext *cx, const jsval& patternArray)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
AutoFallibleTArray<gfxFloat, 10> dashes;
nsresult rv = JSValToDashArray(cx, patternArray, dashes);
if (NS_SUCCEEDED(rv)) {
@ -3146,6 +3311,9 @@ nsCanvasRenderingContext2D::SetMozDash(JSContext *cx, const jsval& patternArray)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozDash(JSContext* cx, jsval* dashArray)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
AutoFallibleTArray<gfxFloat, 10> dashes;
if (!mThebes->CurrentDash(dashes, nsnull)) {
dashes.SetLength(0);
@ -3156,6 +3324,9 @@ nsCanvasRenderingContext2D::GetMozDash(JSContext* cx, jsval* dashArray)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozDashOffset(float offset)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(offset)) {
return NS_ERROR_ILLEGAL_VALUE;
}
@ -3180,6 +3351,9 @@ nsCanvasRenderingContext2D::SetMozDashOffset(float offset)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozDashOffset(float* offset)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
*offset = float(mThebes->CurrentDashOffset());
return NS_OK;
}
@ -3187,6 +3361,9 @@ nsCanvasRenderingContext2D::GetMozDashOffset(float* offset)
NS_IMETHODIMP
nsCanvasRenderingContext2D::IsPointInPath(float x, float y, PRBool *retVal)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y)) {
*retVal = PR_FALSE;
return NS_OK;
@ -3214,6 +3391,9 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
float a6, float a7, float a8,
PRUint8 optional_argc)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!imgElt) {
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
}
@ -3398,6 +3578,9 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsOperator thebes_op;
#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
@ -3427,6 +3610,9 @@ nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsOperator thebes_op = mThebes->CurrentOperator();
#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
@ -3457,6 +3643,9 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
const nsAString& aBGColor,
PRUint32 flags)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
NS_ENSURE_ARG(aWindow != nsnull);
// protect against too-large surfaces that will cause allocation
@ -3547,6 +3736,9 @@ nsCanvasRenderingContext2D::AsyncDrawXULElement(nsIDOMXULElement* aElem, float a
const nsAString& aBGColor,
PRUint32 flags)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
NS_ENSURE_ARG(aElem != nsnull);
// We can't allow web apps to call this until we fix at least the
@ -3660,7 +3852,7 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
PRUint8 *aData, PRUint32 aDataLen)
{
if (!mValid)
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!mCanvasElement && !mDocShell) {
@ -3792,7 +3984,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
PRBool hasDirtyRect, PRInt32 dirtyX, PRInt32 dirtyY,
PRInt32 dirtyWidth, PRInt32 dirtyHeight)
{
if (!mValid)
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (w == 0 || h == 0)
@ -3898,7 +4090,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
{
if (!mSurface) {
if (!EnsureSurface()) {
*surface = nsnull;
return NS_ERROR_NOT_AVAILABLE;
}
@ -3954,7 +4146,7 @@ nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
CanvasLayer *aOldLayer,
LayerManager *aManager)
{
if (!mValid)
if (!EnsureSurface())
return nsnull;
if (!mResetLayer && aOldLayer &&

View File

@ -605,8 +605,7 @@ protected:
* Gets the pres shell from either the canvas element or the doc shell
*/
nsIPresShell *GetPresShell() {
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
if (content) {
nsIDocument* ownerDoc = content->GetOwnerDoc();
return ownerDoc ? ownerDoc->GetShell() : nsnull;
@ -1235,8 +1234,7 @@ nsCanvasRenderingContext2DAzure::SetDimensions(PRInt32 width, PRInt32 height)
if (size.width <= 0xFFFF && size.height <= 0xFFFF &&
size.width >= 0 && size.height >= 0) {
SurfaceFormat format = GetSurfaceFormat();
nsCOMPtr<nsIContent> content =
do_QueryInterface(static_cast<nsIDOMHTMLCanvasElement*>(mCanvasElement));
nsCOMPtr<nsIContent> content = do_QueryObject(mCanvasElement);
nsIDocument* ownerDoc = nsnull;
if (content) {
ownerDoc = content->GetOwnerDoc();

View File

@ -85,7 +85,8 @@ if (!gl) {
testPassed("Successfully enabled OES_texture_float extension");
runTextureCreationTest(testProgram, true);
runRenderTargetTest(testProgram);
runUniqueObjectTest();
// bug 683216, see the discussion in bug 630672
// runUniqueObjectTest();
}
}

View File

@ -0,0 +1,25 @@
# HG changeset patch
# Parent 6c8a909977d32284bbddd60a45e1780e824b5d7c
diff --git a/content/canvas/test/webgl/conformance/oes-texture-float.html b/content/canvas/test/webgl/conformance/oes-texture-float.html
--- a/content/canvas/test/webgl/conformance/oes-texture-float.html
+++ b/content/canvas/test/webgl/conformance/oes-texture-float.html
@@ -80,17 +80,18 @@ if (!gl) {
runTextureCreationTest(testProgram, false);
if (!gl.getExtension("OES_texture_float")) {
testPassed("No OES_texture_float support -- this is legal");
} else {
testPassed("Successfully enabled OES_texture_float extension");
runTextureCreationTest(testProgram, true);
runRenderTargetTest(testProgram);
- runUniqueObjectTest();
+ // bug 683216, see the discussion in bug 630672
+ // runUniqueObjectTest();
}
}
// Needs to be global for shouldBe to see it.
var pixels;
function allocateTexture()
{

View File

@ -1214,8 +1214,7 @@ nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
// If the element is subject to constraint validaton and is invalid, we need
// to update our internal counter.
if (aUpdateValidity) {
nsCOMPtr<nsIConstraintValidation> cvElmt =
do_QueryInterface(static_cast<nsGenericHTMLElement*>(aChild));
nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aChild);
if (cvElmt &&
cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
UpdateValidity(PR_FALSE);
@ -1301,8 +1300,7 @@ nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
// If the element was subject to constraint validaton and is invalid, we need
// to update our internal counter.
if (aUpdateValidity) {
nsCOMPtr<nsIConstraintValidation> cvElmt =
do_QueryInterface(static_cast<nsGenericHTMLElement*>(aChild));
nsCOMPtr<nsIConstraintValidation> cvElmt = do_QueryObject(aChild);
if (cvElmt &&
cvElmt->IsCandidateForConstraintValidation() && !cvElmt->IsValid()) {
UpdateValidity(PR_TRUE);
@ -2350,8 +2348,7 @@ nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
list->AppendElement(newFirst ? content : aChild);
nsCOMPtr<nsISupports> listSupports =
do_QueryInterface(static_cast<nsIDOMNodeList*>(list));
nsCOMPtr<nsISupports> listSupports = do_QueryObject(list);
// Replace the element with the list.
NS_ENSURE_TRUE(mNameLookupTable.Put(aName, listSupports),

View File

@ -2255,8 +2255,7 @@ ImageContainer* nsHTMLMediaElement::GetImageContainer()
return nsnull;
// Only video frames need an image container.
nsCOMPtr<nsIDOMHTMLVideoElement> video =
do_QueryInterface(static_cast<nsIContent*>(this));
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
if (!video)
return nsnull;
@ -2283,7 +2282,7 @@ nsresult nsHTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer,
nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(GetOwnerDoc());
nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent*>(this)));
nsCOMPtr<nsIDOMEventTarget> target(do_QueryObject(this));
NS_ENSURE_TRUE(domDoc && target, NS_ERROR_INVALID_ARG);
nsCOMPtr<nsIDOMEvent> event;
@ -2496,8 +2495,7 @@ void nsHTMLMediaElement::NotifyAddedSource()
nsIContent* nsHTMLMediaElement::GetNextSource()
{
nsresult rv = NS_OK;
nsCOMPtr<nsIDOMNode> thisDomNode =
do_QueryInterface(static_cast<nsGenericElement*>(this));
nsCOMPtr<nsIDOMNode> thisDomNode = do_QueryObject(this);
mSourceLoadCandidate = nsnull;

View File

@ -780,8 +780,8 @@ void nsBuiltinDecoder::SeekingStoppedAtEnd()
seekWasAborted = PR_TRUE;
} else {
UnpinForSeek();
fireEnded = mNextState != PLAY_STATE_PLAYING;
ChangeState(fireEnded ? PLAY_STATE_ENDED : mNextState);
fireEnded = PR_TRUE;
ChangeState(PLAY_STATE_ENDED);
}
}

View File

@ -330,10 +330,13 @@ function MediaTestManager() {
// to start every test, but if you call started() you *must* call finish()
// else you'll timeout.
this.runTests = function(tests, startTest) {
this.startTime = new Date();
SimpleTest.info("Started " + this.startTime + " (" + this.startTime.getTime()/1000 + "s)");
this.testNum = 0;
this.tests = tests;
this.startTest = startTest;
this.tokens = [];
this.isShutdown = false;
// Always wait for explicit finish.
SimpleTest.waitForExplicitFinish();
this.nextTest();
@ -355,7 +358,7 @@ function MediaTestManager() {
// Remove the element from the list of running tests.
this.tokens.splice(i, 1);
}
if (this.tokens.length == 0) {
if (this.tokens.length < PARALLEL_TESTS) {
this.nextTest();
}
}
@ -368,14 +371,7 @@ function MediaTestManager() {
// thread stacks' address space.
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.forceGC();
if (this.testNum == this.tests.length && !DEBUG_TEST_LOOP_FOREVER) {
if (this.onFinished) {
this.onFinished();
}
mediaTestCleanup();
SimpleTest.finish();
return;
}
while (this.testNum < this.tests.length && this.tokens.length < PARALLEL_TESTS) {
var test = this.tests[this.testNum];
var token = (test.name ? (test.name + "-"): "") + this.testNum;
@ -391,11 +387,23 @@ function MediaTestManager() {
// Do the init. This should start the test.
this.startTest(test, token);
}
if (this.tokens.length == 0) {
// No tests were added, we must have tried everything, exit.
if (this.testNum == this.tests.length &&
!DEBUG_TEST_LOOP_FOREVER &&
this.tokens.length == 0 &&
!this.isShutdown)
{
this.isShutdown = true;
if (this.onFinished) {
this.onFinished();
}
mediaTestCleanup();
var end = new Date();
SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
SimpleTest.info("Running time: " + (end.getTime() - this.startTime.getTime())/1000 + "s");
SimpleTest.finish();
return;
}
}
}

View File

@ -23,13 +23,13 @@ var gFragmentParams = [
{ fragment: "#t=3,3", start: null, end: null },
{ fragment: "#t=7,3", start: null, end: null },
{ fragment: "#t=7,15", start: 7, end: null },
{ fragment: "#t=15,20", start: 9.287981, end: null, todo: "See Bug 679262" },
{ fragment: "#t=15,20", start: 9.287981, end: null },
{ fragment: "#t=5", start: 5, end: null },
{ fragment: "#t=5.5", start: 5.5, end: null },
{ fragment: "#t=5,", start: null, end: null },
{ fragment: "#t=,5", start: 0, end: 5 },
{ fragment: "#t=2.5,5.5", start: 2.5, end: 5.5 },
{ fragment: "#t=1,2.5", start: 1, end: 2.5 },
{ fragment: "#t=2.5,5.5", start: 2.5, end: 5.5, todo: "See Bug 682141" },
{ fragment: "#t=1,2.5", start: 1, end: 2.5, todo: "See Bug 682141" },
{ fragment: "#t=,15", start: 0, end: null }
];

View File

@ -1490,6 +1490,7 @@ nsSVGElement::SetLength(nsIAtom* aName, const nsSVGLength2 &aLength)
for (PRUint32 i = 0; i < lengthInfo.mLengthCount; i++) {
if (aName == *lengthInfo.mLengthInfo[i].mName) {
lengthInfo.mLengths[i] = aLength;
DidChangeLength(i, PR_TRUE);
return;
}
}
@ -2342,16 +2343,14 @@ nsSVGElement::GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName)
// Transforms:
nsCOMPtr<nsIDOMSVGAnimatedTransformList> transformList;
if (aName == nsGkAtoms::transform) {
nsCOMPtr<nsIDOMSVGTransformable> transformable(
do_QueryInterface(static_cast<nsIContent*>(this)));
nsCOMPtr<nsIDOMSVGTransformable> transformable(do_QueryObject(this));
if (!transformable)
return nsnull;
nsresult rv = transformable->GetTransform(getter_AddRefs(transformList));
NS_ENSURE_SUCCESS(rv, nsnull);
}
if (aName == nsGkAtoms::gradientTransform) {
nsCOMPtr<nsIDOMSVGGradientElement> gradientElement(
do_QueryInterface(static_cast<nsIContent*>(this)));
nsCOMPtr<nsIDOMSVGGradientElement> gradientElement(do_QueryObject(this));
if (!gradientElement)
return nsnull;
@ -2359,8 +2358,7 @@ nsSVGElement::GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName)
NS_ENSURE_SUCCESS(rv, nsnull);
}
if (aName == nsGkAtoms::patternTransform) {
nsCOMPtr<nsIDOMSVGPatternElement> patternElement(
do_QueryInterface(static_cast<nsIContent*>(this)));
nsCOMPtr<nsIDOMSVGPatternElement> patternElement(do_QueryObject(this));
if (!patternElement)
return nsnull;

View File

@ -647,14 +647,28 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
}
}
// Look for <link rel="dns-prefetch" href="hostname">
// and look for <link rel="next" href="hostname"> like in HTML sink
if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
nsAutoString relVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
if (relVal.EqualsLiteral("dns-prefetch")) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
if (!relVal.IsEmpty()) {
// XXX seems overkill to generate this string array
nsAutoTArray<nsString, 4> linkTypes;
nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes);
PRBool hasPrefetch = linkTypes.Contains(NS_LITERAL_STRING("prefetch"));
if (hasPrefetch || linkTypes.Contains(NS_LITERAL_STRING("next"))) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, aContent, hasPrefetch);
}
}
if (linkTypes.Contains(NS_LITERAL_STRING("dns-prefetch"))) {
nsAutoString hrefVal;
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
}
}
}
}

View File

@ -382,8 +382,8 @@ nsXMLDocument::Load(const nsAString& aUrl, PRBool *aReturn)
nsnull, 0, 0, nsIScriptError::warningFlag,
"DOM",
callingDoc ?
callingDoc->OuterWindowID() :
this->OuterWindowID());
callingDoc->InnerWindowID() :
this->InnerWindowID());
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -580,8 +580,7 @@ nsXULElement::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
return PR_FALSE;
#endif
nsCOMPtr<nsIDOMXULControlElement> xulControl =
do_QueryInterface(static_cast<nsIContent*>(this));
nsCOMPtr<nsIDOMXULControlElement> xulControl = do_QueryObject(this);
if (xulControl) {
// a disabled element cannot be focused and is not part of the tab order
PRBool disabled;
@ -958,7 +957,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
// and cells going away.
// First, retrieve the tree.
// Check first whether this element IS the tree
controlElement = do_QueryInterface(static_cast<nsIContent*>(this));
controlElement = do_QueryObject(this);
// If it's not, look at our parent
if (!controlElement)
@ -2057,7 +2056,7 @@ NS_IMETHODIMP
nsXULElement::Focus()
{
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(static_cast<nsIContent*>(this));
nsCOMPtr<nsIDOMElement> elem = do_QueryObject(this);
return fm ? fm->SetFocus(this, 0) : NS_OK;
}

View File

@ -379,7 +379,7 @@ bool nsDSURIContentListener::CheckFrameOptions(nsIRequest* request)
// cancel the load and display about:blank
httpChannel->Cancel(NS_BINDING_ABORTED);
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(static_cast<nsIDocShell*>(mDocShell)));
nsCOMPtr<nsIWebNavigation> webNav(do_QueryObject(mDocShell));
if (webNav) {
webNav->LoadURI(NS_LITERAL_STRING("about:blank").get(),
0, nsnull, nsnull, nsnull);

View File

@ -43,6 +43,7 @@ let Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
function ConsoleAPI() {}
ConsoleAPI.prototype = {
@ -53,12 +54,16 @@ ConsoleAPI.prototype = {
// nsIDOMGlobalPropertyInitializer
init: function CA_init(aWindow) {
let id;
let outerID;
let innerID;
try {
id = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
} catch (ex) {
let windowUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
outerID = windowUtils.outerWindowID;
innerID = windowUtils.currentInnerWindowID;
}
catch (ex) {
Cu.reportError(ex);
}
@ -66,26 +71,26 @@ ConsoleAPI.prototype = {
let chromeObject = {
// window.console API
log: function CA_log() {
self.notifyObservers(id, "log", arguments);
self.notifyObservers(outerID, innerID, "log", arguments);
},
info: function CA_info() {
self.notifyObservers(id, "info", arguments);
self.notifyObservers(outerID, innerID, "info", arguments);
},
warn: function CA_warn() {
self.notifyObservers(id, "warn", arguments);
self.notifyObservers(outerID, innerID, "warn", arguments);
},
error: function CA_error() {
self.notifyObservers(id, "error", arguments);
self.notifyObservers(outerID, innerID, "error", arguments);
},
debug: function CA_debug() {
self.notifyObservers(id, "log", arguments);
self.notifyObservers(outerID, innerID, "log", arguments);
},
trace: function CA_trace() {
self.notifyObservers(id, "trace", self.getStackTrace());
self.notifyObservers(outerID, innerID, "trace", self.getStackTrace());
},
// Displays an interactive listing of all the properties of an object.
dir: function CA_dir() {
self.notifyObservers(id, "dir", arguments);
self.notifyObservers(outerID, innerID, "dir", arguments);
},
__exposedProps__: {
log: "r",
@ -125,17 +130,29 @@ ConsoleAPI.prototype = {
},
/**
* Notify all observers of any console API call
* Notify all observers of any console API call.
*
* @param number aOuterWindowID
* The outer window ID from where the message came from.
* @param number aInnerWindowID
* The inner window ID from where the message came from.
* @param string aLevel
* The message level.
* @param mixed aArguments
* The arguments given to the console API call.
**/
notifyObservers: function CA_notifyObservers(aID, aLevel, aArguments) {
if (!aID)
notifyObservers:
function CA_notifyObservers(aOuterWindowID, aInnerWindowID, aLevel, aArguments) {
if (!aOuterWindowID) {
return;
}
let stack = this.getStackTrace();
// Skip the first frame since it contains an internal call.
let frame = stack[1];
let consoleEvent = {
ID: aID,
ID: aOuterWindowID,
innerID: aInnerWindowID,
level: aLevel,
filename: frame.filename,
lineNumber: frame.lineNumber,
@ -145,8 +162,10 @@ ConsoleAPI.prototype = {
consoleEvent.wrappedJSObject = consoleEvent;
ConsoleAPIStorage.recordEvent(aInnerWindowID, consoleEvent);
Services.obs.notifyObservers(consoleEvent,
"console-api-log-event", aID);
"console-api-log-event", aOuterWindowID);
},
/**

View File

@ -0,0 +1,180 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is ConsoleStorageService code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Dahl <ddahl@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
let Cu = Components.utils;
let Ci = Components.interfaces;
let Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const STORAGE_MAX_EVENTS = 200;
XPCOMUtils.defineLazyGetter(this, "gPrivBrowsing", function () {
// private browsing may not be available in some Gecko Apps
try {
return Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
}
catch (ex) {
return null;
}
});
var EXPORTED_SYMBOLS = ["ConsoleAPIStorage"];
var _consoleStorage = {};
/**
* The ConsoleAPIStorage is meant to cache window.console API calls for later
* reuse by other components when needed. For example, the Web Console code can
* display the cached messages when it opens for the active tab.
*
* ConsoleAPI messages are stored as they come from the ConsoleAPI code, with
* all their properties. They are kept around until the inner window object that
* created the messages is destroyed. Messages are indexed by the inner window
* ID.
*
* Usage:
* Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
*
* // Get the cached events array for the window you want (use the inner
* // window ID).
* let events = ConsoleAPIStorage.getEvents(innerWindowID);
* events.forEach(function(event) { ... });
*
* // Clear the events for the given inner window ID.
* ConsoleAPIStorage.clearEvents(innerWindowID);
*/
var ConsoleAPIStorage = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
/** @private */
observe: function CS_observe(aSubject, aTopic, aData)
{
if (aTopic == "xpcom-shutdown") {
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.obs.removeObserver(this, "inner-window-destroyed");
Services.obs.removeObserver(this, "memory-pressure");
delete _consoleStorage;
}
else if (aTopic == "inner-window-destroyed") {
let innerWindowID = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
this.clearEvents(innerWindowID);
}
else if (aTopic == "memory-pressure") {
if (aData == "low-memory") {
this.clearEvents();
}
}
},
/** @private */
init: function CS_init()
{
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, "inner-window-destroyed", false);
Services.obs.addObserver(this, "memory-pressure", false);
},
/**
* Get the events array by inner window ID.
*
* @param string aId
* The inner window ID for which you want to get the array of cached
* events.
* @returns array
* The array of cached events for the given window.
*/
getEvents: function CS_getEvents(aId)
{
return _consoleStorage[aId] || [];
},
/**
* Record an event associated with the given window ID.
*
* @param string aWindowID
* The ID of the inner window for which the event occurred.
* @param object aEvent
* A JavaScript object you want to store.
*/
recordEvent: function CS_recordEvent(aWindowID, aEvent)
{
let ID = parseInt(aWindowID);
if (isNaN(ID)) {
throw new Error("Invalid window ID argument");
}
if (gPrivBrowsing && gPrivBrowsing.privateBrowsingEnabled) {
return;
}
if (!_consoleStorage[ID]) {
_consoleStorage[ID] = [];
}
let storage = _consoleStorage[ID];
storage.push(aEvent);
// truncate
if (storage.length > STORAGE_MAX_EVENTS) {
storage.shift();
}
Services.obs.notifyObservers(aEvent, "console-storage-cache-event", ID);
},
/**
* Clear storage data for the given window.
*
* @param string [aId]
* Optional, the inner window ID for which you want to clear the
* messages. If this is not specified all of the cached messages are
* cleared, from all window objects.
*/
clearEvents: function CS_clearEvents(aId)
{
if (aId != null) {
delete _consoleStorage[aId];
}
else {
_consoleStorage = {};
Services.obs.notifyObservers(null, "console-storage-reset", null);
}
},
};
ConsoleAPIStorage.init();

View File

@ -52,6 +52,9 @@ EXTRA_PP_COMPONENTS = \
ConsoleAPI.manifest \
$(NULL)
EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
$(NULL)
XPIDLSRCS = \
nsIEntropyCollector.idl \
nsIScriptChannel.idl \

View File

@ -1702,7 +1702,7 @@ PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
0, // column for error is not available
nsIScriptError::warningFlag,
"DOM:HTML",
nsJSUtils::GetCurrentlyRunningCodeWindowID(cx));
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
if (NS_SUCCEEDED(rv)){
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(scriptError);
@ -5083,7 +5083,7 @@ nsWindowSH::InvalidateGlobalScopePolluter(JSContext *cx, JSObject *obj)
// Pull the global scope polluter out of the prototype chain so
// that it can be freed.
::JS_SetPrototype(cx, obj, ::JS_GetPrototype(cx, proto));
::JS_SplicePrototype(cx, obj, ::JS_GetPrototype(cx, proto));
break;
}
@ -5105,7 +5105,7 @@ nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JSObject *obj,
JSAutoRequest ar(cx);
JSObject *gsp = ::JS_NewObject(cx, &sGlobalScopePolluterClass, nsnull, obj);
JSObject *gsp = ::JS_NewObjectWithUniqueType(cx, &sGlobalScopePolluterClass, nsnull, obj);
if (!gsp) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -5118,9 +5118,7 @@ nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JSObject *obj,
while ((proto = ::JS_GetPrototype(cx, o))) {
if (JS_GET_CLASS(cx, proto) == sObjectClass) {
// Set the global scope polluters prototype to Object.prototype
if (!::JS_SetPrototype(cx, gsp, proto)) {
return NS_ERROR_UNEXPECTED;
}
::JS_SplicePrototype(cx, gsp, proto);
break;
}
@ -5130,9 +5128,7 @@ nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JSObject *obj,
// And then set the prototype of the object whose prototype was
// Object.prototype to be the global scope polluter.
if (!::JS_SetPrototype(cx, o, gsp)) {
return NS_ERROR_UNEXPECTED;
}
::JS_SplicePrototype(cx, o, gsp);
if (!::JS_SetPrivate(cx, gsp, doc)) {
return NS_ERROR_UNEXPECTED;

View File

@ -103,6 +103,8 @@ nsDOMMemoryReporter::GetAmount(PRInt64* aAmount) {
*aAmount = 0;
nsGlobalWindow::WindowByIdTable* windows = nsGlobalWindow::GetWindowsTable();
NS_ENSURE_TRUE(windows, NS_OK);
windows->Enumerate(GetWindowsMemoryUsage, aAmount);
return NS_OK;

View File

@ -1101,8 +1101,7 @@ nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
{
if (IsOuterWindow() && !aIgnoreModalDialog) {
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
nsCOMPtr<nsIDOMModalContentWindow>
dlg(do_QueryInterface(static_cast<nsPIDOMWindow*>(inner)));
nsCOMPtr<nsIDOMModalContentWindow> dlg(do_QueryObject(inner));
if (dlg) {
// The window we're trying to clean up is the outer window of a
// modal dialog. Defer cleanup until the window closes, and let
@ -9779,8 +9778,7 @@ nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
if (!scx || !mDocument)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMChromeWindow> chrome_win =
do_QueryInterface(static_cast<nsIDOMWindow *>(this));
nsCOMPtr<nsIDOMChromeWindow> chrome_win = do_QueryObject(this);
if (nsContentUtils::IsCallerChrome() && !chrome_win) {
// If open() is called from chrome on a non-chrome window, we'll

View File

@ -540,6 +540,11 @@ public:
return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nsnull;
}
static nsGlobalWindow* GetInnerWindowWithId(PRUint64 aInnerWindowID) {
nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nsnull;
}
static bool HasIndexedDBSupport();
static bool HasPerformanceSupport();

View File

@ -267,11 +267,11 @@ public:
const nsAString& aFileName,
const nsAString& aSourceLine,
PRBool aDispatchEvent,
PRUint64 aWindowID)
PRUint64 aInnerWindowID)
: mScriptGlobal(aScriptGlobal), mLineNr(aLineNr), mColumn(aColumn),
mFlags(aFlags), mErrorMsg(aErrorMsg), mFileName(aFileName),
mSourceLine(aSourceLine), mDispatchEvent(aDispatchEvent),
mWindowID(aWindowID)
mInnerWindowID(aInnerWindowID)
{}
NS_IMETHOD Run()
@ -364,7 +364,7 @@ public:
rv = error2->InitWithWindowID(mErrorMsg.get(), mFileName.get(),
mSourceLine.get(),
mLineNr, mColumn, mFlags,
category, mWindowID);
category, mInnerWindowID);
} else {
rv = errorObject->Init(mErrorMsg.get(), mFileName.get(),
mSourceLine.get(),
@ -393,7 +393,7 @@ public:
nsString mFileName;
nsString mSourceLine;
PRBool mDispatchEvent;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
static PRBool sHandlingScriptError;
};
@ -474,13 +474,19 @@ NS_ScriptErrorReporter(JSContext *cx,
nsAutoString sourceLine;
sourceLine.Assign(reinterpret_cast<const PRUnichar*>(report->uclinebuf));
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
PRUint64 windowID = win ? win->WindowID() : 0;
PRUint64 innerWindowID = 0;
if (win) {
nsCOMPtr<nsPIDOMWindow> innerWin = win->GetCurrentInnerWindow();
if (innerWin) {
innerWindowID = innerWin->WindowID();
}
}
nsContentUtils::AddScriptRunner(
new ScriptErrorEvent(globalObject, report->lineno,
report->uctokenptr - report->uclinebuf,
report->flags, msg, fileName, sourceLine,
report->errorNumber != JSMSG_OUT_OF_MEMORY,
windowID));
innerWindowID));
}
}
@ -909,6 +915,7 @@ static const char js_methodjit_chrome_str[] = JS_OPTIONS_DOT_STR "methodjit.ch
static const char js_profiling_content_str[] = JS_OPTIONS_DOT_STR "jitprofiling.content";
static const char js_profiling_chrome_str[] = JS_OPTIONS_DOT_STR "jitprofiling.chrome";
static const char js_methodjit_always_str[] = JS_OPTIONS_DOT_STR "methodjit_always";
static const char js_typeinfer_str[] = JS_OPTIONS_DOT_STR "typeinference";
static const char js_memlog_option_str[] = JS_OPTIONS_DOT_STR "mem.log";
int
@ -941,6 +948,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
js_profiling_chrome_str :
js_profiling_content_str);
PRBool useMethodJITAlways = Preferences::GetBool(js_methodjit_always_str);
PRBool useTypeInference = !chromeWindow && Preferences::GetBool(js_typeinfer_str);
nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
if (xr) {
PRBool safeMode = PR_FALSE;
@ -949,6 +957,7 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
useTraceJIT = PR_FALSE;
useMethodJIT = PR_FALSE;
useProfiling = PR_FALSE;
useTypeInference = PR_FALSE;
useMethodJITAlways = PR_TRUE;
}
}
@ -973,6 +982,11 @@ nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
else
newDefaultJSOptions &= ~JSOPTION_METHODJIT_ALWAYS;
if (useTypeInference)
newDefaultJSOptions |= JSOPTION_TYPE_INFERENCE;
else
newDefaultJSOptions &= ~JSOPTION_TYPE_INFERENCE;
#ifdef DEBUG
// In debug builds, warnings are enabled in chrome context if
// javascript.options.strict.debug is true

View File

@ -163,12 +163,12 @@ nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
}
PRUint64
nsJSUtils::GetCurrentlyRunningCodeWindowID(JSContext *aContext)
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
{
if (!aContext)
return 0;
PRUint64 windowID = 0;
PRUint64 innerWindowID = 0;
JSObject *jsGlobal = JS_GetGlobalForScopeChain(aContext);
if (jsGlobal) {
@ -177,10 +177,10 @@ nsJSUtils::GetCurrentlyRunningCodeWindowID(JSContext *aContext)
if (scriptGlobal) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptGlobal);
if (win)
windowID = win->GetOuterWindow()->WindowID();
innerWindowID = win->WindowID();
}
}
return windowID;
return innerWindowID;
}

View File

@ -71,14 +71,14 @@ public:
static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext);
/**
* Retrieve the outer window ID based on the given JSContext.
* Retrieve the inner window ID based on the given JSContext.
*
* @param JSContext aContext
* The JSContext from which you want to find the outer window ID.
* The JSContext from which you want to find the inner window ID.
*
* @returns PRUint64 the outer window ID.
* @returns PRUint64 the inner window ID.
*/
static PRUint64 GetCurrentlyRunningCodeWindowID(JSContext *aContext);
static PRUint64 GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext);
};

View File

@ -290,8 +290,7 @@ AsyncConnectionHelper::Run()
#ifdef DEBUG
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsISupports> handlerSupports(do_QueryInterface(handler));
nsCOMPtr<nsISupports> thisSupports =
do_QueryInterface(static_cast<nsIRunnable*>(this));
nsCOMPtr<nsISupports> thisSupports = do_QueryObject(this);
NS_ASSERTION(thisSupports == handlerSupports, "Mismatch!");
}
#endif

View File

@ -39,7 +39,7 @@
#include "nsIDOMHTMLElement.idl"
/**
* The nsIDOMHTMLVideoElement interface is the interface to a HTML
* The nsIDOMHTMLSourceElement interface is the interface to a HTML
* <source> element.
*
* For more information on this interface, please see

View File

@ -0,0 +1,52 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
# Ben Turner <bent.mozilla@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
XPIDL_MODULE = dom_threads
GRE_MODULE = 1
XPIDLSRCS = nsIDOMWorkers.idl
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,156 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/**
* From http://www.whatwg.org/specs/web-workers/current-work
*/
#include "nsIDOMEvent.idl"
#include "nsIDOMEventTarget.idl"
interface nsIDOMEventListener;
[scriptable, uuid(ab3725b8-3fca-40cc-a42c-92fb154ef01d)]
interface nsIWorkerMessagePort : nsISupports
{
void postMessage(/* in JSObject aMessage */);
};
[scriptable, uuid(508f2d49-e9a0-4fe8-bd33-321820173b4a)]
interface nsIWorkerMessageEvent : nsIDOMEvent
{
readonly attribute DOMString data;
readonly attribute DOMString origin;
readonly attribute nsISupports source;
void initMessageEvent(in DOMString aTypeArg,
in boolean aCanBubbleArg,
in boolean aCancelableArg,
in DOMString aDataArg,
in DOMString aOriginArg,
in nsISupports aSourceArg);
};
[scriptable, uuid(73d82c1d-05de-49c9-a23b-7121ff09a67a)]
interface nsIWorkerErrorEvent : nsIDOMEvent
{
readonly attribute DOMString message;
readonly attribute DOMString filename;
readonly attribute unsigned long lineno;
void initErrorEvent(in DOMString aTypeArg,
in boolean aCanBubbleArg,
in boolean aCancelableArg,
in DOMString aMessageArg,
in DOMString aFilenameArg,
in unsigned long aLinenoArg);
};
[scriptable, uuid(17a005c3-4f2f-4bb6-b169-c181fa6873de)]
interface nsIWorkerLocation : nsISupports
{
readonly attribute AUTF8String href;
readonly attribute AUTF8String protocol;
readonly attribute AUTF8String host;
readonly attribute AUTF8String hostname;
readonly attribute AUTF8String port;
readonly attribute AUTF8String pathname;
readonly attribute AUTF8String search;
readonly attribute AUTF8String hash;
AUTF8String toString();
};
[scriptable, uuid(74fb665a-e477-4ce2-b3c6-c58b1b28b6c3)]
interface nsIWorkerNavigator : nsISupports
{
readonly attribute DOMString appName;
readonly attribute DOMString appVersion;
readonly attribute DOMString platform;
readonly attribute DOMString userAgent;
};
[scriptable, uuid(c111e7d3-8044-4458-aa7b-637696ffb841)]
interface nsIWorkerGlobalScope : nsISupports
{
readonly attribute nsIWorkerGlobalScope self;
readonly attribute nsIWorkerNavigator navigator;
readonly attribute nsIWorkerLocation location;
attribute nsIDOMEventListener onerror;
};
[scriptable, uuid(5c55ea4b-e4ac-4ceb-bfeb-46bd5e521b8a)]
interface nsIWorkerScope : nsIWorkerGlobalScope
{
void postMessage(/* in JSObject aMessage */);
void close();
attribute nsIDOMEventListener onmessage;
attribute nsIDOMEventListener onclose;
};
[scriptable, builtinclass, uuid(b90b7561-b5e2-4545-84b0-280dbaaa94ea)]
interface nsIAbstractWorker : nsIDOMEventTarget
{
attribute nsIDOMEventListener onerror;
};
[scriptable, builtinclass, uuid(daf945c3-8d29-4724-8939-dd383f7d27a7)]
interface nsIWorker : nsIAbstractWorker
{
void postMessage(/* in JSObject aMessage */);
attribute nsIDOMEventListener onmessage;
void terminate();
};
[scriptable, uuid(cfc4bb32-ca83-4d58-9b6f-66f8054a333a)]
interface nsIWorkerFactory : nsISupports
{
nsIWorker newChromeWorker(/* in DOMString aScriptURL */);
};
%{ C++
#define NS_WORKERFACTORY_CONTRACTID \
"@mozilla.org/threads/workerfactory;1"
%}

View File

@ -687,8 +687,10 @@ bool
ContentChild::RecvAddPermission(const IPC::Permission& permission)
{
#if MOZ_PERMISSIONS
nsRefPtr<nsPermissionManager> permissionManager =
nsPermissionManager::GetSingleton();
nsCOMPtr<nsIPermissionManager> permissionManagerIface =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
nsPermissionManager* permissionManager =
static_cast<nsPermissionManager*>(permissionManagerIface.get());
NS_ABORT_IF_FALSE(permissionManager,
"We have no permissionManager in the Content process !");

View File

@ -269,6 +269,7 @@ ContentParent::OnChannelConnected(int32 pid)
}
namespace {
void
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
{
@ -276,6 +277,20 @@ DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
->PostTask(FROM_HERE,
new DeleteTask<GeckoChildProcessHost>(aSubprocess));
}
// This runnable only exists to delegate ownership of the
// ContentParent to this runnable, until it's deleted by the event
// system.
struct DelayedDeleteContentParentTask : public nsRunnable
{
DelayedDeleteContentParentTask(ContentParent* aObj) : mObj(aObj) { }
// No-op
NS_IMETHODIMP Run() { return NS_OK; }
nsRefPtr<ContentParent> mObj;
};
}
void
@ -366,6 +381,15 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
PostTask(FROM_HERE,
NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
mSubprocess = NULL;
// IPDL rules require actors to live on past ActorDestroy, but it
// may be that the kungFuDeathGrip above is the last reference to
// |this|. If so, when we go out of scope here, we're deleted and
// all hell breaks loose.
//
// This runnable ensures that a reference to |this| lives on at
// least until after the current task finishes running.
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
}
TabParent*
@ -455,8 +479,10 @@ bool
ContentParent::RecvReadPermissions(InfallibleTArray<IPC::Permission>* aPermissions)
{
#ifdef MOZ_PERMISSIONS
nsRefPtr<nsPermissionManager> permissionManager =
nsPermissionManager::GetSingleton();
nsCOMPtr<nsIPermissionManager> permissionManagerIface =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
nsPermissionManager* permissionManager =
static_cast<nsPermissionManager*>(permissionManagerIface.get());
NS_ABORT_IF_FALSE(permissionManager,
"We have no permissionManager in the Chrome process !");

View File

@ -246,6 +246,17 @@ PluginPRLibrary::AsyncSetWindow(NPP instance, NPWindow* window)
return NS_ERROR_NOT_IMPLEMENTED;
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult
PluginPRLibrary::HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
bool* handled)
{
nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*)instance->ndata;
NS_ENSURE_TRUE(inst, NS_ERROR_NULL_POINTER);
return NS_ERROR_NOT_IMPLEMENTED;
}
#endif
nsresult
PluginPRLibrary::GetImage(NPP instance, ImageContainer* aContainer, Image** aImage)
{

View File

@ -154,6 +154,10 @@ public:
NS_OVERRIDE
virtual nsresult EndUpdateBackground(NPP instance,
gfxContext* aCtx, const nsIntRect&);
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
virtual nsresult HandleGUIEvent(NPP instance,
const nsGUIEvent& anEvent, bool* handled);
#endif
private:
NP_InitializeFunc mNP_Initialize;

View File

@ -842,6 +842,23 @@ nsNPAPIPluginInstance::AsyncSetWindow(NPWindow* window)
return library->AsyncSetWindow(&mNPP, window);
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult
nsNPAPIPluginInstance::HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled)
{
if (RUNNING != mRunning) {
*handled = false;
return NS_OK;
}
AutoPluginLibraryCall library(this);
if (!library)
return NS_ERROR_FAILURE;
return library->HandleGUIEvent(&mNPP, anEvent, handled);
}
#endif
nsresult
nsNPAPIPluginInstance::GetImage(ImageContainer* aContainer, Image** aImage)
{

View File

@ -114,6 +114,9 @@ public:
nsresult SetOwner(nsIPluginInstanceOwner *aOwner);
nsresult ShowStatus(const char* message);
nsresult InvalidateOwner();
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled);
#endif
nsNPAPIPlugin* GetPlugin();

View File

@ -1688,6 +1688,29 @@ nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
return NS_OK;
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult nsPluginInstanceOwner::Text(nsIDOMEvent* aTextEvent)
{
if (mInstance) {
nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(aTextEvent));
if (privateEvent) {
nsEvent *event = privateEvent->GetInternalNSEvent();
if (event && event->eventStructType == NS_TEXT_EVENT) {
nsEventStatus rv = ProcessEvent(*static_cast<nsGUIEvent*>(event));
if (nsEventStatus_eConsumeNoDefault == rv) {
aTextEvent->PreventDefault();
aTextEvent->StopPropagation();
}
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchTextToPlugin failed, textEvent null");
}
else NS_ASSERTION(PR_FALSE, "nsPluginInstanceOwner::DispatchTextToPlugin failed, privateEvent null");
}
return NS_OK;
}
#endif
nsresult nsPluginInstanceOwner::KeyPress(nsIDOMEvent* aKeyEvent)
{
#ifdef XP_MACOSX
@ -1871,6 +1894,11 @@ nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
if (eventType.EqualsLiteral("keypress")) {
return KeyPress(aEvent);
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
if (eventType.EqualsLiteral("text")) {
return Text(aEvent);
}
#endif
nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aEvent));
if (dragEvent && mInstance) {
@ -2368,10 +2396,29 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
// DOMKeyCodeToGdkKeyCode(keyEvent.keyCode) and
// gdk_keymap_get_entries_for_keyval will be useful, but the
// mappings will not be unique.
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
bool handled;
if (NS_SUCCEEDED(mInstance->HandleGUIEvent(anEvent, &handled)) &&
handled) {
rv = nsEventStatus_eConsumeNoDefault;
}
#else
NS_WARNING("Synthesized key event not sent to plugin");
#endif
}
break;
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
case NS_TEXT_EVENT:
{
bool handled;
if (NS_SUCCEEDED(mInstance->HandleGUIEvent(anEvent, &handled)) &&
handled) {
rv = nsEventStatus_eConsumeNoDefault;
}
}
break;
#endif
default:
switch (anEvent.message)
{
@ -2452,6 +2499,9 @@ nsPluginInstanceOwner::Destroy()
mContent->RemoveEventListener(NS_LITERAL_STRING("dragstart"), this, PR_TRUE);
mContent->RemoveEventListener(NS_LITERAL_STRING("draggesture"), this, PR_TRUE);
mContent->RemoveEventListener(NS_LITERAL_STRING("dragend"), this, PR_TRUE);
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
mContent->RemoveEventListener(NS_LITERAL_STRING("text"), this, PR_TRUE);
#endif
if (mWidget) {
nsCOMPtr<nsIPluginWidget> pluginWidget = do_QueryInterface(mWidget);
@ -2912,6 +2962,9 @@ nsresult nsPluginInstanceOwner::Init(nsPresContext* aPresContext,
mContent->AddEventListener(NS_LITERAL_STRING("dragstart"), this, PR_TRUE);
mContent->AddEventListener(NS_LITERAL_STRING("draggesture"), this, PR_TRUE);
mContent->AddEventListener(NS_LITERAL_STRING("dragend"), this, PR_TRUE);
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
mContent->AddEventListener(NS_LITERAL_STRING("text"), this, PR_TRUE);
#endif
// Register scroll position listeners
// We need to register a scroll position listener on every scrollable

View File

@ -69,7 +69,7 @@
#endif
class nsIInputStream;
class nsIntRect;
struct nsIntRect;
class nsPluginDOMContextMenuListener;
class nsObjectFrame;
class nsDisplayListBuilder;
@ -130,6 +130,9 @@ public:
nsresult MouseDown(nsIDOMEvent* aKeyEvent);
nsresult KeyPress(nsIDOMEvent* aKeyEvent);
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult Text(nsIDOMEvent* aTextEvent);
#endif
nsresult Destroy();

View File

@ -46,6 +46,7 @@ include protocol PStreamNotify;
include protocol PPluginSurface;
include "mozilla/plugins/PluginMessageUtils.h";
include "IPC/nsGUIEventIPC.h";
using NPError;
using NPRemoteWindow;
@ -59,6 +60,8 @@ using gfxIntSize;
using mozilla::null_t;
using mozilla::plugins::WindowsSharedMemoryHandle;
using nsIntRect;
using nsTextEvent;
using nsKeyEvent;
namespace mozilla {
namespace plugins {
@ -147,6 +150,11 @@ child:
// refer to the existing background or a fresh descriptor.
async UpdateBackground(SurfaceDescriptor background, nsIntRect rect);
rpc HandleTextEvent(nsTextEvent event)
returns (bool handled);
rpc HandleKeyEvent(nsKeyEvent event)
returns (bool handled);
rpc NPP_Destroy()
returns (NPError rv);

View File

@ -37,6 +37,14 @@
*
* ***** END LICENSE BLOCK ***** */
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
#include <QEvent>
#include <QKeyEvent>
#include <QApplication>
#include <QInputMethodEvent>
#include "nsQtKeyUtils.h"
#endif
#include "PluginBackgroundDestroyer.h"
#include "PluginInstanceChild.h"
#include "PluginModuleChild.h"
@ -74,6 +82,8 @@ using namespace mozilla::plugins;
#elif defined(MOZ_WIDGET_QT)
#include <QX11Info>
#undef KeyPress
#undef KeyRelease
#elif defined(OS_WIN)
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
@ -2317,6 +2327,57 @@ PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
return true;
}
bool
PluginInstanceChild::AnswerHandleKeyEvent(const nsKeyEvent& aKeyEvent,
bool* handled)
{
AssertPluginThread();
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
Qt::KeyboardModifiers modifier;
if (aKeyEvent.isShift)
modifier |= Qt::ShiftModifier;
if (aKeyEvent.isControl)
modifier |= Qt::ControlModifier;
if (aKeyEvent.isAlt)
modifier |= Qt::AltModifier;
if (aKeyEvent.isMeta)
modifier |= Qt::MetaModifier;
QEvent::Type type;
if (aKeyEvent.message == NS_KEY_DOWN) {
type = QEvent::KeyPress;
} else if (aKeyEvent.message == NS_KEY_UP) {
type = QEvent::KeyRelease;
} else {
*handled = false;
return true;
}
QKeyEvent keyEv(type, DOMKeyCodeToQtKeyCode(aKeyEvent.keyCode), modifier);
*handled = QApplication::sendEvent(qApp, &keyEv);
#else
NS_ERROR("Not implemented");
#endif
return true;
}
bool
PluginInstanceChild::AnswerHandleTextEvent(const nsTextEvent& aEvent,
bool* handled)
{
AssertPluginThread();
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
QInputMethodEvent event;
event.setCommitString(QString((const QChar*)aEvent.theText.get(),
aEvent.theText.Length()));
*handled = QApplication::sendEvent(qApp, &event);
#else
NS_ERROR("Not implemented");
#endif
return true;
}
void
PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
const NPRemoteWindow& aWindow,

View File

@ -120,6 +120,11 @@ protected:
const NPRemoteWindow& aWindow,
bool aIsAsync);
virtual bool
AnswerHandleKeyEvent(const nsKeyEvent& aEvent, bool* handled);
virtual bool
AnswerHandleTextEvent(const nsTextEvent& aEvent, bool* handled);
virtual PPluginSurfaceChild* AllocPPluginSurface(const WindowsSharedMemoryHandle&,
const gfxIntSize&, const bool&) {
return new PPluginSurfaceChild();

View File

@ -618,6 +618,31 @@ PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow)
return NS_OK;
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult
PluginInstanceParent::HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled)
{
switch (anEvent.eventStructType) {
case NS_KEY_EVENT:
if (!CallHandleKeyEvent(static_cast<const nsKeyEvent&>(anEvent),
handled)) {
return NS_ERROR_FAILURE;
}
break;
case NS_TEXT_EVENT:
if (!CallHandleTextEvent(static_cast<const nsTextEvent&>(anEvent),
handled)) {
return NS_ERROR_FAILURE;
}
break;
default:
NS_ERROR("Not implemented for this event type");
return NS_ERROR_FAILURE;
}
return NS_OK;
}
#endif
nsresult
PluginInstanceParent::GetImage(ImageContainer* aContainer, Image** aImage)
{

View File

@ -57,6 +57,7 @@
#ifdef MOZ_X11
class gfxXlibSurface;
#endif
#include "nsGUIEvent.h"
namespace mozilla {
namespace plugins {
@ -290,6 +291,9 @@ public:
gfxContext** aCtx);
nsresult EndUpdateBackground(gfxContext* aCtx,
const nsIntRect& aRect);
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult HandleGUIEvent(const nsGUIEvent& anEvent, bool* handled);
#endif
private:
// Create an appropriate platform surface for a background of size

View File

@ -52,6 +52,7 @@ class nsCString;
struct nsIntRect;
struct nsIntSize;
class nsNPAPIPlugin;
class nsGUIEvent;
namespace mozilla {
namespace layers {
@ -116,6 +117,9 @@ public:
const nsIntRect&, gfxContext**) = 0;
virtual nsresult EndUpdateBackground(NPP instance,
gfxContext*, const nsIntRect&) = 0;
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent&, bool*) = 0;
#endif
};

View File

@ -703,6 +703,20 @@ PluginModuleParent::AsyncSetWindow(NPP instance, NPWindow* window)
return i->AsyncSetWindow(window);
}
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
nsresult
PluginModuleParent::HandleGUIEvent(NPP instance,
const nsGUIEvent& anEvent,
bool* handled)
{
PluginInstanceParent* i = InstCast(instance);
if (!i)
return NS_ERROR_FAILURE;
return i->HandleGUIEvent(anEvent, handled);
}
#endif
nsresult
PluginModuleParent::GetImage(NPP instance,
mozilla::layers::ImageContainer* aContainer,

View File

@ -296,6 +296,10 @@ private:
#if defined(XP_MACOSX)
virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, PRBool *aDrawing);
#endif
#if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
bool* handled);
#endif
private:
void WritePluginExtraDataForMinidump(const nsAString& id);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,212 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMTHREADSERVICE_H__
#define __NSDOMTHREADSERVICE_H__
// Interfaces
#include "nsIEventTarget.h"
#include "nsIObserver.h"
#include "nsIThreadPool.h"
// Other includes
#include "jsapi.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsStringGlue.h"
#include "nsTPtrArray.h"
#include "prlog.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gDOMThreadsLog;
#endif
class nsDOMWorker;
class nsDOMWorkerPool;
class nsDOMWorkerRunnable;
class nsDOMWorkerTimeout;
class nsIJSRuntimeService;
class nsIScriptGlobalObject;
class nsIThreadJSContextStack;
class nsIXPConnect;
class nsIXPCSecurityManager;
enum ThreadsafeStatus
{
Threadsafe,
NotThreadsafe,
Unknown
};
class nsDOMThreadService : public nsIEventTarget,
public nsIObserver,
public nsIThreadPoolListener
{
friend class nsDOMWorker;
friend class nsDOMWorkerNavigator;
friend class nsDOMWorkerPool;
friend class nsDOMWorkerRunnable;
friend class nsDOMWorkerThread;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRProxy;
friend class nsLayoutStatics;
friend class nsReportErrorRunnable;
friend void DOMWorkerErrorReporter(JSContext* aCx,
const char* aMessage,
JSErrorReport* aReport);
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIEVENTTARGET
NS_DECL_NSIOBSERVER
NS_DECL_NSITHREADPOOLLISTENER
// Any DOM consumers that need access to this service should use this method.
static already_AddRefed<nsDOMThreadService> GetOrInitService();
// Simple getter for this service. This does not create the service if it
// hasn't been created already, and it never AddRef's!
static nsDOMThreadService* get();
static JSContext* GetCurrentContext();
// Easy access to the services we care about.
static nsIJSRuntimeService* JSRuntimeService();
static nsIThreadJSContextStack* ThreadJSContextStack();
static nsIXPCSecurityManager* WorkerSecurityManager();
void CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
void ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
nsresult ChangeThreadPoolMaxThreads(PRInt16 aDelta);
void NoteThreadsafeContractId(const nsACString& aContractId,
PRBool aIsThreadsafe);
ThreadsafeStatus GetContractIdThreadsafeStatus(const nsACString& aContractId);
private:
nsDOMThreadService();
~nsDOMThreadService();
nsresult Init();
void Cleanup();
static void Shutdown();
nsresult Dispatch(nsDOMWorker* aWorker,
nsIRunnable* aRunnable,
PRIntervalTime aTimeoutInterval = 0,
PRBool aClearQueue = PR_FALSE);
void SetWorkerTimeout(nsDOMWorker* aWorker,
PRIntervalTime aTimeoutInterval);
void WorkerComplete(nsDOMWorkerRunnable* aRunnable);
static JSContext* CreateJSContext();
already_AddRefed<nsDOMWorkerPool>
GetPoolForGlobal(nsIScriptGlobalObject* aGlobalObject,
PRBool aRemove);
void TriggerOperationCallbackForPool(nsDOMWorkerPool* aPool);
void RescheduleSuspendedWorkerForPool(nsDOMWorkerPool* aPool);
void NoteEmptyPool(nsDOMWorkerPool* aPool);
void TimeoutReady(nsDOMWorkerTimeout* aTimeout);
nsresult RegisterWorker(nsDOMWorker* aWorker,
nsIScriptGlobalObject* aGlobalObject);
void GetAppName(nsAString& aAppName);
void GetAppVersion(nsAString& aAppVersion);
void GetPlatform(nsAString& aPlatform);
void GetUserAgent(nsAString& aUserAgent);
void RegisterPrefCallbacks();
void UnregisterPrefCallbacks();
static int PrefCallback(const char* aPrefName,
void* aClosure);
static PRUint32 GetWorkerCloseHandlerTimeoutMS();
PRBool QueueSuspendedWorker(nsDOMWorkerRunnable* aRunnable);
// Our internal thread pool.
nsCOMPtr<nsIThreadPool> mThreadPool;
// Maps nsIScriptGlobalObject* to nsDOMWorkerPool.
nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerPool> mPools;
// mReentrantMonitor protects all access to mWorkersInProgress and
// mCreationsInProgress.
mozilla::ReentrantMonitor mReentrantMonitor;
// A map from nsDOMWorkerThread to nsDOMWorkerRunnable.
nsRefPtrHashtable<nsVoidPtrHashKey, nsDOMWorkerRunnable> mWorkersInProgress;
// A list of active JSContexts that we've created. Always protected with
// mReentrantMonitor.
nsTArray<JSContext*> mJSContexts;
// A list of worker runnables that were never started because the worker was
// suspended. Always protected with mReentrantMonitor.
nsTArray<nsDOMWorkerRunnable*> mSuspendedWorkers;
// Always protected with mReentrantMonitor.
nsDataHashtable<nsCStringHashKey, PRBool> mThreadsafeContractIDs;
nsString mAppName;
nsString mAppVersion;
nsString mPlatform;
nsString mUserAgent;
PRBool mNavigatorStringsLoaded;
};
#endif /* __NSDOMTHREADSERVICE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,471 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKER_H__
#define __NSDOMWORKER_H__
#include "nsIDOMEventTarget.h"
#include "nsIDOMWorkers.h"
#include "nsIJSNativeInitializer.h"
#include "nsIPrincipal.h"
#include "nsITimer.h"
#include "nsIURI.h"
#include "nsIXPCScriptable.h"
#include "jsapi.h"
#include "mozilla/Mutex.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsTPtrArray.h"
#include "nsDOMWorkerMessageHandler.h"
// {1295EFB5-8644-42B2-8B8E-80EEF56E4284}
#define NS_WORKERFACTORY_CID \
{0x1295efb5, 0x8644, 0x42b2, \
{0x8b, 0x8e, 0x80, 0xee, 0xf5, 0x6e, 0x42, 0x84} }
class nsDOMWorker;
class nsDOMWorkerFeature;
class nsDOMWorkerMessageHandler;
class nsDOMWorkerNavigator;
class nsDOMWorkerPool;
class nsDOMWorkerTimeout;
class nsICancelable;
class nsIDOMEventListener;
class nsIEventTarget;
class nsIRunnable;
class nsIScriptGlobalObject;
class nsIXPConnectWrappedNative;
class nsDOMWorkerScope : public nsDOMWorkerMessageHandler,
public nsIWorkerScope,
public nsIXPCScriptable
{
friend class nsDOMWorker;
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_DECL_NSIWORKERGLOBALSCOPE
NS_DECL_NSIWORKERSCOPE
NS_DECL_NSIXPCSCRIPTABLE
NS_DECL_NSICLASSINFO
typedef NS_STDCALL_FUNCPROTO(nsresult, SetListenerFunc, nsDOMWorkerScope,
SetOnmessage, (nsIDOMEventListener*));
nsDOMWorkerScope(nsDOMWorker* aWorker);
protected:
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative();
private:
nsDOMWorker* mWorker;
nsIXPConnectWrappedNative* mWrappedNative;
nsRefPtr<nsDOMWorkerNavigator> mNavigator;
PRPackedBool mHasOnerror;
};
class nsLazyAutoRequest
{
public:
nsLazyAutoRequest() : mCx(nsnull) {}
~nsLazyAutoRequest() {
if (mCx)
JS_EndRequest(mCx);
}
void enter(JSContext *aCx) {
JS_BeginRequest(aCx);
mCx = aCx;
}
bool entered() const { return mCx != nsnull; }
void swap(nsLazyAutoRequest &other) {
JSContext *tmp = mCx;
mCx = other.mCx;
other.mCx = tmp;
}
private:
JSContext *mCx;
};
class nsDOMWorker : public nsDOMWorkerMessageHandler,
public nsIWorker,
public nsITimerCallback,
public nsIJSNativeInitializer,
public nsIXPCScriptable
{
typedef mozilla::Mutex Mutex;
friend class nsDOMWorkerFeature;
friend class nsDOMWorkerFunctions;
friend class nsDOMWorkerScope;
friend class nsDOMWorkerScriptLoader;
friend class nsDOMWorkerTimeout;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRProxy;
friend class nsReportErrorRunnable;
friend class nsDOMFireEventRunnable;
friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
friend void DOMWorkerErrorReporter(JSContext* aCx,
const char* aMessage,
JSErrorReport* aReport);
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_DECL_NSIABSTRACTWORKER
NS_DECL_NSIWORKER
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICLASSINFO
NS_DECL_NSIXPCSCRIPTABLE
static nsresult NewWorker(nsISupports** aNewObject);
static nsresult NewChromeWorker(nsISupports** aNewObject);
static nsresult NewChromeDOMWorker(nsDOMWorker** aNewObject);
enum WorkerPrivilegeModel { CONTENT, CHROME };
nsDOMWorker(nsDOMWorker* aParent,
nsIXPConnectWrappedNative* aParentWN,
WorkerPrivilegeModel aModel);
NS_IMETHOD Initialize(nsISupports* aOwner,
JSContext* aCx,
JSObject* aObj,
PRUint32 aArgc,
jsval* aArgv);
nsresult InitializeInternal(nsIScriptGlobalObject* aOwner,
JSContext* aCx,
JSObject* aObj,
PRUint32 aArgc,
jsval* aArgv);
void Cancel();
void Kill();
void Suspend();
void Resume();
// This just calls IsCanceledNoLock with an autolock around the call.
PRBool IsCanceled();
PRBool IsClosing();
PRBool IsSuspended();
PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
void SetPool(nsDOMWorkerPool* aPool);
nsDOMWorkerPool* Pool() {
return mPool;
}
Mutex& GetLock() {
return mLock;
}
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative();
already_AddRefed<nsDOMWorker> GetParent();
nsDOMWorkerScope* GetInnerScope() {
return mInnerScope;
}
void SetExpirationTime(PRIntervalTime aExpirationTime);
#ifdef DEBUG
PRIntervalTime GetExpirationTime();
#endif
PRBool IsPrivileged() {
return mPrivilegeModel == CHROME;
}
static JSObject* ReadStructuredClone(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32 aTag,
uint32 aData,
void* aClosure);
/**
* Use this chart to help figure out behavior during each of the closing
* statuses. Details below.
*
* +=============+=============+=================+=======================+
* | status | clear queue | abort execution | close handler timeout |
* +=============+=============+=================+=======================+
* | eClosed | yes | no | no |
* +-------------+-------------+-----------------+-----------------------+
* | eTerminated | yes | yes | no |
* +-------------+-------------+-----------------+-----------------------+
* | eCanceled | yes | yes | yes |
* +-------------+-------------+-----------------+-----------------------+
*
*/
enum DOMWorkerStatus {
// This status means that the close handler has not yet been scheduled.
eRunning = 0,
// Inner script called Close() on the worker global scope. Setting this
// status causes the worker to clear its queue of events but does not abort
// the currently running script. The close handler is also scheduled with
// no expiration time. This status may be superseded by 'eTerminated' in
// which case the currently running script will be aborted as detailed
// below. It may also be superseded by 'eCanceled' at which point the close
// handler will be assigned an expiration time. Once the close handler has
// completed or timed out the status will be changed to 'eKilled'.
eClosed,
// Outer script called Terminate() on the worker or the worker object was
// garbage collected in its outer script. Setting this status causes the
// worker to abort immediately, clear its queue of events, and schedules the
// close handler with no expiration time. This status may be superseded by
// 'eCanceled' at which point the close handler will have an expiration time
// assigned. Once the close handler has completed or timed out the status
// will be changed to 'eKilled'.
eTerminated,
// Either the user navigated away from the owning page, the owning page fell
// out of bfcache, or the user quit the application. Setting this status
// causes the worker to abort immediately and schedules the close handler
// with an expiration time. Since the page has gone away the worker may not
// post any messages. Once the close handler has completed or timed out the
// status will be changed to 'eKilled'.
eCanceled,
// The close handler has run and the worker is effectively dead.
eKilled
};
private:
~nsDOMWorker();
nsresult PostMessageInternal(PRBool aToInner);
PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
PRUint32 NextTimeoutId() {
return ++mNextTimeoutId;
}
nsresult AddFeature(nsDOMWorkerFeature* aFeature,
JSContext* aCx);
void RemoveFeature(nsDOMWorkerFeature* aFeature,
JSContext* aCx);
void CancelTimeoutWithId(PRUint32 aId);
void SuspendFeatures();
void ResumeFeatures();
nsIPrincipal* GetPrincipal() {
return mPrincipal;
}
void SetPrincipal(nsIPrincipal* aPrincipal);
nsIURI* GetBaseURI() {
return mBaseURI;
}
nsresult SetBaseURI(nsIURI* aURI);
void ClearBaseURI();
nsresult FireCloseRunnable(PRIntervalTime aTimeoutInterval,
PRBool aClearQueue,
PRBool aFromFinalize);
nsresult Close();
nsresult TerminateInternal(PRBool aFromFinalize);
nsIWorkerLocation* GetLocation() {
return mLocation;
}
PRBool QueueSuspendedRunnable(nsIRunnable* aRunnable);
// Determines if the worker should be considered "canceled". See the large
// comment in the implementation for more details.
PRBool IsCanceledNoLock();
private:
// mParent will live as long as mParentWN but only mParentWN will keep the JS
// reflection alive, so we only hold one strong reference to mParentWN.
nsDOMWorker* mParent;
nsCOMPtr<nsIXPConnectWrappedNative> mParentWN;
// Whether or not this worker has chrome privileges. Never changed after the
// worker is created.
WorkerPrivilegeModel mPrivilegeModel;
Mutex mLock;
nsRefPtr<nsDOMWorkerPool> mPool;
nsDOMWorkerScope* mInnerScope;
nsCOMPtr<nsIXPConnectWrappedNative> mScopeWN;
JSObject* mGlobal;
PRUint32 mNextTimeoutId;
nsTArray<nsDOMWorkerFeature*> mFeatures;
PRUint32 mFeatureSuspendDepth;
nsString mScriptURL;
nsIXPConnectWrappedNative* mWrappedNative;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIURI> mBaseURI;
PRInt32 mErrorHandlerRecursionCount;
// Always protected by mLock
DOMWorkerStatus mStatus;
// Always protected by mLock
PRIntervalTime mExpirationTime;
nsCOMPtr<nsITimer> mKillTimer;
nsCOMPtr<nsIWorkerLocation> mLocation;
nsTArray<nsCOMPtr<nsIRunnable> > mQueuedRunnables;
PRPackedBool mSuspended;
PRPackedBool mCompileAttempted;
};
/**
* A worker "feature" holds the worker alive yet can be canceled, paused, and
* resumed by the worker. It is up to each derived class to implement these
* methods. This class uses a custom implementation of Release in order to
* ensure no races between Cancel and object destruction can occur, so derived
* classes must use the ISUPPORTS_INHERITED macros.
*
* To use this class you should inherit it and use the ISUPPORTS_INHERITED
* macros. Then add or remove an instance to the worker using the
* AddFeature/RemoveFeature functions.
*/
class nsDOMWorkerFeature : public nsISupports
{
friend class nsDOMWorker;
public:
NS_DECL_ISUPPORTS
nsDOMWorkerFeature(nsDOMWorker* aWorker)
: mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(0),
mHasId(PR_FALSE), mFreeToDie(PR_TRUE) { }
nsDOMWorkerFeature(nsDOMWorker* aWorker, PRUint32 aId)
: mWorker(aWorker), mWorkerWN(aWorker->GetWrappedNative()), mId(aId),
mHasId(PR_TRUE), mFreeToDie(PR_TRUE) { }
virtual void Cancel() = 0;
virtual void Suspend() { }
virtual void Resume() { }
PRUint32 GetId() {
return mId;
}
PRBool HasId() {
return mHasId;
}
protected:
virtual ~nsDOMWorkerFeature() { }
private:
void FreeToDie(PRBool aFreeToDie) {
mFreeToDie = aFreeToDie;
}
protected:
nsRefPtr<nsDOMWorker> mWorker;
nsCOMPtr<nsIXPConnectWrappedNative> mWorkerWN;
PRUint32 mId;
private:
PRPackedBool mHasId;
PRPackedBool mFreeToDie;
};
class nsWorkerFactory : public nsIWorkerFactory
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWORKERFACTORY
};
#endif /* __NSDOMWORKER_H__ */

View File

@ -0,0 +1,635 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerEvents.h"
#include "nsIXMLHttpRequest.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "nsAXPCNativeCallContext.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "nsDOMWorkerMessageHandler.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerXHR.h"
#include "nsDOMWorkerXHRProxy.h"
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMWorkerPrivateEvent,
NS_IDOMWORKERPRIVATEEVENT_IID)
nsDOMWorkerPrivateEvent::nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent)
: mEvent(aEvent),
mProgressEvent(do_QueryInterface(aEvent)),
mMessageEvent(do_QueryInterface(aEvent)),
mErrorEvent(do_QueryInterface(aEvent)),
mPreventDefaultCalled(PR_FALSE)
{
NS_ASSERTION(aEvent, "Null pointer!");
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPrivateEvent)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEvent, nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMWorkerPrivateEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerMessageEvent, mMessageEvent)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIWorkerErrorEvent, mErrorEvent)
NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
NS_INTERFACE_MAP_END
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerPrivateEvent, nsIDOMEvent)
NS_IMPL_THREADSAFE_DOM_CI_HELPER(nsDOMWorkerPrivateEvent)
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(nsDOMWorkerPrivateEvent)
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::GetInterfaces(PRUint32* aCount, nsIID*** aArray)
{
nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mEvent));
if (ci) {
return ci->GetInterfaces(aCount, aArray);
}
return NS_CI_INTERFACE_GETTER_NAME(nsDOMWorkerPrivateEvent)(aCount, aArray);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::PreventDefault()
{
PRBool cancelable = PR_FALSE;
mEvent->GetCancelable(&cancelable);
if (cancelable) {
mPreventDefaultCalled = PR_TRUE;
}
return mEvent->PreventDefault();
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::GetDefaultPrevented(PRBool* aRetVal)
{
*aRetVal = mPreventDefaultCalled;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitEvent(const nsAString& aEventType,
PRBool aCanBubble,
PRBool aCancelable)
{
mPreventDefaultCalled = PR_FALSE;
return mEvent->InitEvent(aEventType, aCanBubble, aCancelable);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitProgressEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg)
{
NS_ASSERTION(mProgressEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mProgressEvent->InitProgressEvent(aTypeArg, aCanBubbleArg,
aCancelableArg, aLengthComputableArg,
aLoadedArg, aTotalArg);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg)
{
NS_ASSERTION(mMessageEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mMessageEvent->InitMessageEvent(aTypeArg, aCanBubbleArg,
aCancelableArg, aDataArg, aOriginArg,
aSourceArg);
}
NS_IMETHODIMP
nsDOMWorkerPrivateEvent::InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg)
{
NS_ASSERTION(mErrorEvent, "Impossible!");
mPreventDefaultCalled = PR_FALSE;
return mErrorEvent->InitErrorEvent(aTypeArg, aCanBubbleArg, aCancelableArg,
aMessageArg, aFilenameArg, aLinenoArg);
}
PRBool
nsDOMWorkerPrivateEvent::PreventDefaultCalled()
{
return mPreventDefaultCalled;
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerEvent, nsIDOMEvent,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerEvent, nsIDOMEvent)
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerEvent)
NS_IMETHODIMP
nsDOMWorkerEvent::GetType(nsAString& aType)
{
aType.Assign(mType);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetTarget(nsIDOMEventTarget** aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mTarget);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
{
NS_ENSURE_ARG_POINTER(aCurrentTarget);
NS_IF_ADDREF(*aCurrentTarget = mTarget);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetEventPhase(PRUint16* aEventPhase)
{
NS_ENSURE_ARG_POINTER(aEventPhase);
*aEventPhase = mEventPhase;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetBubbles(PRBool* aBubbles)
{
NS_ENSURE_ARG_POINTER(aBubbles);
*aBubbles = mBubbles;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetCancelable(PRBool* aCancelable)
{
NS_ENSURE_ARG_POINTER(aCancelable);
*aCancelable = mCancelable;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetTimeStamp(DOMTimeStamp* aTimeStamp)
{
NS_ENSURE_ARG_POINTER(aTimeStamp);
*aTimeStamp = mTimeStamp;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::StopPropagation()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerEvent::PreventDefault()
{
mPreventDefaultCalled = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::GetDefaultPrevented(PRBool* aRetVal)
{
*aRetVal = mPreventDefaultCalled;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerEvent::InitEvent(const nsAString& aEventTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg)
{
NS_ENSURE_FALSE(aEventTypeArg.IsEmpty(), NS_ERROR_INVALID_ARG);
mType.Assign(aEventTypeArg);
mBubbles = aCanBubbleArg;
mCancelable = aCancelableArg;
mPreventDefaultCalled = PR_FALSE;
mTimeStamp = PR_Now();
return NS_OK;
}
nsDOMWorkerMessageEvent::~nsDOMWorkerMessageEvent()
{
if (mData) {
JSContext* cx = nsDOMThreadService::GetCurrentContext();
if (cx) {
JS_free(cx, mData);
}
else {
NS_WARNING("Failed to get safe JSContext, leaking event data!");
}
}
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerMessageEvent, nsDOMWorkerEvent,
nsIWorkerMessageEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerMessageEvent, nsIDOMEvent,
nsIWorkerMessageEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerMessageEvent)
nsresult
nsDOMWorkerMessageEvent::SetJSData(
JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer,
nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives)
{
NS_ASSERTION(aCx, "Null context!");
if (!mDataVal.Hold(aCx)) {
NS_WARNING("Failed to hold jsval!");
return NS_ERROR_FAILURE;
}
if (!mWrappedNatives.SwapElements(aWrappedNatives)) {
NS_ERROR("This should never fail!");
}
aBuffer.steal(&mData, &mDataLen);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetData(nsAString& aData)
{
nsIXPConnect* xpc = nsContentUtils::XPConnect();
NS_ENSURE_TRUE(xpc, NS_ERROR_UNEXPECTED);
nsAXPCNativeCallContext* cc;
nsresult rv = xpc->GetCurrentNativeCallContext(&cc);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(cc, NS_ERROR_UNEXPECTED);
if (mData) {
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(cx, mData, mDataLen);
mData = nsnull;
mDataLen = 0;
JSStructuredCloneCallbacks callbacks = {
nsDOMWorker::ReadStructuredClone, nsnull, nsnull
};
JSBool ok = buffer.read(mDataVal.ToJSValPtr(), cx, &callbacks);
// Release wrapped natives now, regardless of whether or not the deserialize
// succeeded.
mWrappedNatives.Clear();
if (!ok) {
NS_WARNING("Failed to deserialize!");
return NS_ERROR_FAILURE;
}
}
jsval* retval;
rv = cc->GetRetValPtr(&retval);
NS_ENSURE_SUCCESS(rv, rv);
cc->SetReturnValueWasSet(PR_TRUE);
*retval = mDataVal;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetOrigin(nsAString& aOrigin)
{
aOrigin.Assign(mOrigin);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::GetSource(nsISupports** aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mSource);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerMessageEvent::InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg)
{
mOrigin.Assign(aOriginArg);
mSource = aSourceArg;
return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerProgressEvent, nsDOMWorkerEvent,
nsIDOMProgressEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerProgressEvent, nsIDOMEvent,
nsIDOMProgressEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerProgressEvent)
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetLengthComputable(PRBool* aLengthComputable)
{
NS_ENSURE_ARG_POINTER(aLengthComputable);
*aLengthComputable = mLengthComputable;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetLoaded(PRUint64* aLoaded)
{
NS_ENSURE_ARG_POINTER(aLoaded);
*aLoaded = mLoaded;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::GetTotal(PRUint64* aTotal)
{
NS_ENSURE_ARG_POINTER(aTotal);
*aTotal = mTotal;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerProgressEvent::InitProgressEvent(const nsAString_internal& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg)
{
mLengthComputable = aLengthComputableArg;
mLoaded = aLoadedArg;
mTotal = aTotalArg;
return nsDOMWorkerEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerXHRState)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerXHRState)
nsDOMWorkerXHREvent::nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy)
: mXHRProxy(aXHRProxy),
mXHREventType(PR_UINT32_MAX),
mChannelID(-1),
mUploadEvent(PR_FALSE),
mProgressEvent(PR_FALSE)
{
NS_ASSERTION(aXHRProxy, "Can't be null!");
}
NS_IMPL_ADDREF_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMWorkerXHREvent, nsDOMWorkerProgressEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMWorkerXHREvent)
NS_INTERFACE_MAP_ENTRY(nsIRunnable)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMProgressEvent, mProgressEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMWorkerEvent)
NS_IMETHODIMP
nsDOMWorkerXHREvent::GetInterfaces(PRUint32* aCount,
nsIID*** aArray)
{
PRUint32 count = *aCount = mProgressEvent ? 2 : 1;
*aArray = (nsIID**)nsMemory::Alloc(sizeof(nsIID*) * count);
if (mProgressEvent) {
(*aArray)[--count] =
(nsIID*)nsMemory::Clone(&NS_GET_IID(nsIDOMProgressEvent), sizeof(nsIID));
}
(*aArray)[--count] =
(nsIID *)nsMemory::Clone(&NS_GET_IID(nsIDOMEvent), sizeof(nsIID));
NS_ASSERTION(!count, "Bad math!");
return NS_OK;
}
nsresult
nsDOMWorkerXHREvent::Init(PRUint32 aXHREventType,
const nsAString& aType,
nsIDOMEvent* aEvent,
SnapshotChoice aSnapshot)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aEvent, "Don't pass null here!");
mXHREventType = aXHREventType;
// Only set a channel id if we're not going to be run immediately.
mChannelID = mXHRProxy->mSyncEventQueue ? -1 : mXHRProxy->ChannelID();
mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR);
NS_ENSURE_TRUE(mTarget, NS_ERROR_UNEXPECTED);
mXHRWN = mXHRProxy->mWorkerXHR->GetWrappedNative();
NS_ENSURE_STATE(mXHRWN);
nsCOMPtr<nsIDOMEventTarget> mainThreadTarget;
nsresult rv = aEvent->GetTarget(getter_AddRefs(mainThreadTarget));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(mainThreadTarget);
nsCOMPtr<nsIXMLHttpRequestUpload> upload(do_QueryInterface(mainThreadTarget));
if (upload) {
mUploadEvent = PR_TRUE;
mTarget =
static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR->mUpload);
}
else {
mUploadEvent = PR_FALSE;
mTarget = static_cast<nsDOMWorkerMessageHandler*>(mXHRProxy->mWorkerXHR);
}
NS_ASSERTION(mTarget, "Null target!");
PRBool bubbles;
rv = aEvent->GetBubbles(&bubbles);
NS_ENSURE_SUCCESS(rv, rv);
PRBool cancelable;
rv = aEvent->GetCancelable(&cancelable);
NS_ENSURE_SUCCESS(rv, rv);
rv = aEvent->GetTimeStamp(&mTimeStamp);
NS_ENSURE_SUCCESS(rv, rv);
rv = aEvent->GetEventPhase(&mEventPhase);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(mEventPhase == nsIDOMEvent::AT_TARGET, "Unsupported phase!");
nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(aEvent));
if (progressEvent) {
mProgressEvent = PR_TRUE;
PRBool lengthComputable;
rv = progressEvent->GetLengthComputable(&lengthComputable);
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 loaded;
rv = progressEvent->GetLoaded(&loaded);
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 total;
rv = progressEvent->GetTotal(&total);
NS_ENSURE_SUCCESS(rv, rv);
rv = InitProgressEvent(aType, bubbles, cancelable, lengthComputable, loaded,
total);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
mProgressEvent = PR_FALSE;
rv = InitEvent(aType, bubbles, cancelable);
NS_ENSURE_SUCCESS(rv, rv);
}
mState = new nsDOMWorkerXHRState();
NS_ENSURE_TRUE(mState, NS_ERROR_OUT_OF_MEMORY);
if (aSnapshot == SNAPSHOT) {
SnapshotXHRState(mXHRProxy->mXHR, mState);
}
return NS_OK;
}
/* static */
void
nsDOMWorkerXHREvent::SnapshotXHRState(nsIXMLHttpRequest* aXHR,
nsDOMWorkerXHRState* aState)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aXHR && aState, "Don't pass null here!");
aState->responseTextResult = aXHR->GetResponseText(aState->responseText);
aState->statusTextResult = aXHR->GetStatusText(aState->statusText);
aState->statusResult = aXHR->GetStatus(&aState->status);
aState->readyStateResult = aXHR->GetReadyState(&aState->readyState);
}
NS_IMETHODIMP
nsDOMWorkerXHREvent::Run()
{
nsresult rv = mXHRProxy->HandleWorkerEvent(this, mUploadEvent);
// Prevent reference cycles by releasing this here.
mXHRProxy = nsnull;
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerErrorEvent, nsDOMWorkerEvent,
nsIWorkerErrorEvent)
NS_IMPL_CI_INTERFACE_GETTER2(nsDOMWorkerErrorEvent, nsIDOMEvent,
nsIWorkerErrorEvent)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerErrorEvent)
nsresult
nsDOMWorkerErrorEvent::GetMessage(nsAString& aMessage)
{
aMessage.Assign(mMessage);
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::GetFilename(nsAString& aFilename)
{
aFilename.Assign(mFilename);
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::GetLineno(PRUint32* aLineno)
{
NS_ENSURE_ARG_POINTER(aLineno);
*aLineno = mLineno;
return NS_OK;
}
nsresult
nsDOMWorkerErrorEvent::InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg)
{
mMessage.Assign(aMessageArg);
mFilename.Assign(aFilenameArg);
mLineno = aLinenoArg;
return InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
}

View File

@ -0,0 +1,340 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKEREVENTS_H__
#define __NSDOMWORKEREVENTS_H__
#include "nsIClassInfo.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMProgressEvent.h"
#include "nsIDOMWorkers.h"
#include "nsIRunnable.h"
#include "jsapi.h"
#include "jsutil.h"
#include "nsAutoJSValHolder.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsDOMWorkerMacros.h"
class nsDOMWorkerXHRProxy;
class nsIXMLHttpRequest;
class nsIXPConnectWrappedNative;
/* 4d5794d6-98ab-4a6b-ad5a-8ed1fa1d4839 */
#define NS_IDOMWORKERPRIVATEEVENT_IID \
{ \
0x4d5794d6, \
0x98ab, \
0x4a6b, \
{ 0xad, 0x5a, 0x8e, 0xd1, 0xfa, 0x1d, 0x48, 0x39 } \
}
class nsIDOMWorkerPrivateEvent : public nsIDOMEvent
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMWORKERPRIVATEEVENT_IID)
virtual PRBool PreventDefaultCalled() = 0;
};
#define NS_FORWARD_NSIDOMEVENT_SPECIAL \
NS_IMETHOD GetType(nsAString& aType) \
{ return mEvent->GetType(aType); } \
NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) \
{ return mEvent->GetTarget(aTarget); } \
NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) \
{ return mEvent->GetCurrentTarget(aCurrentTarget); } \
NS_IMETHOD GetEventPhase(PRUint16* aEventPhase) \
{ return mEvent->GetEventPhase(aEventPhase); } \
NS_IMETHOD GetBubbles(PRBool* aBubbles) \
{ return mEvent->GetBubbles(aBubbles); } \
NS_IMETHOD GetCancelable(PRBool* aCancelable) \
{ return mEvent->GetCancelable(aCancelable); } \
NS_IMETHOD GetTimeStamp(DOMTimeStamp* aTimeStamp) \
{ return mEvent->GetTimeStamp(aTimeStamp); } \
NS_IMETHOD StopPropagation() \
{ return mEvent->StopPropagation(); }
#define NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL \
NS_IMETHOD GetLengthComputable(PRBool* aLengthComputable) \
{ return mProgressEvent->GetLengthComputable(aLengthComputable); } \
NS_IMETHOD GetLoaded(PRUint64* aLoaded) \
{ return mProgressEvent->GetLoaded(aLoaded); } \
NS_IMETHOD GetTotal(PRUint64* aTotal) \
{ return mProgressEvent->GetTotal(aTotal); }
#define NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL \
NS_IMETHOD GetData(nsAString& aData) \
{ return mMessageEvent->GetData(aData); } \
NS_IMETHOD GetOrigin(nsAString& aOrigin) \
{ return mMessageEvent->GetOrigin(aOrigin); } \
NS_IMETHOD GetSource(nsISupports** aSource) \
{ return mMessageEvent->GetSource(aSource); }
#define NS_FORWARD_NSIWORKERERROREVENT_SPECIAL \
NS_IMETHOD GetMessage(nsAString& aMessage) \
{ return mErrorEvent->GetMessage(aMessage); } \
NS_IMETHOD GetFilename(nsAString& aFilename) \
{ return mErrorEvent->GetFilename(aFilename); } \
NS_IMETHOD GetLineno(PRUint32* aLineno) \
{ return mErrorEvent->GetLineno(aLineno); }
class nsDOMWorkerPrivateEvent : public nsIDOMWorkerPrivateEvent,
public nsIDOMProgressEvent,
public nsIWorkerMessageEvent,
public nsIWorkerErrorEvent,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSIDOMEVENT_SPECIAL
NS_FORWARD_NSIWORKERMESSAGEEVENT_SPECIAL
NS_FORWARD_NSIDOMPROGRESSEVENT_SPECIAL
NS_FORWARD_NSIWORKERERROREVENT_SPECIAL
NS_DECL_NSICLASSINFO
nsDOMWorkerPrivateEvent(nsIDOMEvent* aEvent);
NS_IMETHOD PreventDefault();
NS_IMETHOD InitEvent(const nsAString& aEventType,
PRBool aCanBubble,
PRBool aCancelable);
NS_IMETHOD InitProgressEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
PRBool aLengthComputableArg,
PRUint64 aLoadedArg,
PRUint64 aTotalArg);
NS_IMETHOD InitMessageEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aDataArg,
const nsAString& aOriginArg,
nsISupports* aSourceArg);
NS_IMETHOD InitErrorEvent(const nsAString& aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString& aMessageArg,
const nsAString& aFilenameArg,
PRUint32 aLinenoArg);
NS_IMETHOD GetDefaultPrevented(PRBool* aRetVal);
virtual PRBool PreventDefaultCalled();
private:
nsCOMPtr<nsIDOMEvent> mEvent;
nsCOMPtr<nsIDOMProgressEvent> mProgressEvent;
nsCOMPtr<nsIWorkerMessageEvent> mMessageEvent;
nsCOMPtr<nsIWorkerErrorEvent> mErrorEvent;
PRBool mPreventDefaultCalled;
};
class nsDOMWorkerEvent : public nsIDOMEvent,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENT
NS_DECL_NSICLASSINFO
nsDOMWorkerEvent()
: mEventPhase(nsIDOMEvent::AT_TARGET), mTimeStamp(0), mBubbles(PR_FALSE),
mCancelable(PR_FALSE), mPreventDefaultCalled(PR_FALSE) { }
void SetTarget(nsIDOMEventTarget* aTarget) {
mTarget = aTarget;
}
PRBool PreventDefaultCalled() {
return PRBool(mPreventDefaultCalled);
}
protected:
virtual ~nsDOMWorkerEvent() { }
nsString mType;
nsCOMPtr<nsIDOMEventTarget> mTarget;
PRUint16 mEventPhase;
DOMTimeStamp mTimeStamp;
PRPackedBool mBubbles;
PRPackedBool mCancelable;
PRPackedBool mPreventDefaultCalled;
};
class nsDOMWorkerMessageEvent : public nsDOMWorkerEvent,
public nsIWorkerMessageEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIWORKERMESSAGEEVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerMessageEvent() : mData(nsnull) { }
~nsDOMWorkerMessageEvent();
nsresult SetJSData(JSContext* aCx,
JSAutoStructuredCloneBuffer& aBuffer,
nsTArray<nsCOMPtr<nsISupports> >& aWrappedNatives);
protected:
nsString mOrigin;
nsCOMPtr<nsISupports> mSource;
nsAutoJSValHolder mDataVal;
uint64* mData;
size_t mDataLen;
nsTArray<nsCOMPtr<nsISupports> > mWrappedNatives;
};
class nsDOMWorkerProgressEvent : public nsDOMWorkerEvent,
public nsIDOMProgressEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIDOMPROGRESSEVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerProgressEvent()
: mLoaded(0), mTotal(0), mLengthComputable(PR_FALSE) { }
protected:
PRUint64 mLoaded;
PRUint64 mTotal;
PRBool mLengthComputable;
};
class nsDOMWorkerXHRState
{
public:
nsDOMWorkerXHRState()
: responseTextResult(NS_OK), statusTextResult(NS_OK), status(NS_OK),
statusResult(NS_OK), readyState(0), readyStateResult(NS_OK) { }
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
nsString responseText;
nsresult responseTextResult;
nsCString statusText;
nsresult statusTextResult;
nsresult status;
nsresult statusResult;
PRUint16 readyState;
nsresult readyStateResult;
protected:
virtual ~nsDOMWorkerXHRState() { }
nsAutoRefCnt mRefCnt;
};
class nsDOMWorkerXHREvent : public nsDOMWorkerProgressEvent,
public nsIRunnable
{
friend class nsDOMWorkerXHRProxy;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
NS_DECL_NSICLASSINFO_GETINTERFACES
enum SnapshotChoice {
SNAPSHOT,
NO_SNAPSHOT
};
nsDOMWorkerXHREvent(nsDOMWorkerXHRProxy* aXHRProxy);
nsresult Init(PRUint32 aXHREventType,
const nsAString& aType,
nsIDOMEvent* aEvent,
SnapshotChoice = SNAPSHOT);
static void SnapshotXHRState(nsIXMLHttpRequest* aXHR,
nsDOMWorkerXHRState* aState);
already_AddRefed<nsDOMWorkerXHRState> ForgetState() {
return mState.forget();
}
protected:
nsDOMWorkerXHRState* GetState() {
return mState;
}
nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy;
nsCOMPtr<nsIXPConnectWrappedNative> mXHRWN;
nsRefPtr<nsDOMWorkerXHRState> mState;
PRUint32 mXHREventType;
PRInt32 mChannelID;
PRPackedBool mUploadEvent;
PRPackedBool mProgressEvent;
};
class nsDOMWorkerErrorEvent : public nsDOMWorkerEvent,
public nsIWorkerErrorEvent
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENT(nsDOMWorkerEvent::)
NS_DECL_NSIWORKERERROREVENT
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerErrorEvent()
: mLineno(0) { }
protected:
nsString mMessage;
nsString mFilename;
PRUint32 mLineno;
};
#endif /* __NSDOMWORKEREVENTS_H__ */

View File

@ -0,0 +1,135 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERMACROS_H__
#define __NSDOMWORKERMACROS_H__
// Macro to generate nsIClassInfo methods for these threadsafe DOM classes
#define NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
NS_IMETHODIMP \
_class::GetInterfaces(PRUint32* _count, nsIID*** _array) \
{ \
return NS_CI_INTERFACE_GETTER_NAME(_class)(_count, _array); \
} \
#define NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \
NS_IMETHODIMP \
_class::GetHelperForLanguage(PRUint32 _language, nsISupports** _retval) \
{ \
*_retval = nsnull; \
return NS_OK; \
}
#define NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class) \
NS_IMETHODIMP \
_class::GetContractID(char** _contractID) \
{ \
*_contractID = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassDescription(char** _classDescription) \
{ \
*_classDescription = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassID(nsCID** _classID) \
{ \
*_classID = nsnull; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetImplementationLanguage(PRUint32* _language) \
{ \
*_language = nsIProgrammingLanguage::CPLUSPLUS; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetFlags(PRUint32* _flags) \
{ \
*_flags = nsIClassInfo::THREADSAFE | nsIClassInfo::DOM_OBJECT; \
return NS_OK; \
} \
\
NS_IMETHODIMP \
_class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc) \
{ \
return NS_ERROR_NOT_AVAILABLE; \
}
#define NS_IMPL_THREADSAFE_DOM_CI(_class) \
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(_class) \
NS_IMPL_THREADSAFE_DOM_CI_HELPER(_class) \
NS_IMPL_THREADSAFE_DOM_CI_ALL_THE_REST(_class)
#define NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(_to) \
NS_IMETHOD GetHelperForLanguage(PRUint32 aLanguage, nsISupports** _retval) \
{ return _to GetHelperForLanguage(aLanguage, _retval); } \
NS_IMETHOD GetContractID(char** aContractID) \
{ return _to GetContractID(aContractID); } \
NS_IMETHOD GetClassDescription(char** aClassDescription) \
{ return _to GetClassDescription(aClassDescription); } \
NS_IMETHOD GetClassID(nsCID** aClassID) \
{ return _to GetClassID(aClassID); } \
NS_IMETHOD GetImplementationLanguage(PRUint32* aImplementationLanguage) \
{ return _to GetImplementationLanguage(aImplementationLanguage); } \
NS_IMETHOD GetFlags(PRUint32* aFlags) \
{ return _to GetFlags(aFlags); } \
NS_IMETHOD GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) \
{ return _to GetClassIDNoAlloc(aClassIDNoAlloc); }
#define NS_DECL_NSICLASSINFO_GETINTERFACES \
NS_IMETHOD GetInterfaces(PRUint32* aCount, nsIID*** aArray);
// Don't know why nsISupports.idl defines this out...
#define NS_FORWARD_NSISUPPORTS(_to) \
NS_IMETHOD QueryInterface(const nsIID& uuid, void** result) { \
return _to QueryInterface(uuid, result); \
} \
NS_IMETHOD_(nsrefcnt) AddRef(void) { return _to AddRef(); } \
NS_IMETHOD_(nsrefcnt) Release(void) { return _to Release(); }
#define JSON_PRIMITIVE_PROPNAME \
"primitive"
#endif /* __NSDOMWORKERMACROS_H__ */

View File

@ -0,0 +1,440 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerMessageHandler.h"
#include "nsIDOMEvent.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerEvents.h"
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerEventListenerBase)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerEventListenerBase)
nsresult
nsDOMWorkerWeakEventListener::Init(nsIDOMEventListener* aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS(do_QueryInterface(aListener));
NS_ENSURE_TRUE(wrappedJS, NS_NOINTERFACE);
JSObject* obj;
nsresult rv = wrappedJS->GetJSObject(&obj);
NS_ENSURE_SUCCESS(rv, rv);
mObj = obj;
return NS_OK;
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerWeakEventListener::GetListener()
{
JSContext* cx = nsDOMThreadService::GetCurrentContext();
NS_ENSURE_TRUE(cx, nsnull);
nsIXPConnect* xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIDOMEventListener> listener;
nsresult rv = xpc->WrapJS(cx, mObj, NS_GET_IID(nsIDOMEventListener),
getter_AddRefs(listener));
NS_ENSURE_SUCCESS(rv, nsnull);
return listener.forget();
}
nsDOMWorkerWrappedWeakEventListener::
nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner)
: mInner(aInner)
{
NS_ASSERTION(aInner, "Null pointer!");
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerMessageHandler,
nsIDOMEventTarget,
nsIClassInfo)
NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerMessageHandler,
nsIDOMEventTarget)
NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerMessageHandler)
const nsDOMWorkerMessageHandler::ListenerCollection*
nsDOMWorkerMessageHandler::GetListenerCollection(const nsAString& aType) const
{
PRUint32 count = mCollections.Length();
for (PRUint32 index = 0; index < count; index++) {
const ListenerCollection& collection = mCollections[index];
if (collection.type.Equals(aType)) {
return &collection;
}
}
return nsnull;
}
void
nsDOMWorkerMessageHandler::GetListenersForType(const nsAString& aType,
ListenerArray& _retval) const
{
_retval.Clear();
const ListenerCollection* collection = GetListenerCollection(aType);
if (collection) {
PRUint32 count = collection->listeners.Length();
if (!_retval.SetLength(count)) {
NS_WARNING("Out of memory!");
return;
}
for (PRUint32 index = 0; index < count; index++) {
nsCOMPtr<nsIDOMEventListener> listener =
collection->listeners[index]->GetListener();
_retval[index].swap(listener);
}
}
}
nsresult
nsDOMWorkerMessageHandler::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
nsRefPtr<nsDOMWorkerWrappedWeakEventListener> wrappedListener;
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
#ifdef DEBUG
PRBool removed;
#endif
if (collection) {
wrappedListener.swap(collection->onXListener);
if (wrappedListener) {
#ifdef DEBUG
removed =
#endif
collection->listeners.RemoveElement(wrappedListener);
NS_ASSERTION(removed, "Element wasn't in the list!");
}
}
if (!aListener) {
if (collection && !collection->listeners.Length()) {
#ifdef DEBUG
removed =
#endif
mCollections.RemoveElement(*collection);
NS_ASSERTION(removed, "Element wasn't in the list!");
}
return NS_OK;
}
nsRefPtr<nsDOMWorkerWeakEventListener> weakListener =
new nsDOMWorkerWeakEventListener();
NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = weakListener->Init(aListener);
NS_ENSURE_SUCCESS(rv, rv);
wrappedListener = new nsDOMWorkerWrappedWeakEventListener(weakListener);
NS_ENSURE_TRUE(wrappedListener, NS_ERROR_OUT_OF_MEMORY);
if (!collection) {
collection = mCollections.AppendElement(aType);
NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY);
}
WeakListener* newListener =
collection->listeners.AppendElement(wrappedListener);
NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY);
wrappedListener.swap(collection->onXListener);
return NS_OK;
}
already_AddRefed<nsIDOMEventListener>
nsDOMWorkerMessageHandler::GetOnXListener(const nsAString& aType) const
{
const ListenerCollection* collection = GetListenerCollection(aType);
if (collection && collection->onXListener) {
return collection->onXListener->GetListener();
}
return nsnull;
}
void
nsDOMWorkerMessageHandler::ClearListeners(const nsAString& aType)
{
PRUint32 count = mCollections.Length();
for (PRUint32 index = 0; index < count; index++) {
if (mCollections[index].type.Equals(aType)) {
mCollections.RemoveElementAt(index);
return;
}
}
}
PRBool
nsDOMWorkerMessageHandler::HasListeners(const nsAString& aType)
{
const ListenerCollection* collection = GetListenerCollection(aType);
return collection && collection->listeners.Length();
}
void
nsDOMWorkerMessageHandler::ClearAllListeners()
{
mCollections.Clear();
}
void
nsDOMWorkerMessageHandler::Trace(JSTracer* aTracer)
{
PRUint32 cCount = mCollections.Length();
for (PRUint32 cIndex = 0; cIndex < cCount; cIndex++) {
const ListenerCollection& collection = mCollections[cIndex];
PRUint32 lCount = collection.listeners.Length();
for (PRUint32 lIndex = 0; lIndex < lCount; lIndex++) {
JSObject* obj = collection.listeners[lIndex]->GetJSObject();
NS_ASSERTION(obj, "Null object!");
JS_SET_TRACING_DETAILS(aTracer, nsnull, this, 0);
JS_CallTracer(aTracer, obj, JSTRACE_OBJECT);
}
}
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
if (collection) {
PRUint32 count = collection->listeners.Length();
for (PRUint32 index = 0; index < count; index++) {
WeakListener& weakListener = collection->listeners[index];
if (weakListener == collection->onXListener) {
continue;
}
nsCOMPtr<nsIDOMEventListener> listener = weakListener->GetListener();
if (listener == aListener) {
collection->listeners.RemoveElementAt(index);
break;
}
}
if (!collection->listeners.Length()) {
#ifdef DEBUG
PRBool removed =
#endif
mCollections.RemoveElement(*collection);
NS_ASSERTION(removed, "Somehow this wasn't in the list!");
}
}
return NS_OK;
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval)
{
NS_ENSURE_ARG_POINTER(aEvent);
nsCOMPtr<nsIDOMWorkerPrivateEvent> event;
if (_retval) {
event = do_QueryInterface(aEvent);
if (!event) {
event = new nsDOMWorkerPrivateEvent(aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
}
aEvent = event;
}
nsAutoString type;
nsresult rv = aEvent->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoTArray<Listener, 10> listeners;
GetListenersForType(type, listeners);
PRUint32 count = listeners.Length();
for (PRUint32 index = 0; index < count; index++) {
const Listener& listener = listeners[index];
NS_ASSERTION(listener, "Null listener in array!");
listener->HandleEvent(aEvent);
}
if (_retval) {
*_retval = event->PreventDefaultCalled();
}
return NS_OK;
}
/**
* See nsIDOMEventTarget
*/
NS_IMETHODIMP
nsDOMWorkerMessageHandler::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 aOptionalArgc)
{
// We don't support aWantsUntrusted yet.
NS_ENSURE_TRUE(aOptionalArgc < 2, NS_ERROR_NOT_IMPLEMENTED);
ListenerCollection* collection =
const_cast<ListenerCollection*>(GetListenerCollection(aType));
if (!collection) {
collection = mCollections.AppendElement(aType);
NS_ENSURE_TRUE(collection, NS_ERROR_OUT_OF_MEMORY);
}
nsRefPtr<nsDOMWorkerWeakEventListener> weakListener =
new nsDOMWorkerWeakEventListener();
NS_ENSURE_TRUE(weakListener, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = weakListener->Init(aListener);
NS_ENSURE_SUCCESS(rv, rv);
WeakListener* newListener = collection->listeners.AppendElement(weakListener);
NS_ENSURE_TRUE(newListener, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
nsIDOMEventTarget *
nsDOMWorkerMessageHandler::GetTargetForDOMEvent()
{
NS_ERROR("Should not be called");
return nsnull;
}
nsIDOMEventTarget *
nsDOMWorkerMessageHandler::GetTargetForEventTargetChain()
{
NS_ERROR("Should not be called");
return nsnull;
}
nsresult
nsDOMWorkerMessageHandler::PreHandleEvent(nsEventChainPreVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::WillHandleEvent(nsEventChainPostVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::PostHandleEvent(nsEventChainPostVisitor & aVisitor)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent,
nsPresContext *aPresContext,
nsEventStatus *aEventStatus)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsEventListenerManager*
nsDOMWorkerMessageHandler::GetListenerManager(PRBool aMayCreate)
{
NS_ERROR("Should not be called");
return nsnull;
}
nsresult
nsDOMWorkerMessageHandler::AddEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID & aIID)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
nsDOMWorkerMessageHandler::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID & aIID)
{
NS_ERROR("Should not be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIScriptContext*
nsDOMWorkerMessageHandler::GetContextForEventHandlers(nsresult *aRv)
{
NS_ERROR("Should not be called");
*aRv = NS_ERROR_NOT_IMPLEMENTED;
return nsnull;
}
JSContext*
nsDOMWorkerMessageHandler::GetJSContextForEventHandlers()
{
NS_ERROR("Should not be called");
return nsnull;
}

View File

@ -0,0 +1,175 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERMESSAGEHANDLER_H__
#define __NSDOMWORKERMESSAGEHANDLER_H__
#include "nsIClassInfo.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMWorkers.h"
#include "nsIProgrammingLanguage.h"
#include "jsapi.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIClassInfoImpl.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsIWeakReference.h"
class nsDOMWorkerEventListenerBase
{
public:
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
virtual already_AddRefed<nsIDOMEventListener> GetListener() = 0;
virtual JSObject* GetJSObject() = 0;
protected:
virtual ~nsDOMWorkerEventListenerBase() { }
nsAutoRefCnt mRefCnt;
};
class nsDOMWorkerWeakEventListener : public nsDOMWorkerEventListenerBase
{
public:
nsDOMWorkerWeakEventListener()
: mObj(NULL) { }
nsresult Init(nsIDOMEventListener* aListener);
already_AddRefed<nsIDOMEventListener> GetListener();
virtual JSObject* GetJSObject() {
return mObj;
}
private:
JSObject* mObj;
};
class nsDOMWorkerWrappedWeakEventListener : public nsDOMWorkerEventListenerBase
{
public:
nsDOMWorkerWrappedWeakEventListener(nsDOMWorkerWeakEventListener* aInner);
already_AddRefed<nsIDOMEventListener> GetListener() {
return mInner->GetListener();
}
virtual JSObject* GetJSObject() {
return mInner->GetJSObject();
}
private:
nsRefPtr<nsDOMWorkerWeakEventListener> mInner;
};
class nsDOMWorkerMessageHandler : public nsIDOMEventTarget,
public nsIClassInfo
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_NSICLASSINFO
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
already_AddRefed<nsIDOMEventListener>
GetOnXListener(const nsAString& aType) const;
void ClearListeners(const nsAString& aType);
PRBool HasListeners(const nsAString& aType);
void ClearAllListeners();
void Trace(JSTracer* aTracer);
protected:
virtual ~nsDOMWorkerMessageHandler() { }
private:
typedef nsCOMPtr<nsIDOMEventListener> Listener;
typedef nsTArray<Listener> ListenerArray;
typedef nsRefPtr<nsDOMWorkerEventListenerBase> WeakListener;
typedef nsTArray<WeakListener> WeakListenerArray;
struct ListenerCollection {
PRBool operator==(const ListenerCollection& aOther) const {
return this == &aOther;
}
ListenerCollection(const nsAString& aType)
: type(aType) { }
nsString type;
WeakListenerArray listeners;
nsRefPtr<nsDOMWorkerWrappedWeakEventListener> onXListener;
};
const ListenerCollection* GetListenerCollection(const nsAString& aType) const;
void GetListenersForType(const nsAString& aType,
ListenerArray& _retval) const;
nsTArray<ListenerCollection> mCollections;
};
#define NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(_to) \
virtual nsIDOMEventTarget * GetTargetForDOMEvent(void) { return _to GetTargetForDOMEvent(); } \
virtual nsIDOMEventTarget * GetTargetForEventTargetChain(void) { return _to GetTargetForEventTargetChain(); } \
virtual nsresult PreHandleEvent(nsEventChainPreVisitor & aVisitor) { return _to PreHandleEvent(aVisitor); } \
virtual nsresult WillHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to WillHandleEvent(aVisitor); } \
virtual nsresult PostHandleEvent(nsEventChainPostVisitor & aVisitor) { return _to PostHandleEvent(aVisitor); } \
virtual nsresult DispatchDOMEvent(nsEvent *aEvent, nsIDOMEvent *aDOMEvent, nsPresContext *aPresContext, nsEventStatus *aEventStatus) { return _to DispatchDOMEvent(aEvent, aDOMEvent, aPresContext, aEventStatus); } \
virtual nsEventListenerManager * GetListenerManager(PRBool aMayCreate) { return _to GetListenerManager(aMayCreate); } \
virtual nsresult AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to AddEventListenerByIID(aListener, aIID); } \
virtual nsresult RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID & aIID) { return _to RemoveEventListenerByIID(aListener, aIID); } \
virtual nsIScriptContext * GetContextForEventHandlers(nsresult *aRv NS_OUTPARAM) { return _to GetContextForEventHandlers(aRv); } \
virtual JSContext * GetJSContextForEventHandlers(void) { return _to GetJSContextForEventHandlers(); }
#endif /* __NSDOMWORKERMESSAGEHANDLER_H__ */

View File

@ -0,0 +1,238 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerPool.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMClassInfo.h"
#include "nsIJSContextStack.h"
#include "nsIScriptGlobalObject.h"
#include "nsIServiceManager.h"
#include "nsIThreadManager.h"
#include "nsIXPConnect.h"
#include "nsPIDOMWindow.h"
// Other includes
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorker.h"
using namespace mozilla;
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
nsDOMWorkerPool::nsDOMWorkerPool(nsIScriptGlobalObject* aGlobalObject,
nsIDocument* aDocument)
: mParentGlobal(aGlobalObject),
mParentDocument(aDocument),
mReentrantMonitor("nsDOMWorkerPool.mReentrantMonitor"),
mCanceled(PR_FALSE),
mSuspended(PR_FALSE),
mWindowID(aDocument ? aDocument->OuterWindowID() : 0)
{
}
nsDOMWorkerPool::~nsDOMWorkerPool()
{
nsCOMPtr<nsIThread> mainThread;
NS_GetMainThread(getter_AddRefs(mainThread));
nsIScriptGlobalObject* global;
mParentGlobal.forget(&global);
if (global) {
NS_ProxyRelease(mainThread, global, PR_FALSE);
}
nsIDocument* document;
mParentDocument.forget(&document);
if (document) {
NS_ProxyRelease(mainThread, document, PR_FALSE);
}
}
NS_IMPL_THREADSAFE_ADDREF(nsDOMWorkerPool)
NS_IMPL_THREADSAFE_RELEASE(nsDOMWorkerPool)
nsresult
nsDOMWorkerPool::Init()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return NS_OK;
}
nsresult
nsDOMWorkerPool::NoteWorker(nsDOMWorker* aWorker)
{
NS_ASSERTION(aWorker, "Null pointer!");
PRBool suspendWorker;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsDOMWorker** newWorker = mWorkers.AppendElement(aWorker);
NS_ENSURE_TRUE(newWorker, NS_ERROR_OUT_OF_MEMORY);
suspendWorker = mSuspended;
}
if (suspendWorker) {
aWorker->Suspend();
}
return NS_OK;
}
void
nsDOMWorkerPool::NoteDyingWorker(nsDOMWorker* aWorker)
{
NS_ASSERTION(aWorker, "Null pointer!");
PRBool removeFromThreadService = PR_FALSE;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mWorkers.Contains(aWorker), "Worker from a different pool?!");
mWorkers.RemoveElement(aWorker);
if (!mCanceled && !mWorkers.Length()) {
removeFromThreadService = PR_TRUE;
}
}
if (removeFromThreadService) {
nsRefPtr<nsDOMWorkerPool> kungFuDeathGrip(this);
nsDOMThreadService::get()->NoteEmptyPool(this);
}
}
void
nsDOMWorkerPool::GetWorkers(nsTArray<nsDOMWorker*>& aArray)
{
mReentrantMonitor.AssertCurrentThreadIn();
NS_ASSERTION(!aArray.Length(), "Should be empty!");
#ifdef DEBUG
nsDOMWorker** newWorkers =
#endif
aArray.AppendElements(mWorkers);
NS_WARN_IF_FALSE(newWorkers, "Out of memory!");
}
void
nsDOMWorkerPool::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mCanceled, "Canceled more than once!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mCanceled = PR_TRUE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
if (count) {
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Cancel();
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mon.NotifyAll();
}
}
void
nsDOMWorkerPool::Suspend()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(!mSuspended, "Suspended more than once!");
mSuspended = PR_TRUE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Suspend();
}
}
void
nsDOMWorkerPool::Resume()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsAutoTArray<nsDOMWorker*, 10> workers;
{
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mSuspended, "Not suspended!");
mSuspended = PR_FALSE;
GetWorkers(workers);
}
PRUint32 count = workers.Length();
if (count) {
for (PRUint32 index = 0; index < count; index++) {
workers[index]->Resume();
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mon.NotifyAll();
}
}

View File

@ -0,0 +1,118 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com> (Original Author)
* Ben Turner <bent.mozilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERPOOL_H__
#define __NSDOMWORKERPOOL_H__
// Other includes
#include "jsapi.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class nsDOMWorker;
class nsIDocument;
class nsIScriptContext;
class nsIScriptError;
class nsIScriptGlobalObject;
class nsDOMWorkerPool
{
typedef mozilla::ReentrantMonitor ReentrantMonitor;
public:
nsDOMWorkerPool(nsIScriptGlobalObject* aGlobalObject,
nsIDocument* aDocument);
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
nsIScriptGlobalObject* ScriptGlobalObject() {
return mParentGlobal;
}
nsIDocument* ParentDocument() {
return mParentDocument;
}
nsresult Init();
void Cancel();
void Suspend();
void Resume();
nsresult NoteWorker(nsDOMWorker* aWorker);
void NoteDyingWorker(nsDOMWorker* aWorker);
ReentrantMonitor& GetReentrantMonitor() {
return mReentrantMonitor;
}
const PRUint64 WindowID() const {
return mWindowID;
}
private:
virtual ~nsDOMWorkerPool();
void GetWorkers(nsTArray<nsDOMWorker*>& aArray);
nsAutoRefCnt mRefCnt;
// Reference to the window that created and owns this pool.
nsCOMPtr<nsIScriptGlobalObject> mParentGlobal;
// Reference to the document that created this pool.
nsCOMPtr<nsIDocument> mParentDocument;
// Weak array of workers. The idea is that workers can be garbage collected
// independently of the owning pool and other workers.
nsTArray<nsDOMWorker*> mWorkers;
// ReentrantMonitor for suspending and resuming workers.
ReentrantMonitor mReentrantMonitor;
PRPackedBool mCanceled;
PRPackedBool mSuspended;
const PRUint64 mWindowID;
};
#endif /* __NSDOMWORKERPOOL_H__ */

View File

@ -0,0 +1,881 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerScriptLoader.h"
// Interfaces
#include "nsIChannel.h"
#include "nsIContentPolicy.h"
#include "nsIHttpChannel.h"
#include "nsIIOService.h"
#include "nsIProtocolHandler.h"
#include "nsIRequest.h"
#include "nsIScriptSecurityManager.h"
#include "nsIStreamLoader.h"
// Other includes
#include "nsContentErrors.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
#include "nsISupportsPrimitives.h"
#include "nsNetError.h"
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsThreadUtils.h"
#include "pratom.h"
#include "nsDocShellCID.h"
#include "nsIChannelPolicy.h"
#include "nsChannelPolicy.h"
#include "nsIContentSecurityPolicy.h"
// DOMWorker includes
#include "nsDOMWorkerPool.h"
#include "nsDOMWorkerSecurityManager.h"
#include "nsDOMThreadService.h"
#include "nsDOMWorkerTimeout.h"
using namespace mozilla;
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
nsDOMWorkerScriptLoader::nsDOMWorkerScriptLoader(nsDOMWorker* aWorker)
: nsDOMWorkerFeature(aWorker),
mTarget(nsnull),
mScriptCount(0),
mCanceled(PR_FALSE),
mForWorker(PR_FALSE)
{
// Created on worker thread.
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorker, "Null worker!");
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDOMWorkerScriptLoader, nsDOMWorkerFeature,
nsIRunnable,
nsIStreamLoaderObserver)
nsresult
nsDOMWorkerScriptLoader::LoadScripts(JSContext* aCx,
const nsTArray<nsString>& aURLs,
PRBool aExecute)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aCx, "Null context!");
mTarget = NS_GetCurrentThread();
NS_ASSERTION(mTarget, "This should never be null!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
mScriptCount = aURLs.Length();
if (!mScriptCount) {
return NS_ERROR_INVALID_ARG;
}
// Do all the memory work for these arrays now rather than checking for
// failures all along the way.
PRBool success = mLoadInfos.SetCapacity(mScriptCount);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
// Need one runnable per script and then an extra for the finished
// notification.
success = mPendingRunnables.SetCapacity(mScriptCount + 1);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo* newInfo = mLoadInfos.AppendElement();
NS_ASSERTION(newInfo, "Shouldn't fail if SetCapacity succeeded above!");
newInfo->url.Assign(aURLs[index]);
if (newInfo->url.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
}
success = newInfo->scriptObj.Hold(aCx);
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
}
// Don't want timeouts, etc., from queuing up while we're waiting on the
// network or compiling.
AutoSuspendWorkerEvents aswe(this);
nsresult rv = DoRunLoop(aCx);
if (NS_FAILED(rv)) {
return rv;
}
// Verify that all scripts downloaded and compiled.
rv = VerifyScripts(aCx);
if (NS_FAILED(rv)) {
return rv;
}
if (aExecute) {
rv = ExecuteScripts(aCx);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::LoadWorkerScript(JSContext* aCx,
const nsString& aURL)
{
mForWorker = PR_TRUE;
nsAutoTArray<nsString, 1> url;
url.AppendElement(aURL);
return LoadScripts(aCx, url, PR_FALSE);
}
nsresult
nsDOMWorkerScriptLoader::DoRunLoop(JSContext* aCx)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
volatile PRBool done = PR_FALSE;
mDoneRunnable = new ScriptLoaderDone(this, &done);
NS_ENSURE_TRUE(mDoneRunnable, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = NS_DispatchToMainThread(this);
NS_ENSURE_SUCCESS(rv, rv);
while (!(done || mCanceled)) {
JSAutoSuspendRequest asr(aCx);
NS_ProcessNextEvent(mTarget);
}
return mCanceled ? NS_ERROR_ABORT : NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::VerifyScripts(JSContext* aCx)
{
NS_ASSERTION(aCx, "Shouldn't be null!");
nsresult rv = NS_OK;
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
NS_ASSERTION(loadInfo.done, "Inconsistent state!");
if (NS_SUCCEEDED(loadInfo.result) && loadInfo.scriptObj.ToJSObject()) {
continue;
}
NS_ASSERTION(!loadInfo.scriptObj.ToJSObject(), "Inconsistent state!");
// Flag failure before worrying about whether or not to report an error.
rv = NS_FAILED(loadInfo.result) ? loadInfo.result : NS_ERROR_FAILURE;
// If loadInfo.result is a success code then the compiler probably reported
// an error already. Also we don't really care about NS_BINDING_ABORTED
// since that's the code we set when some other script had a problem and the
// rest were canceled.
if (NS_SUCCEEDED(loadInfo.result) || loadInfo.result == NS_BINDING_ABORTED) {
continue;
}
// Ok, this is the script that caused us to fail.
JSAutoRequest ar(aCx);
// Only throw an error if there is no other pending exception.
if (!JS_IsExceptionPending(aCx)) {
const char* message;
switch (loadInfo.result) {
case NS_ERROR_MALFORMED_URI:
message = "Malformed script URI: %s";
break;
case NS_ERROR_FILE_NOT_FOUND:
case NS_ERROR_NOT_AVAILABLE:
message = "Script file not found: %s";
break;
default:
message = "Failed to load script: %s (nsresult = 0x%x)";
break;
}
NS_ConvertUTF16toUTF8 url(loadInfo.url);
JS_ReportError(aCx, message, url.get(), loadInfo.result);
}
break;
}
return rv;
}
nsresult
nsDOMWorkerScriptLoader::ExecuteScripts(JSContext* aCx)
{
NS_ASSERTION(aCx, "Shouldn't be null!");
// Now execute all the scripts.
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
JSAutoRequest ar(aCx);
JSObject* scriptObj = loadInfo.scriptObj.ToJSObject();
NS_ASSERTION(scriptObj, "This shouldn't ever be null!");
JSObject* global = mWorker->mGlobal ?
mWorker->mGlobal :
JS_GetGlobalObject(aCx);
NS_ENSURE_STATE(global);
// Because we may have nested calls to this function we don't want the
// execution to automatically report errors. We let them propagate instead.
uint32 oldOpts =
JS_SetOptions(aCx, JS_GetOptions(aCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
PRBool success = JS_ExecuteScript(aCx, global, scriptObj, NULL);
JS_SetOptions(aCx, oldOpts);
if (!success) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
void
nsDOMWorkerScriptLoader::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mCanceled, "Cancel called more than once!");
mCanceled = PR_TRUE;
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsIRequest* request =
static_cast<nsIRequest*>(loadInfo.channel.get());
if (request) {
#ifdef DEBUG
nsresult rv =
#endif
request->Cancel(NS_BINDING_ABORTED);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to cancel channel!");
}
}
nsAutoTArray<ScriptLoaderRunnable*, 10> runnables;
{
MutexAutoLock lock(mWorker->GetLock());
runnables.AppendElements(mPendingRunnables);
mPendingRunnables.Clear();
}
PRUint32 runnableCount = runnables.Length();
for (PRUint32 index = 0; index < runnableCount; index++) {
runnables[index]->Revoke();
}
// We're about to post a revoked event to the worker thread, which seems
// silly, but we have to do this because the worker thread may be sleeping
// waiting on its event queue.
NotifyDone();
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// We may have been canceled already.
if (mCanceled) {
return NS_BINDING_ABORTED;
}
nsresult rv = RunInternal();
if (NS_SUCCEEDED(rv)) {
return rv;
}
// Ok, something failed beyond a normal cancel.
// If necko is holding a ref to us then we'll end up notifying in the
// OnStreamComplete method, not here.
PRBool needsNotify = PR_TRUE;
// Cancel any async channels that were already opened.
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsIRequest* request = static_cast<nsIRequest*>(loadInfo.channel.get());
if (request) {
#ifdef DEBUG
nsresult rvInner =
#endif
request->Cancel(NS_BINDING_ABORTED);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rvInner), "Failed to cancel channel!");
// Necko is holding a ref to us so make sure that the OnStreamComplete
// code sends the done event.
needsNotify = PR_FALSE;
}
else {
// Make sure to set this so that the OnStreamComplete code will dispatch
// the done event.
loadInfo.done = PR_TRUE;
}
}
if (needsNotify) {
NotifyDone();
}
return rv;
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
PRUint32 aStringLen,
const PRUint8* aString)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// We may have been canceled already.
if (mCanceled) {
return NS_BINDING_ABORTED;
}
nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus, aStringLen,
aString);
// Dispatch the done event if we've received all the data.
for (PRUint32 index = 0; index < mScriptCount; index++) {
if (!mLoadInfos[index].done) {
// Some async load is still outstanding, don't notify yet.
break;
}
if (index == mScriptCount - 1) {
// All loads complete, signal the thread.
NotifyDone();
}
}
return rv;
}
nsresult
nsDOMWorkerScriptLoader::RunInternal()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mForWorker) {
NS_ASSERTION(mScriptCount == 1, "Bad state!");
}
nsRefPtr<nsDOMWorker> parentWorker = mWorker->GetParent();
// Figure out which principal to use.
nsIPrincipal* principal = mWorker->GetPrincipal();
if (!principal) {
if (!parentWorker) {
NS_ERROR("Must have a principal if this is not a subworker!");
}
principal = parentWorker->GetPrincipal();
}
NS_ASSERTION(principal, "This should never be null here!");
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI;
if (mForWorker) {
if (parentWorker) {
baseURI = parentWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
else {
// May be null.
baseURI = mWorker->GetBaseURI();
// Don't leave a temporary URI hanging around.
mWorker->ClearBaseURI();
}
NS_ASSERTION(!mWorker->GetBaseURI(), "Should not be set here!");
}
else {
baseURI = mWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
}
nsCOMPtr<nsIDocument> parentDoc = mWorker->Pool()->ParentDocument();
// All of these can potentially be null, but that should be ok. We'll either
// succeed without them or fail below.
nsCOMPtr<nsILoadGroup> loadGroup;
if (parentDoc) {
loadGroup = parentDoc->GetDocumentLoadGroup();
}
nsCOMPtr<nsIIOService> ios(do_GetIOService());
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
NS_ASSERTION(secMan, "This should never be null!");
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
nsresult& rv = loadInfo.result;
nsCOMPtr<nsIURI>& uri = loadInfo.finalURI;
rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
loadInfo.url, parentDoc,
baseURI);
if (NS_FAILED(rv)) {
return rv;
}
// If we're part of a document then check the content load policy.
if (parentDoc) {
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT, uri,
principal, parentDoc,
NS_LITERAL_CSTRING("text/javascript"),
nsnull, &shouldLoad,
nsContentUtils::GetContentPolicy(),
secMan);
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
return (rv = NS_ERROR_CONTENT_BLOCKED);
}
return (rv = NS_ERROR_CONTENT_BLOCKED_SHOW_ALT);
}
}
// If this script loader is being used to make a new worker then we need to
// do a same-origin check. Otherwise we need to clear the load with the
// security manager.
rv = mForWorker ?
principal->CheckMayLoad(uri, PR_FALSE):
secMan->CheckLoadURIWithPrincipal(principal, uri, 0);
NS_ENSURE_SUCCESS(rv, rv);
// We need to know which index we're on in OnStreamComplete so we know where
// to put the result.
nsCOMPtr<nsISupportsPRUint32> indexSupports =
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = indexSupports->SetData(index);
NS_ENSURE_SUCCESS(rv, rv);
// We don't care about progress so just use the simple stream loader for
// OnStreamComplete notification only.
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
NS_ENSURE_SUCCESS(rv, rv);
// Get Content Security Policy from parent document to pass into channel
nsCOMPtr<nsIContentSecurityPolicy> csp;
rv = principal->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannelPolicy> channelPolicy;
if (csp) {
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetContentSecurityPolicy(csp);
NS_ENSURE_SUCCESS(rv, rv);
rv = channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SCRIPT);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = NS_NewChannel(getter_AddRefs(loadInfo.channel),
uri, ios, loadGroup, nsnull,
nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI,
channelPolicy);
NS_ENSURE_SUCCESS(rv, rv);
rv = loadInfo.channel->AsyncOpen(loader, indexSupports);
if (NS_FAILED(rv)) {
// Null this out so we don't try to cancel it later.
loadInfo.channel = nsnull;
return rv;
}
}
return NS_OK;
}
nsresult
nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader,
nsISupports* aContext,
nsresult aStatus,
PRUint32 aStringLen,
const PRUint8* aString)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
NS_ENSURE_TRUE(indexSupports, NS_ERROR_NO_INTERFACE);
PRUint32 index = PR_UINT32_MAX;
indexSupports->GetData(&index);
if (index >= mScriptCount) {
NS_NOTREACHED("This really can't fail or we'll hang!");
return NS_ERROR_FAILURE;
}
ScriptLoadInfo& loadInfo = mLoadInfos[index];
NS_ASSERTION(!loadInfo.done, "Got complete on the same load twice!");
loadInfo.done = PR_TRUE;
// Use an alias to keep rv and loadInfo.result in sync.
nsresult& rv = loadInfo.result;
if (NS_FAILED(aStatus)) {
return rv = aStatus;
}
if (!(aStringLen && aString)) {
return rv = NS_ERROR_UNEXPECTED;
}
// Make sure we're not seeing the result of a 404 or something by checking the
// 'requestSucceeded' attribute on the http channel.
nsCOMPtr<nsIRequest> request;
rv = aLoader->GetRequest(getter_AddRefs(request));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (httpChannel) {
PRBool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
NS_ENSURE_SUCCESS(rv, rv);
if (!requestSucceeded) {
return rv = NS_ERROR_NOT_AVAILABLE;
}
}
// May be null.
nsIDocument* parentDoc = mWorker->Pool()->ParentDocument();
// Use the regular nsScriptLoader for this grunt work! Should be just fine
// because we're running on the main thread.
rv = nsScriptLoader::ConvertToUTF16(loadInfo.channel, aString, aStringLen,
EmptyString(), parentDoc,
loadInfo.scriptText);
if (NS_FAILED(rv)) {
return rv;
}
if (loadInfo.scriptText.IsEmpty()) {
return rv = NS_ERROR_FAILURE;
}
nsCString filename;
rv = loadInfo.finalURI->GetSpec(filename);
NS_ENSURE_SUCCESS(rv, rv);
if (filename.IsEmpty()) {
filename.Assign(NS_LossyConvertUTF16toASCII(loadInfo.url));
}
else {
// This will help callers figure out what their script url resolved to in
// case of errors.
loadInfo.url.Assign(NS_ConvertUTF8toUTF16(filename));
}
// Update the principal of the worker and its base URI if we just loaded the
// worker's primary script.
if (mForWorker) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ASSERTION(channel, "This should never fail!");
// Take care of the base URI first.
nsCOMPtr<nsIURI> finalURI;
rv = NS_GetFinalChannelURI(channel, getter_AddRefs(finalURI));
NS_ENSURE_SUCCESS(rv, rv);
mWorker->SetBaseURI(finalURI);
// Now to figure out which principal to give this worker.
nsRefPtr<nsDOMWorker> parent = mWorker->GetParent();
NS_ASSERTION(mWorker->GetPrincipal() || parent, "Must have one of these!");
nsCOMPtr<nsIPrincipal> loadPrincipal = mWorker->GetPrincipal() ?
mWorker->GetPrincipal() :
parent->GetPrincipal();
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
NS_ASSERTION(ssm, "Should never be null!");
nsCOMPtr<nsIPrincipal> channelPrincipal;
rv = ssm->GetChannelPrincipal(channel, getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
// See if this is a resource URI. Since JSMs usually come from resource://
// URIs we're currently considering all URIs with the URI_IS_UI_RESOURCE
// flag as valid for creating privileged workers.
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
PRBool isResource;
rv = NS_URIChainHasFlags(finalURI,
nsIProtocolHandler::URI_IS_UI_RESOURCE,
&isResource);
NS_ENSURE_SUCCESS(rv, rv);
if (isResource) {
rv = ssm->GetSystemPrincipal(getter_AddRefs(channelPrincipal));
NS_ENSURE_SUCCESS(rv, rv);
}
}
// If the load principal is the system principal then the channel principal
// must also be the system principal (we do not allow chrome code to create
// workers with non-chrome scripts). Otherwise this channel principal must
// be same origin with the load principal (we check again here in case
// redirects changed the location of the script).
if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) {
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
return rv = NS_ERROR_DOM_BAD_URI;
}
}
else if (NS_FAILED(loadPrincipal->CheckMayLoad(finalURI, PR_FALSE))) {
return rv = NS_ERROR_DOM_BAD_URI;
}
mWorker->SetPrincipal(channelPrincipal);
}
nsRefPtr<ScriptCompiler> compiler =
new ScriptCompiler(this, loadInfo.scriptText, filename, loadInfo.scriptObj);
NS_ASSERTION(compiler, "Out of memory!");
if (!compiler) {
return rv = NS_ERROR_OUT_OF_MEMORY;
}
rv = mTarget->Dispatch(compiler, NS_DISPATCH_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
void
nsDOMWorkerScriptLoader::NotifyDone()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!mDoneRunnable) {
// We've already completed, no need to cancel anything.
return;
}
for (PRUint32 index = 0; index < mScriptCount; index++) {
ScriptLoadInfo& loadInfo = mLoadInfos[index];
// Null both of these out because they aren't threadsafe and must be
// destroyed on this thread.
loadInfo.channel = nsnull;
loadInfo.finalURI = nsnull;
if (mCanceled) {
// Simulate a complete, yet failed, load.
loadInfo.done = PR_TRUE;
loadInfo.result = NS_BINDING_ABORTED;
}
}
#ifdef DEBUG
nsresult rv =
#endif
mTarget->Dispatch(mDoneRunnable, NS_DISPATCH_NORMAL);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't dispatch done event!");
mDoneRunnable = nsnull;
}
void
nsDOMWorkerScriptLoader::SuspendWorkerEvents()
{
NS_ASSERTION(mWorker, "No worker yet!");
mWorker->SuspendFeatures();
}
void
nsDOMWorkerScriptLoader::ResumeWorkerEvents()
{
NS_ASSERTION(mWorker, "No worker yet!");
mWorker->ResumeFeatures();
}
nsDOMWorkerScriptLoader::
ScriptLoaderRunnable::ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader)
: mRevoked(PR_FALSE),
mLoader(aLoader)
{
MutexAutoLock lock(aLoader->GetLock());
#ifdef DEBUG
nsDOMWorkerScriptLoader::ScriptLoaderRunnable** added =
#endif
aLoader->mPendingRunnables.AppendElement(this);
NS_ASSERTION(added, "This shouldn't fail because we SetCapacity earlier!");
}
nsDOMWorkerScriptLoader::
ScriptLoaderRunnable::~ScriptLoaderRunnable()
{
if (!mRevoked) {
MutexAutoLock lock(mLoader->GetLock());
#ifdef DEBUG
PRBool removed =
#endif
mLoader->mPendingRunnables.RemoveElement(this);
NS_ASSERTION(removed, "Someone has changed the array!");
}
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerScriptLoader::ScriptLoaderRunnable,
nsIRunnable)
void
nsDOMWorkerScriptLoader::ScriptLoaderRunnable::Revoke()
{
mRevoked = PR_TRUE;
}
nsDOMWorkerScriptLoader::
ScriptCompiler::ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
const nsString& aScriptText,
const nsCString& aFilename,
nsAutoJSValHolder& aScriptObj)
: ScriptLoaderRunnable(aLoader),
mScriptText(aScriptText),
mFilename(aFilename),
mScriptObj(aScriptObj)
{
NS_ASSERTION(!aScriptText.IsEmpty(), "No script to compile!");
NS_ASSERTION(aScriptObj.IsHeld(), "Should be held!");
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::ScriptCompiler::Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mRevoked) {
return NS_OK;
}
NS_ASSERTION(!mScriptObj.ToJSObject(), "Already have a script object?!");
NS_ASSERTION(mScriptObj.IsHeld(), "Not held?!");
NS_ASSERTION(!mScriptText.IsEmpty(), "Shouldn't have empty source here!");
JSContext* cx = nsDOMThreadService::GetCurrentContext();
NS_ENSURE_STATE(cx);
JSAutoRequest ar(cx);
JSObject* global = JS_GetGlobalObject(cx);
NS_ENSURE_STATE(global);
// Because we may have nested calls to this function we don't want the
// execution to automatically report errors. We let them propagate instead.
uint32 oldOpts =
JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_DONT_REPORT_UNCAUGHT |
JSOPTION_NO_SCRIPT_RVAL);
JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
JSObject* scriptObj =
JS_CompileUCScriptForPrincipals(cx, global, principal,
reinterpret_cast<const jschar*>
(mScriptText.BeginReading()),
mScriptText.Length(), mFilename.get(), 1);
JS_SetOptions(cx, oldOpts);
if (!scriptObj) {
return NS_ERROR_FAILURE;
}
mScriptObj = scriptObj;
return NS_OK;
}
nsDOMWorkerScriptLoader::
ScriptLoaderDone::ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
volatile PRBool* aDoneFlag)
: ScriptLoaderRunnable(aLoader),
mDoneFlag(aDoneFlag)
{
NS_ASSERTION(aDoneFlag && !*aDoneFlag, "Bad setup!");
}
NS_IMETHODIMP
nsDOMWorkerScriptLoader::ScriptLoaderDone::Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mRevoked) {
return NS_OK;
}
*mDoneFlag = PR_TRUE;
return NS_OK;
}
nsDOMWorkerScriptLoader::
AutoSuspendWorkerEvents::AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader)
: mLoader(aLoader)
{
NS_ASSERTION(aLoader, "Don't hand me null!");
aLoader->SuspendWorkerEvents();
}
nsDOMWorkerScriptLoader::
AutoSuspendWorkerEvents::~AutoSuspendWorkerEvents()
{
mLoader->ResumeWorkerEvents();
}

View File

@ -0,0 +1,148 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerSecurityManager.h"
// Interfaces
#include "nsIClassInfo.h"
// Other includes
#include "jsapi.h"
#include "nsDOMError.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorker.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
class nsDOMWorkerPrincipal
{
public:
static void Destroy(JSContext*, JSPrincipals*) {
// nothing
}
static JSBool Subsume(JSPrincipals*, JSPrincipals*) {
return JS_TRUE;
}
};
static JSPrincipals gWorkerPrincipal =
{ "domworkerthread" /* codebase */,
NULL /* getPrincipalArray */,
NULL /* globalPrivilegesEnabled */,
1 /* refcount */,
nsDOMWorkerPrincipal::Destroy /* destroy */,
nsDOMWorkerPrincipal::Subsume /* subsume */ };
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDOMWorkerSecurityManager,
nsIXPCSecurityManager)
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanCreateWrapper(JSContext* aCx,
const nsIID& aIID,
nsISupports* aObj,
nsIClassInfo* aClassInfo,
void** aPolicy)
{
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanCreateInstance(JSContext* aCx,
const nsCID& aCID)
{
return CanGetService(aCx, aCID);
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanGetService(JSContext* aCx,
const nsCID& aCID)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsDOMWorker* worker = static_cast<nsDOMWorker*>(JS_GetContextPrivate(aCx));
NS_ASSERTION(worker, "This should be set by the DOM thread service!");
return worker->IsPrivileged() ? NS_OK : NS_ERROR_DOM_XPCONNECT_ACCESS_DENIED;
}
NS_IMETHODIMP
nsDOMWorkerSecurityManager::CanAccess(PRUint32 aAction,
nsAXPCNativeCallContext* aCallContext,
JSContext* aJSContext,
JSObject* aJSObject,
nsISupports* aObj,
nsIClassInfo* aClassInfo,
jsid aName,
void** aPolicy)
{
return NS_OK;
}
JSPrincipals*
nsDOMWorkerSecurityManager::WorkerPrincipal()
{
return &gWorkerPrincipal;
}
JSBool
nsDOMWorkerSecurityManager::JSCheckAccess(JSContext* aCx,
JSObject* aObj,
jsid aId,
JSAccessMode aMode,
jsval* aVp)
{
return JS_TRUE;
}
JSPrincipals*
nsDOMWorkerSecurityManager::JSFindPrincipal(JSContext* aCx, JSObject* aObj)
{
return WorkerPrincipal();
}
JSBool
nsDOMWorkerSecurityManager::JSTranscodePrincipals(JSXDRState* aXdr,
JSPrincipals** aJsprinp)
{
NS_NOTREACHED("Shouldn't ever call this!");
return JS_FALSE;
}

View File

@ -0,0 +1,62 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERSECURITYMANAGER_H__
#define __NSDOMWORKERSECURITYMANAGER_H__
#include "nsIXPCSecurityManager.h"
#include "jsapi.h"
class nsDOMWorkerSecurityManager : public nsIXPCSecurityManager
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCSECURITYMANAGER
static JSPrincipals* WorkerPrincipal();
static JSBool JSCheckAccess(JSContext* aCx, JSObject* aObj, jsid aId,
JSAccessMode aMode, jsval* aVp);
static JSPrincipals* JSFindPrincipal(JSContext* aCx, JSObject* aObj);
static JSBool JSTranscodePrincipals(JSXDRState* aXdr,
JSPrincipals** aJsprinp);
};
#endif /* __NSDOMWORKERSECURITYMANAGER_H__ */

View File

@ -0,0 +1,485 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerTimeout.h"
// Interfaces
#include "nsIJSContextStack.h"
#include "nsIJSRuntimeService.h"
#include "nsITimer.h"
#include "nsIXPConnect.h"
// Other includes
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
#include "pratom.h"
#include "prtime.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorkerSecurityManager.h"
#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
#define CONSTRUCTOR_ENSURE_TRUE(_cond, _rv) \
PR_BEGIN_MACRO \
if (NS_UNLIKELY(!(_cond))) { \
NS_WARNING("CONSTRUCTOR_ENSURE_TRUE(" #_cond ") failed"); \
(_rv) = NS_ERROR_FAILURE; \
return; \
} \
PR_END_MACRO
#define SUSPEND_SPINLOCK_COUNT 5000
static const char* kSetIntervalStr = "setInterval";
static const char* kSetTimeoutStr = "setTimeout";
nsDOMWorkerTimeout::FunctionCallback::FunctionCallback(PRUint32 aArgc,
jsval* aArgv,
nsresult* aRv)
: mCallbackArgsLength(0)
{
MOZ_COUNT_CTOR(nsDOMWorkerTimeout::FunctionCallback);
JSRuntime* rt;
*aRv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
if (NS_FAILED(*aRv))
return;
JSBool ok = mCallback.Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mCallback = aArgv[0];
// We want enough space for an extra lateness arg.
mCallbackArgsLength = aArgc > 2 ? aArgc - 1 : 1;
PRBool success = mCallbackArgs.SetLength(mCallbackArgsLength);
CONSTRUCTOR_ENSURE_TRUE(success, *aRv);
PRUint32 index = 0;
for (; index < mCallbackArgsLength - 1; index++) {
ok = mCallbackArgs[index].Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mCallbackArgs[index] = aArgv[index + 2];
}
// Take care of the last arg.
index = mCallbackArgsLength - 1;
ok = mCallbackArgs[index].Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
*aRv = NS_OK;
}
nsDOMWorkerTimeout::FunctionCallback::~FunctionCallback()
{
MOZ_COUNT_DTOR(nsDOMWorkerTimeout::FunctionCallback);
}
nsresult
nsDOMWorkerTimeout::FunctionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx)
{
PRInt32 lateness = NS_MAX(0, PRInt32(PR_Now() - aTimeout->mTargetTime)) /
(PRTime)PR_USEC_PER_MSEC;
mCallbackArgs[mCallbackArgsLength - 1] = INT_TO_JSVAL(lateness);
JSObject* global = JS_GetGlobalObject(aCx);
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
nsTArray<jsval> argv;
PRBool success = argv.SetCapacity(mCallbackArgsLength);
NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
for (PRUint32 index = 0; index < mCallbackArgsLength; index++) {
argv.AppendElement(mCallbackArgs[index]);
}
jsval rval;
JSBool ok =
JS_CallFunctionValue(aCx, global, mCallback, mCallbackArgsLength,
argv.Elements(), &rval);
NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
return NS_OK;
}
nsDOMWorkerTimeout::ExpressionCallback::ExpressionCallback(PRUint32 aArgc,
jsval* aArgv,
JSContext* aCx,
nsresult* aRv)
: mLineNumber(0)
{
MOZ_COUNT_CTOR(nsDOMWorkerTimeout::ExpressionCallback);
JSString* expr = JS_ValueToString(aCx, aArgv[0]);
*aRv = expr ? NS_OK : NS_ERROR_FAILURE;
if (NS_FAILED(*aRv))
return;
JSRuntime* rt;
*aRv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
if (NS_FAILED(*aRv))
return;
JSBool ok = mExpression.Hold(rt);
CONSTRUCTOR_ENSURE_TRUE(ok, *aRv);
mExpression = aArgv[0];
// Get the calling location.
const char* fileName;
PRUint32 lineNumber;
if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNumber)) {
mFileName.Assign(fileName);
mLineNumber = lineNumber;
}
*aRv = NS_OK;
}
nsDOMWorkerTimeout::ExpressionCallback::~ExpressionCallback()
{
MOZ_COUNT_DTOR(nsDOMWorkerTimeout::ExpressionCallback);
}
nsresult
nsDOMWorkerTimeout::ExpressionCallback::Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx)
{
JSObject* global = JS_GetGlobalObject(aCx);
NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
JSPrincipals* principal = nsDOMWorkerSecurityManager::WorkerPrincipal();
NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
JSString* expression = JS_ValueToString(aCx, mExpression);
NS_ENSURE_TRUE(expression, NS_ERROR_FAILURE);
size_t stringLength;
const jschar* string = JS_GetStringCharsAndLength(aCx, expression, &stringLength);
NS_ENSURE_TRUE(string, NS_ERROR_FAILURE);
PRBool success = JS_EvaluateUCScriptForPrincipals(aCx, global, principal,
string, stringLength,
mFileName.get(),
mLineNumber, nsnull);
if (!success) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsDOMWorkerTimeout::nsDOMWorkerTimeout(nsDOMWorker* aWorker,
PRUint32 aId)
: nsDOMWorkerFeature(aWorker, aId),
mInterval(0),
mSuspendSpinlock(0),
mSuspendInterval(0),
mIsInterval(PR_FALSE),
mIsSuspended(PR_FALSE),
mSuspendedBeforeStart(PR_FALSE),
mStarted(PR_FALSE)
{
NS_ASSERTION(mWorker, "Need a worker here!");
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerTimeout, nsDOMWorkerFeature,
nsITimerCallback)
nsresult
nsDOMWorkerTimeout::Init(JSContext* aCx, PRUint32 aArgc, jsval* aArgv,
PRBool aIsInterval)
{
NS_ASSERTION(aCx, "Null pointer!");
NS_ASSERTION(aArgv, "Null pointer!");
JSAutoRequest ar(aCx);
if (!aArgc) {
JS_ReportError(aCx, "Function %s requires at least 1 parameter",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return NS_ERROR_INVALID_ARG;
}
PRUint32 interval;
if (aArgc > 1) {
if (!JS_ValueToECMAUint32(aCx, aArgv[1], (uint32*)&interval)) {
JS_ReportError(aCx, "Second argument to %s must be a millisecond value",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
return NS_ERROR_INVALID_ARG;
}
}
else {
// If no interval was specified, treat this like a timeout, to avoid
// setting an interval of 0 milliseconds.
interval = 0;
aIsInterval = PR_FALSE;
}
mInterval = interval;
mIsInterval = aIsInterval;
mTargetTime = PR_Now() + interval * (PRTime)PR_USEC_PER_MSEC;
nsresult rv;
switch (JS_TypeOfValue(aCx, aArgv[0])) {
case JSTYPE_FUNCTION:
mCallback = new FunctionCallback(aArgc, aArgv, &rv);
NS_ENSURE_TRUE(mCallback, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
break;
case JSTYPE_STRING:
case JSTYPE_OBJECT:
mCallback = new ExpressionCallback(aArgc, aArgv, aCx, &rv);
NS_ENSURE_TRUE(mCallback, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
break;
default:
JS_ReportError(aCx, "useless %s call (missing quotes around argument?)",
aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
// Return an error that nsGlobalWindow can recognize and turn into NS_OK.
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIEventTarget* target =
static_cast<nsIEventTarget*>(nsDOMThreadService::get());
rv = timer->SetTarget(target);
NS_ENSURE_SUCCESS(rv, rv);
mTimer.swap(timer);
return NS_OK;
}
nsresult
nsDOMWorkerTimeout::Start()
{
if (IsSuspended()) {
NS_ASSERTION(mSuspendedBeforeStart, "Bad state!");
return NS_OK;
}
nsresult rv = mTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv, rv);
mStarted = PR_TRUE;
return NS_OK;
}
nsresult
nsDOMWorkerTimeout::Run()
{
NS_ENSURE_TRUE(mCallback, NS_ERROR_NOT_INITIALIZED);
LOG(("Worker [0x%p] running timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
JSContext* cx;
nsresult rv =
nsDOMThreadService::ThreadJSContextStack()->GetSafeJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoRequest ar(cx);
rv = mCallback->Run(this, cx);
// Make sure any pending exceptions are converted to errors for the pool.
JS_ReportPendingException(cx);
if (mIsInterval) {
mTargetTime = PR_Now() + mInterval * (PRTime)PR_USEC_PER_MSEC;
nsresult rv2 = mTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_ONE_SHOT);
NS_ENSURE_SUCCESS(rv2, rv2);
}
return rv;
}
void
nsDOMWorkerTimeout::Cancel()
{
NS_ASSERTION(mTimer, "Impossible to get here without a timer!");
LOG(("Worker [0x%p] canceling timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
{
AutoSpinlock lock(this);
if (IsSuspendedNoLock()) {
mIsSuspended = PR_FALSE;
// This should kill us when all is said and done.
mSuspendedRef = nsnull;
}
}
// This call to Cancel should kill us.
mTimer->Cancel();
}
void
nsDOMWorkerTimeout::Suspend()
{
AutoSpinlock lock(this);
NS_ASSERTION(!IsSuspendedNoLock(), "Bad state!");
mIsSuspended = PR_TRUE;
mSuspendedRef = this;
if (!mStarted) {
mSuspendedBeforeStart = PR_TRUE;
return;
}
mTimer->Cancel();
mSuspendInterval = NS_MAX(0, PRInt32(mTargetTime - PR_Now())) /
(PRTime)PR_USEC_PER_MSEC;
LOG(("Worker [0x%p] suspending timeout [0x%p] with id %u (interval = %u)",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId,
mSuspendInterval));
}
void
nsDOMWorkerTimeout::Resume()
{
NS_ASSERTION(mTimer, "Impossible to get here without a timer!");
LOG(("Worker [0x%p] resuming timeout [0x%p] with id %u",
static_cast<void*>(mWorker.get()), static_cast<void*>(this), mId));
AutoSpinlock lock(this);
NS_ASSERTION(IsSuspendedNoLock(), "Should be suspended!");
if (mSuspendedBeforeStart) {
NS_ASSERTION(!mSuspendInterval, "Bad state!");
mSuspendedBeforeStart = PR_FALSE;
mSuspendInterval = mInterval;
mStarted = PR_TRUE;
}
mTargetTime = PR_Now() + mSuspendInterval * (PRTime)PR_USEC_PER_MSEC;
#ifdef DEBUG
nsresult rv =
#endif
mTimer->InitWithCallback(this, mSuspendInterval, nsITimer::TYPE_ONE_SHOT);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to init timer!");
}
void
nsDOMWorkerTimeout::AcquireSpinlock()
{
PRUint32 loopCount = 0;
while (PR_ATOMIC_SET(&mSuspendSpinlock, 1) == 1) {
if (++loopCount > SUSPEND_SPINLOCK_COUNT) {
LOG(("AcquireSpinlock taking too long (looped %u times), yielding.",
loopCount));
loopCount = 0;
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
#ifdef PR_LOGGING
if (loopCount) {
LOG(("AcquireSpinlock needed %u loops", loopCount));
}
#endif
}
void
nsDOMWorkerTimeout::ReleaseSpinlock()
{
#ifdef DEBUG
PRInt32 suspended =
#endif
PR_ATOMIC_SET(&mSuspendSpinlock, 0);
NS_ASSERTION(suspended == 1, "Huh?!");
}
NS_IMETHODIMP
nsDOMWorkerTimeout::Notify(nsITimer* aTimer)
{
// Should be on the timer thread.
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aTimer == mTimer, "Wrong timer?!");
PRUint32 type;
nsresult rv = aTimer->GetType(&type);
NS_ENSURE_SUCCESS(rv, rv);
// We only care about one-shot timers here because that may be the one that
// we set from Resume().
if (type == nsITimer::TYPE_ONE_SHOT) {
AutoSpinlock lock(this);
if (mIsSuspended) {
mIsSuspended = PR_FALSE;
mSuspendedRef = nsnull;
if (mIsInterval) {
// This is the first fire since we resumed. Set our interval back to the
// real interval.
mTargetTime = PR_Now() + mInterval * (PRTime)PR_USEC_PER_MSEC;
rv = aTimer->InitWithCallback(this, mInterval,
nsITimer::TYPE_REPEATING_SLACK);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
nsDOMThreadService::get()->TimeoutReady(this);
return NS_OK;
}

View File

@ -0,0 +1,190 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERTIMEOUT_H__
#define __NSDOMWORKERTIMEOUT_H__
// Interfaces
#include "nsITimer.h"
// Other includes
#include "jsapi.h"
#include "nsAutoJSValHolder.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
// DOMWorker includes
#include "nsDOMWorker.h"
/**
* The nsDOMWorkerTimeout has a slightly complicated life cycle. It's created
* by an nsDOMWorker (or one of its JS context functions) and immediately takes
* a strong reference to the worker that created it. It does this so that the
* worker can't be collected while a timeout is outstanding. However, the worker
* needs a weak reference to the timeout so that it can be canceled if the
* worker is canceled (in the event that the page falls out of the fastback
* cache or the application is exiting, for instance). The only thing that holds
* the timeout alive is its mTimer via the nsITimerCallback interface. If the
* timer is single-shot and has run already or if the timer is canceled then
* this object should die.
*/
class nsDOMWorkerTimeout : public nsDOMWorkerFeature,
public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSITIMERCALLBACK
nsDOMWorkerTimeout(nsDOMWorker* aWorker,
PRUint32 aId);
nsresult Init(JSContext* aCx,
PRUint32 aArgc,
jsval* aArgv,
PRBool aIsInterval);
nsresult Start();
nsresult Run();
virtual void Cancel();
virtual void Suspend();
virtual void Resume();
PRIntervalTime GetInterval() {
return mInterval;
}
nsDOMWorker* GetWorker() {
return mWorker;
}
PRBool IsSuspended() {
AutoSpinlock lock(this);
return IsSuspendedNoLock();
}
private:
~nsDOMWorkerTimeout() { }
void AcquireSpinlock();
void ReleaseSpinlock();
PRBool IsSuspendedNoLock() {
return mIsSuspended;
}
class AutoSpinlock
{
public:
AutoSpinlock(nsDOMWorkerTimeout* aTimeout)
: mTimeout(aTimeout) {
aTimeout->AcquireSpinlock();
}
~AutoSpinlock() {
mTimeout->ReleaseSpinlock();
}
private:
nsDOMWorkerTimeout* mTimeout;
};
// We support two types of callbacks (functions and expressions) just like the
// normal window timeouts. Each type has its own member and rooting needs so
// we split them into two classes with a common base.
class CallbackBase
{
public:
virtual ~CallbackBase() { }
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx) = 0;
};
class FunctionCallback : public CallbackBase
{
public:
FunctionCallback(PRUint32 aArgc,
jsval* aArgv,
nsresult* aRv);
virtual ~FunctionCallback();
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx);
protected:
nsAutoJSValHolder mCallback;
nsTArray<nsAutoJSValHolder> mCallbackArgs;
PRUint32 mCallbackArgsLength;
};
class ExpressionCallback : public CallbackBase
{
public:
ExpressionCallback(PRUint32 aArgc,
jsval* aArgv,
JSContext* aCx,
nsresult* aRv);
virtual ~ExpressionCallback();
virtual nsresult Run(nsDOMWorkerTimeout* aTimeout,
JSContext* aCx);
protected:
nsAutoJSValHolder mExpression;
nsCString mFileName;
PRUint32 mLineNumber;
};
// Hold this object alive!
nsCOMPtr<nsITimer> mTimer;
PRUint32 mInterval;
PRTime mTargetTime;
nsAutoPtr<CallbackBase> mCallback;
PRInt32 mSuspendSpinlock;
PRUint32 mSuspendInterval;
nsRefPtr<nsDOMWorkerTimeout> mSuspendedRef;
PRPackedBool mIsInterval;
PRPackedBool mIsSuspended;
PRPackedBool mSuspendedBeforeStart;
PRPackedBool mStarted;
};
#endif /* __NSDOMWORKERTIMEOUT_H__ */

View File

@ -0,0 +1,910 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDOMWorkerXHR.h"
// Interfaces
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsIThread.h"
#include "nsIXPConnect.h"
// Other includes
#include "nsAXPCNativeCallContext.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIClassInfoImpl.h"
#include "nsJSUtils.h"
#include "nsThreadUtils.h"
// DOMWorker includes
#include "nsDOMThreadService.h"
#include "nsDOMWorkerEvents.h"
#include "nsDOMWorkerPool.h"
#include "nsDOMWorkerXHRProxy.h"
using namespace mozilla;
// The list of event types that we support. This list and the defines based on
// it determine the sizes of the listener arrays in nsDOMWorkerXHRProxy. Make
// sure that any event types shared by both the XHR and Upload objects are
// together at the beginning of the list. Any changes made to this list may
// affect sMaxUploadEventTypes, so make sure that it is adjusted accordingly or
// things will break!
const char* const nsDOMWorkerXHREventTarget::sListenerTypes[] = {
// nsIXMLHttpRequestEventTarget listeners.
"abort", /* LISTENER_TYPE_ABORT */
"error", /* LISTENER_TYPE_ERROR */
"load", /* LISTENER_TYPE_LOAD */
"loadstart", /* LISTENER_TYPE_LOADSTART */
"progress", /* LISTENER_TYPE_PROGRESS */
// nsIXMLHttpRequest listeners.
"readystatechange", /* LISTENER_TYPE_READYSTATECHANGE */
"loadend"
};
// This should always be set to the length of sListenerTypes.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxXHREventTypes =
NS_ARRAY_LENGTH(nsDOMWorkerXHREventTarget::sListenerTypes);
// This should be set to the index of the first event type that is *not*
// supported by the Upload object.
const PRUint32 nsDOMWorkerXHREventTarget::sMaxUploadEventTypes =
LISTENER_TYPE_READYSTATECHANGE;
// Enforce the invariant that the upload object supports no more event types
// than the xhr object.
PR_STATIC_ASSERT(nsDOMWorkerXHREventTarget::sMaxXHREventTypes >=
nsDOMWorkerXHREventTarget::sMaxUploadEventTypes);
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerXHREventTarget,
nsDOMWorkerMessageHandler,
nsIXMLHttpRequestEventTarget)
PRUint32
nsDOMWorkerXHREventTarget::GetListenerTypeFromString(const nsAString& aString)
{
for (PRUint32 index = 0; index < sMaxXHREventTypes; index++) {
if (aString.EqualsASCII(sListenerTypes[index])) {
return index;
}
}
return PR_UINT32_MAX;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnabort(nsIDOMEventListener** aOnabort)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnabort);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ABORT]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnabort);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnabort(nsIDOMEventListener* aOnabort)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ABORT]);
return SetOnXListener(type, aOnabort);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnerror(nsIDOMEventListener** aOnerror)
{
NS_ENSURE_ARG_POINTER(aOnerror);
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ERROR]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnerror);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnerror(nsIDOMEventListener* aOnerror)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_ERROR]);
return SetOnXListener(type, aOnerror);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnload(nsIDOMEventListener** aOnload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnload);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOAD]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnload(nsIDOMEventListener* aOnload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOAD]);
return SetOnXListener(type, aOnload);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnloadstart(nsIDOMEventListener** aOnloadstart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnloadstart);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADSTART]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnloadstart);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnloadstart(nsIDOMEventListener* aOnloadstart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADSTART]);
return SetOnXListener(type, aOnloadstart);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnprogress(nsIDOMEventListener** aOnprogress)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnprogress);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_PROGRESS]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnprogress);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnprogress(nsIDOMEventListener* aOnprogress)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_PROGRESS]);
return SetOnXListener(type, aOnprogress);
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::GetOnloadend(nsIDOMEventListener** aOnloadend)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aOnloadend);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADEND]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnloadend);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHREventTarget::SetOnloadend(nsIDOMEventListener* aOnloadend)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_LOADEND]);
return SetOnXListener(type, aOnloadend);
}
nsDOMWorkerXHRUpload::nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR)
: mWorkerXHR(aWorkerXHR)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorkerXHR, "Null pointer!");
}
NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerXHRUpload, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequestUpload)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHRUpload, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequestUpload)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerXHRUpload)
NS_IMETHODIMP
nsDOMWorkerXHRUpload::RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aListener);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
return nsDOMWorkerXHREventTarget::RemoveEventListener(aType, aListener,
aUseCapture);
}
NS_IMETHODIMP
nsDOMWorkerXHRUpload::DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aEvent);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
return nsDOMWorkerXHREventTarget::DispatchEvent(aEvent, _retval);
}
NS_IMETHODIMP
nsDOMWorkerXHRUpload::AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aListener);
if (mWorkerXHR->mWorker->IsCanceled()) {
return NS_ERROR_ABORT;
}
nsresult rv = nsDOMWorkerXHREventTarget::AddEventListener(aType, aListener,
aUseCapture,
aWantsUntrusted,
optional_argc);
NS_ENSURE_SUCCESS(rv, rv);
rv = mWorkerXHR->mXHRProxy->UploadEventListenerAdded();
if (NS_FAILED(rv)) {
NS_WARNING("UploadEventListenerAdded failed!");
RemoveEventListener(aType, aListener, aUseCapture);
return rv;
}
return NS_OK;
}
nsresult
nsDOMWorkerXHRUpload::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mWorkerXHR->mCanceled) {
return NS_ERROR_ABORT;
}
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxUploadEventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return nsDOMWorkerXHREventTarget::SetOnXListener(aType, aListener);
}
nsDOMWorkerXHR::nsDOMWorkerXHR(nsDOMWorker* aWorker)
: nsDOMWorkerFeature(aWorker),
mWrappedNative(nsnull),
mCanceled(PR_FALSE)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aWorker, "Must have a worker!");
}
nsDOMWorkerXHR::~nsDOMWorkerXHR()
{
if (mXHRProxy) {
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(mXHRProxy, &nsDOMWorkerXHRProxy::Destroy);
if (runnable) {
mXHRProxy = nsnull;
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
}
}
else {
mXHRProxy->Destroy();
}
}
}
// Tricky! We use the AddRef/Release method of nsDOMWorkerFeature (to make sure
// we properly remove ourselves from the worker array) but inherit the QI of
// nsDOMWorkerXHREventTarget.
NS_IMPL_ADDREF_INHERITED(nsDOMWorkerXHR, nsDOMWorkerFeature)
NS_IMPL_RELEASE_INHERITED(nsDOMWorkerXHR, nsDOMWorkerFeature)
NS_IMPL_QUERY_INTERFACE_INHERITED2(nsDOMWorkerXHR, nsDOMWorkerXHREventTarget,
nsIXMLHttpRequest,
nsIXPCScriptable)
NS_IMPL_CI_INTERFACE_GETTER3(nsDOMWorkerXHR, nsIDOMEventTarget,
nsIXMLHttpRequestEventTarget,
nsIXMLHttpRequest)
NS_IMPL_THREADSAFE_DOM_CI_GETINTERFACES(nsDOMWorkerXHR)
#define XPC_MAP_CLASSNAME nsDOMWorkerXHR
#define XPC_MAP_QUOTED_CLASSNAME "XMLHttpRequest"
#define XPC_MAP_WANT_POSTCREATE
#define XPC_MAP_WANT_TRACE
#define XPC_MAP_WANT_FINALIZE
#define XPC_MAP_FLAGS \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY | \
nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
#include "xpc_map_end.h"
NS_IMETHODIMP
nsDOMWorkerXHR::Trace(nsIXPConnectWrappedNative* /* aWrapper */,
JSTracer* aTracer,
JSObject* /*aObj */)
{
if (!mCanceled) {
nsDOMWorkerMessageHandler::Trace(aTracer);
if (mUpload) {
mUpload->Trace(aTracer);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Finalize(nsIXPConnectWrappedNative* /* aWrapper */,
JSContext* /* aCx */,
JSObject* /* aObj */)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsDOMWorkerMessageHandler::ClearAllListeners();
if (mUpload) {
mUpload->ClearAllListeners();
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::PostCreate(nsIXPConnectWrappedNative* aWrapper,
JSContext* /* aCx */,
JSObject* /* aObj */)
{
mWrappedNative = aWrapper;
return NS_OK;
}
nsresult
nsDOMWorkerXHR::Init()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsRefPtr<nsDOMWorkerXHRProxy> proxy = new nsDOMWorkerXHRProxy(this);
NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = proxy->Init();
NS_ENSURE_SUCCESS(rv, rv);
proxy.swap(mXHRProxy);
return NS_OK;
}
void
nsDOMWorkerXHR::Cancel()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Just in case mUpload holds the only ref to this object we make sure to stay
// alive through this call.
nsRefPtr<nsDOMWorkerXHR> kungFuDeathGrip(this);
{
// This lock is here to prevent a race between Cancel and GetUpload, not to
// protect mCanceled.
MutexAutoLock lock(mWorker->GetLock());
mCanceled = PR_TRUE;
mUpload = nsnull;
}
if (mXHRProxy) {
mXHRProxy->Destroy();
mXHRProxy = nsnull;
}
mWorker = nsnull;
}
nsresult
nsDOMWorkerXHR::SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
PRUint32 type = GetListenerTypeFromString(aType);
if (type > sMaxXHREventTypes) {
// Silently ignore junk events.
return NS_OK;
}
return nsDOMWorkerXHREventTarget::SetOnXListener(aType, aListener);
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetChannel(nsIChannel** aChannel)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aChannel);
*aChannel = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseXML(nsIDOMDocument** aResponseXML)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aResponseXML);
*aResponseXML = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseText(nsAString& aResponseText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseText(aResponseText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatus(PRUint32* aStatus)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(aStatus);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatus(aStatus);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetStatusText(nsACString& aStatusText)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetStatusText(aStatusText);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Abort()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->Abort();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetAllResponseHeaders(char** _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_ENSURE_ARG_POINTER(_retval);
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetAllResponseHeaders(_retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseHeader(const nsACString& aHeader,
nsACString& _retval)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->GetResponseHeader(aHeader, _retval);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Open(const nsACString& aMethod, const nsACString& aUrl,
PRBool aAsync, const nsAString& aUser,
const nsAString& aPassword, PRUint8 optional_argc)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (!optional_argc) {
aAsync = PR_TRUE;
}
nsresult rv = mXHRProxy->Open(aMethod, aUrl, aAsync, aUser, aPassword);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Send(nsIVariant* aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (mWorker->IsClosing() && !mXHRProxy->mSyncRequest) {
// Cheat and don't start this request since we know we'll never be able to
// use the data.
return NS_OK;
}
nsresult rv = mXHRProxy->Send(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SendAsBinary(const nsAString& aBody)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
if (mWorker->IsClosing() && !mXHRProxy->mSyncRequest) {
// Cheat and don't start this request since we know we'll never be able to
// use the data.
return NS_OK;
}
nsresult rv = mXHRProxy->SendAsBinary(aBody);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetRequestHeader(aHeader, aValue);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetReadyState(PRUint16* aReadyState)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aReadyState);
nsresult rv = mXHRProxy->GetReadyState(aReadyState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::OverrideMimeType(const nsACString& aMimetype)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->OverrideMimeType(aMimetype);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMultipart(PRBool* aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMultipart);
nsresult rv = mXHRProxy->GetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMultipart(PRBool aMultipart)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetMultipart(aMultipart);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetMozBackgroundRequest(PRBool* aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aMozBackgroundRequest);
*aMozBackgroundRequest = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetMozBackgroundRequest(PRBool aMozBackgroundRequest)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (aMozBackgroundRequest) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::Init(nsIPrincipal* aPrincipal,
nsIScriptContext* aScriptContext,
nsPIDOMWindow* aOwnerWindow,
nsIURI* aBaseURI)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
NS_NOTREACHED("No one should be calling this!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetUpload(nsIXMLHttpRequestUpload** aUpload)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
nsRefPtr<nsDOMWorker> worker = mWorker;
if (!worker) {
return NS_ERROR_ABORT;
}
MutexAutoLock lock(worker->GetLock());
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aUpload);
if (!mUpload) {
mUpload = new nsDOMWorkerXHRUpload(this);
NS_ENSURE_TRUE(mUpload, NS_ERROR_OUT_OF_MEMORY);
}
NS_ADDREF(*aUpload = mUpload);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetOnreadystatechange(nsIDOMEventListener** aOnreadystatechange)
{
NS_ENSURE_ARG_POINTER(aOnreadystatechange);
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_READYSTATECHANGE]);
nsCOMPtr<nsIDOMEventListener> listener = GetOnXListener(type);
listener.forget(aOnreadystatechange);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetOnreadystatechange(nsIDOMEventListener* aOnreadystatechange)
{
nsAutoString type;
type.AssignASCII(sListenerTypes[LISTENER_TYPE_READYSTATECHANGE]);
return SetOnXListener(type, aOnreadystatechange);
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetWithCredentials(PRBool* aWithCredentials)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
NS_ENSURE_ARG_POINTER(aWithCredentials);
nsresult rv = mXHRProxy->GetWithCredentials(aWithCredentials);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetWithCredentials(PRBool aWithCredentials)
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
if (mCanceled) {
return NS_ERROR_ABORT;
}
nsresult rv = mXHRProxy->SetWithCredentials(aWithCredentials);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponseType(nsAString& aResponseText)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDOMWorkerXHR::SetResponseType(const nsAString& aResponseText)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute jsval response; */
NS_IMETHODIMP
nsDOMWorkerXHR::GetResponse(JSContext *aCx, jsval *aResult)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -0,0 +1,172 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHR_H__
#define __NSDOMWORKERXHR_H__
// Bases
#include "nsIClassInfo.h"
#include "nsIXMLHttpRequest.h"
#include "nsIXPCScriptable.h"
// Other includes
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
// DOMWorker includes
#include "nsDOMWorker.h"
#include "nsDOMWorkerMacros.h"
#include "nsDOMWorkerXHRProxy.h"
// Convenience defines for event *indexes* in the sListenerTypes array.
#define LISTENER_TYPE_ABORT 0
#define LISTENER_TYPE_ERROR 1
#define LISTENER_TYPE_LOAD 2
#define LISTENER_TYPE_LOADSTART 3
#define LISTENER_TYPE_PROGRESS 4
#define LISTENER_TYPE_READYSTATECHANGE 5
#define LISTENER_TYPE_LOADEND 6
class nsIXPConnectWrappedNative;
class nsDOMWorkerXHREventTarget : public nsDOMWorkerMessageHandler,
public nsIXMLHttpRequestEventTarget
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
static const char* const sListenerTypes[];
static const PRUint32 sMaxXHREventTypes;
static const PRUint32 sMaxUploadEventTypes;
static PRUint32 GetListenerTypeFromString(const nsAString& aString);
protected:
virtual ~nsDOMWorkerXHREventTarget() { }
};
class nsDOMWorkerXHRUpload;
class nsDOMWorkerXHR : public nsDOMWorkerFeature,
public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequest,
public nsIXPCScriptable
{
typedef mozilla::Mutex Mutex;
friend class nsDOMWorkerXHREvent;
friend class nsDOMWorkerXHRLastProgressOrLoadEvent;
friend class nsDOMWorkerXHRProxy;
friend class nsDOMWorkerXHRUpload;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIXMLHTTPREQUEST
NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(nsDOMWorkerXHREventTarget::)
NS_DECL_NSICLASSINFO_GETINTERFACES
NS_DECL_NSIXPCSCRIPTABLE
nsDOMWorkerXHR(nsDOMWorker* aWorker);
nsresult Init();
virtual void Cancel();
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
private:
virtual ~nsDOMWorkerXHR();
Mutex& GetLock() {
return mWorker->GetLock();
}
already_AddRefed<nsIXPConnectWrappedNative> GetWrappedNative() {
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative(mWrappedNative);
return wrappedNative.forget();
}
nsRefPtr<nsDOMWorkerXHRProxy> mXHRProxy;
nsRefPtr<nsDOMWorkerXHRUpload> mUpload;
nsIXPConnectWrappedNative* mWrappedNative;
volatile PRBool mCanceled;
};
class nsDOMWorkerXHRUpload : public nsDOMWorkerXHREventTarget,
public nsIXMLHttpRequestUpload
{
friend class nsDOMWorkerXHR;
public:
NS_DECL_ISUPPORTS_INHERITED
// nsIDOMEventHandler
NS_FORWARD_INTERNAL_NSIDOMEVENTTARGET(nsDOMWorkerMessageHandler::)
NS_IMETHOD AddEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture,
PRBool aWantsUntrusted,
PRUint8 optional_argc);
NS_IMETHOD RemoveEventListener(const nsAString& aType,
nsIDOMEventListener* aListener,
PRBool aUseCapture);
NS_IMETHOD DispatchEvent(nsIDOMEvent* aEvent,
PRBool* _retval);
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsDOMWorkerXHREventTarget::)
NS_DECL_NSIXMLHTTPREQUESTUPLOAD
NS_FORWARD_NSICLASSINFO_NOGETINTERFACES(nsDOMWorkerXHREventTarget::)
NS_DECL_NSICLASSINFO_GETINTERFACES
nsDOMWorkerXHRUpload(nsDOMWorkerXHR* aWorkerXHR);
virtual nsresult SetOnXListener(const nsAString& aType,
nsIDOMEventListener* aListener);
protected:
virtual ~nsDOMWorkerXHRUpload() { }
nsRefPtr<nsDOMWorkerXHR> mWorkerXHR;
};
#endif /* __NSDOMWORKERXHR_H__ */

View File

@ -0,0 +1,182 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__
#define MAKE_PROXIED_FUNCTION0(_name) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (); \
} \
return NS_OK; \
} \
}
#define MAKE_PROXIED_FUNCTION1(_name, _arg1) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
_name (_arg1 aArg1) : mArg1(aArg1) { } \
\
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1); \
} \
return NS_OK; \
} \
private: \
_arg1 mArg1; \
}
#define MAKE_PROXIED_FUNCTION2(_name, _arg1, _arg2) \
class _name : public SyncEventCapturingRunnable \
{ \
public: \
_name (_arg1 aArg1, _arg2 aArg2) : mArg1(aArg1), mArg2(aArg2) { } \
\
virtual nsresult RunInternal() \
{ \
nsCOMPtr<nsIXMLHttpRequest> xhr = mXHR->GetXMLHttpRequest(); \
if (xhr) { \
return xhr-> _name (mArg1, mArg2); \
} \
return NS_OK; \
} \
private: \
_arg1 mArg1; \
_arg2 mArg2; \
}
namespace nsDOMWorkerProxiedXHRFunctions
{
typedef nsDOMWorkerXHRProxy::SyncEventQueue SyncEventQueue;
class SyncEventCapturingRunnable : public nsRunnable
{
public:
SyncEventCapturingRunnable()
: mXHR(nsnull), mQueue(nsnull) { }
void Init(nsDOMWorkerXHRProxy* aXHR,
SyncEventQueue* aQueue) {
NS_ASSERTION(aXHR, "Null pointer!");
NS_ASSERTION(aQueue, "Null pointer!");
mXHR = aXHR;
mQueue = aQueue;
}
virtual nsresult RunInternal() = 0;
NS_IMETHOD Run() {
NS_ASSERTION(mXHR && mQueue, "Forgot to call Init!");
SyncEventQueue* oldQueue = mXHR->SetSyncEventQueue(mQueue);
nsresult rv = RunInternal();
mXHR->SetSyncEventQueue(oldQueue);
return rv;
}
protected:
nsRefPtr<nsDOMWorkerXHRProxy> mXHR;
SyncEventQueue* mQueue;
};
class Abort : public SyncEventCapturingRunnable
{
public:
virtual nsresult RunInternal() {
return mXHR->Abort();
}
};
class Open : public SyncEventCapturingRunnable
{
public:
Open(const nsACString& aMethod, const nsACString& aUrl,
PRBool aAsync, const nsAString& aUser,
const nsAString& aPassword)
: mMethod(aMethod), mUrl(aUrl), mAsync(aAsync), mUser(aUser),
mPassword(aPassword) { }
virtual nsresult RunInternal() {
return mXHR->Open(mMethod, mUrl, mAsync, mUser, mPassword);
}
private:
nsCString mMethod;
nsCString mUrl;
PRBool mAsync;
nsString mUser;
nsString mPassword;
};
MAKE_PROXIED_FUNCTION1(GetAllResponseHeaders, char**);
MAKE_PROXIED_FUNCTION2(GetResponseHeader, const nsACString&, nsACString&);
MAKE_PROXIED_FUNCTION1(Send, nsIVariant*);
MAKE_PROXIED_FUNCTION1(SendAsBinary, const nsAString&);
MAKE_PROXIED_FUNCTION2(SetRequestHeader, const nsACString&,
const nsACString&);
MAKE_PROXIED_FUNCTION1(OverrideMimeType, const nsACString&);
MAKE_PROXIED_FUNCTION1(SetMultipart, PRBool);
MAKE_PROXIED_FUNCTION1(GetMultipart, PRBool*);
MAKE_PROXIED_FUNCTION1(GetWithCredentials, PRBool*);
MAKE_PROXIED_FUNCTION1(SetWithCredentials, PRBool);
}
#endif /* __NSDOMWORKERXHRPROXIEDFUNCTIONS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,198 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is worker threads.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NSDOMWORKERXHRPROXY_H__
#define __NSDOMWORKERXHRPROXY_H__
// Bases
#include "nsThreadUtils.h"
#include "nsIDOMEventListener.h"
#include "nsIRequestObserver.h"
// Other includes
#include "nsIDOMEventTarget.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
class nsIJSXMLHttpRequest;
class nsIThread;
class nsIVariant;
class nsIXMLHttpRequest;
class nsIXMLHttpRequestUpload;
class nsIXPConnectWrappedNative;
class nsDOMWorkerXHR;
class nsDOMWorkerXHREvent;
class nsDOMWorkerXHRFinishSyncXHRRunnable;
class nsDOMWorkerXHRState;
class nsDOMWorkerXHRWrappedListener;
class nsXMLHttpRequest;
class nsDOMWorkerXHRProxy : public nsIRunnable,
public nsIDOMEventListener,
public nsIRequestObserver
{
friend class nsDOMWorkerXHRAttachUploadListenersRunnable;
friend class nsDOMWorkerXHREvent;
friend class nsDOMWorkerXHRFinishSyncXHRRunnable;
friend class nsDOMWorkerXHRLastProgressOrLoadEvent;
friend class nsDOMWorkerXHR;
friend class nsDOMWorkerXHRUpload;
public:
typedef nsAutoTArray<nsCOMPtr<nsIRunnable>, 5> SyncEventQueue;
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIREQUESTOBSERVER
nsDOMWorkerXHRProxy(nsDOMWorkerXHR* aWorkerXHR);
virtual ~nsDOMWorkerXHRProxy();
nsresult Init();
nsIXMLHttpRequest* GetXMLHttpRequest();
nsresult Open(const nsACString& aMethod,
const nsACString& aUrl,
PRBool aAsync,
const nsAString& aUser,
const nsAString& aPassword);
nsresult Abort();
SyncEventQueue* SetSyncEventQueue(SyncEventQueue* aQueue);
PRInt32 ChannelID() {
return mChannelID;
}
protected:
struct ProgressInfo {
ProgressInfo() : computable(PR_FALSE), loaded(0), total(0) { }
PRBool computable;
PRUint64 loaded;
PRUint64 total;
};
nsresult InitInternal();
void DestroyInternal();
nsresult Destroy();
void AddRemoveXHRListeners(PRBool aAdd);
void FlipOwnership();
nsresult UploadEventListenerAdded();
nsresult HandleWorkerEvent(nsDOMWorkerXHREvent* aEvent,
PRBool aUploadEvent);
nsresult HandleEventRunnable(nsIRunnable* aRunnable);
// Methods of nsIXMLHttpRequest that we implement
nsresult GetAllResponseHeaders(char** _retval);
nsresult GetResponseHeader(const nsACString& aHeader,
nsACString& _retval);
nsresult Send(nsIVariant* aBody);
nsresult SendAsBinary(const nsAString& aBody);
nsresult GetResponseText(nsAString& _retval);
nsresult GetStatusText(nsACString& _retval);
nsresult GetStatus(nsresult* _retval);
nsresult GetReadyState(PRUint16* _retval);
nsresult SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue);
nsresult OverrideMimeType(const nsACString& aMimetype);
nsresult GetMultipart(PRBool* aMultipart);
nsresult SetMultipart(PRBool aMultipart);
nsresult GetWithCredentials(PRBool* aWithCredentials);
nsresult SetWithCredentials(PRBool aWithCredentials);
nsresult RunSyncEventLoop();
PRBool IsUploadEvent(nsIDOMEvent* aEvent);
nsresult DispatchPrematureAbortEvents(PRUint32 aType,
nsIDOMEventTarget* aTarget,
ProgressInfo* aProgressInfo);
nsresult MaybeDispatchPrematureAbortEvents(PRBool aFromOpenRequest);
// May be weak or strong, check mOwnedByXHR.
nsDOMWorkerXHR* mWorkerXHR;
nsCOMPtr<nsIXPConnectWrappedNative> mWorkerXHRWN;
// May be weak or strong, check mOwnedByXHR.
nsIXMLHttpRequest* mXHR;
// Always weak!
nsXMLHttpRequest* mConcreteXHR;
nsIXMLHttpRequestUpload* mUpload;
nsCOMPtr<nsIThread> mMainThread;
nsRefPtr<nsDOMWorkerXHRState> mLastXHRState;
nsRefPtr<nsDOMWorkerXHREvent> mLastProgressOrLoadEvent;
SyncEventQueue* mSyncEventQueue;
PRInt32 mChannelID;
// Only touched on the worker thread!
nsCOMPtr<nsIThread> mSyncXHRThread;
// Touched on more than one thread, protected by the worker's lock.
nsRefPtr<nsDOMWorkerXHRFinishSyncXHRRunnable> mSyncFinishedRunnable;
nsAutoPtr<ProgressInfo> mDownloadProgressInfo;
nsAutoPtr<ProgressInfo> mUploadProgressInfo;
// Whether or not this object is owned by the real XHR object.
PRPackedBool mOwnedByXHR;
PRPackedBool mWantUploadListeners;
PRPackedBool mCanceled;
PRPackedBool mSyncRequest;
};
#endif /* __NSDOMWORKERXHRPROXY_H__ */

Some files were not shown because too many files have changed in this diff Show More