mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
73ef0db47a
@ -141,6 +141,8 @@ struct MaiAtkObjectClass
|
||||
|
||||
static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
|
||||
|
||||
static void MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName);
|
||||
|
||||
G_BEGIN_DECLS
|
||||
/* callbacks for MaiAtkObject */
|
||||
static void classInitCB(AtkObjectClass *aClass);
|
||||
@ -600,16 +602,41 @@ getNameCB(AtkObject* aAtkObj)
|
||||
if (!accWrap)
|
||||
return nullptr;
|
||||
|
||||
nsAutoString uniName;
|
||||
accWrap->Name(uniName);
|
||||
nsAutoString name;
|
||||
accWrap->Name(name);
|
||||
|
||||
NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
|
||||
if (!uniName.Equals(objName))
|
||||
atk_object_set_name(aAtkObj, NS_ConvertUTF16toUTF8(uniName).get());
|
||||
// XXX Firing an event from here does not seem right
|
||||
MaybeFireNameChange(aAtkObj, name);
|
||||
|
||||
return aAtkObj->name;
|
||||
}
|
||||
|
||||
static void
|
||||
MaybeFireNameChange(AtkObject* aAtkObj, const nsString& aNewName)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 newNameUTF8(aNewName);
|
||||
if (aAtkObj->name && newNameUTF8.Equals(aAtkObj->name))
|
||||
return;
|
||||
|
||||
// Below we duplicate the functionality of atk_object_set_name(),
|
||||
// but without calling atk_object_get_name(). Instead of
|
||||
// atk_object_get_name() we directly access aAtkObj->name. This is because
|
||||
// atk_object_get_name() would call getNameCB() which would call
|
||||
// MaybeFireNameChange() (or atk_object_set_name() before this problem was
|
||||
// fixed) and we would get an infinite recursion.
|
||||
// See http://bugzilla.mozilla.org/733712
|
||||
|
||||
// Do not notify for initial name setting.
|
||||
// See bug http://bugzilla.gnome.org/665870
|
||||
bool notify = !!aAtkObj->name;
|
||||
|
||||
free(aAtkObj->name);
|
||||
aAtkObj->name = strdup(newNameUTF8.get());
|
||||
|
||||
if (notify)
|
||||
g_object_notify(G_OBJECT(aAtkObj), "accessible-name");
|
||||
}
|
||||
|
||||
const gchar *
|
||||
getDescriptionCB(AtkObject *aAtkObj)
|
||||
{
|
||||
@ -617,7 +644,7 @@ getDescriptionCB(AtkObject *aAtkObj)
|
||||
if (!accWrap || accWrap->IsDefunct())
|
||||
return nullptr;
|
||||
|
||||
/* nsIAccessible is responsible for the non-nullptr description */
|
||||
/* nsIAccessible is responsible for the nonnull description */
|
||||
nsAutoString uniDesc;
|
||||
accWrap->Description(uniDesc);
|
||||
|
||||
@ -975,9 +1002,8 @@ AccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
|
||||
{
|
||||
nsAutoString newName;
|
||||
accessible->Name(newName);
|
||||
NS_ConvertUTF16toUTF8 utf8Name(newName);
|
||||
if (!atkObj->name || !utf8Name.Equals(atkObj->name))
|
||||
atk_object_set_name(atkObj, utf8Name.get());
|
||||
|
||||
MaybeFireNameChange(atkObj, newName);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ UpdatePrompt.prototype = {
|
||||
// for the user to press Later or Install Now. In this situation we
|
||||
// don't want to clear this._update, becuase handleApplyPromptResult
|
||||
// needs it.
|
||||
if (this._applyPromptTimer == null) {
|
||||
if (this._applyPromptTimer == null && !this._waitingForIdle) {
|
||||
this._update = null;
|
||||
}
|
||||
break;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[{
|
||||
"size": 634920651,
|
||||
"digest": "731237d9fcd51637e1fdb7240f57d11f1bda18770025186c06ff72e960551c764bada3c43bae2347f716acd36492c2f4e6bb8eddd9ced7198cbcd8c994ea0705",
|
||||
"size": 647503948,
|
||||
"digest": "9ba4f195052e0d5eaae734375aed52f52b7b3337fa8caf01a61830529266e282be19697095c88135379c984d7242ec36b384cf81155176bb6527e6621f32eed3",
|
||||
"algorithm": "sha512",
|
||||
"filename": "emulator.zip"
|
||||
}]
|
||||
|
@ -640,8 +640,17 @@ toolbarbutton[type="badged"] {
|
||||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#toolbarbutton-badged");
|
||||
}
|
||||
|
||||
/* Note the chatbox 'width' values are duplicated in socialchat.xml */
|
||||
chatbox {
|
||||
-moz-binding: url("chrome://browser/content/socialchat.xml#chatbox");
|
||||
transition: height 150ms ease-out, width 150ms ease-out;
|
||||
height: 285px;
|
||||
width: 260px; /* CHAT_WIDTH_OPEN in socialchat.xml */
|
||||
}
|
||||
|
||||
chatbox[minimized="true"] {
|
||||
width: 160px;
|
||||
height: 20px; /* CHAT_WIDTH_MINIMIZED in socialchat.xml */
|
||||
}
|
||||
|
||||
chatbar {
|
||||
|
@ -63,7 +63,8 @@
|
||||
return this.getAttribute("minimized") == "true";
|
||||
</getter>
|
||||
<setter><![CDATA[
|
||||
this.isActive = !val;
|
||||
// Note that this.isActive is set via our transitionend handler so
|
||||
// the content doesn't see intermediate values.
|
||||
let parent = this.parentNode;
|
||||
if (val) {
|
||||
this.setAttribute("minimized", "true");
|
||||
@ -144,6 +145,10 @@
|
||||
this.setAttribute('image', uri.spec);
|
||||
this.parentNode.updateTitlebar(this);
|
||||
]]></handler>
|
||||
<handler event="transitionend">
|
||||
if (this.isActive == this.minimized)
|
||||
this.isActive = !this.minimized;
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
@ -160,9 +165,7 @@
|
||||
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<constructor>
|
||||
// to avoid reflows we cache the values for various widths.
|
||||
this.cachedWidthOpen = 0;
|
||||
this.cachedWidthMinimized = 0;
|
||||
// to avoid reflows we cache the width of the nub.
|
||||
this.cachedWidthNub = 0;
|
||||
this._selectedChat = null;
|
||||
</constructor>
|
||||
@ -326,25 +329,11 @@
|
||||
<method name="getTotalChildWidth">
|
||||
<parameter name="aChatbox"/>
|
||||
<body><![CDATA[
|
||||
// gets the width of a child, using/setting the cached value for
|
||||
// children of this type.
|
||||
// DOES NOT take collapsed into account - ie, this is the width
|
||||
// of a child assuming it is *not* collapsed. (collapsed chats
|
||||
// have a width of zero as they are not shown).
|
||||
if (aChatbox.minimized) {
|
||||
if (!this.cachedWidthMinimized) {
|
||||
if (aChatbox.collapsed)
|
||||
throw new Error("can't calculate size of collapsed chat!");
|
||||
this.cachedWidthMinimized = this.calcTotalWidthOf(aChatbox);
|
||||
}
|
||||
return this.cachedWidthMinimized;
|
||||
}
|
||||
if (!this.cachedWidthOpen) {
|
||||
if (aChatbox.collapsed)
|
||||
throw new Error("can't calculate size of collapsed chat!");
|
||||
this.cachedWidthOpen = this.calcTotalWidthOf(aChatbox);
|
||||
}
|
||||
return this.cachedWidthOpen;
|
||||
// These are from the CSS for the chatbox and must be kept in sync.
|
||||
// We can't use calcTotalWidthOf due to the transitions...
|
||||
const CHAT_WIDTH_OPEN = 260;
|
||||
const CHAT_WIDTH_MINIMIZED = 160;
|
||||
return aChatbox.minimized ? CHAT_WIDTH_MINIMIZED : CHAT_WIDTH_OPEN;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
@ -58,13 +58,21 @@ function testNavigation() {
|
||||
Task.spawn(function () {
|
||||
yield FullZoomHelper.load(gTab1, TEST_VIDEO);
|
||||
FullZoomHelper.zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded");
|
||||
yield waitForNextTurn(); // trying to fix orange bug 806046
|
||||
yield FullZoomHelper.navigate(FullZoomHelper.BACK);
|
||||
FullZoomHelper.zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded");
|
||||
yield waitForNextTurn(); // trying to fix orange bug 806046
|
||||
yield FullZoomHelper.navigate(FullZoomHelper.FORWARD);
|
||||
FullZoomHelper.zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video");
|
||||
}).then(finishTest, FullZoomHelper.failAndContinue(finish));
|
||||
}
|
||||
|
||||
function waitForNextTurn() {
|
||||
let deferred = Promise.defer();
|
||||
setTimeout(function () deferred.resolve(), 0);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
var finishTestStarted = false;
|
||||
function finishTest() {
|
||||
Task.spawn(function () {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 48 KiB |
@ -15,8 +15,8 @@
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource:///modules/MigrationUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups",
|
||||
"resource://gre/modules/PlacesBackups.jsm");
|
||||
|
||||
function FirefoxProfileMigrator() { }
|
||||
|
||||
@ -76,7 +76,7 @@ FirefoxProfileMigrator.prototype.getResources = function() {
|
||||
["signons.sqlite", "key3.db"]);
|
||||
let formData = getFileResource(types.FORMDATA, ["formhistory.sqlite"]);
|
||||
let bookmarksBackups = getFileResource(types.OTHERDATA,
|
||||
[PlacesUtils.backups.profileRelativeFolderPath]);
|
||||
[PlacesBackups.profileRelativeFolderPath]);
|
||||
let dictionary = getFileResource(types.OTHERDATA, ["persdict.dat"]);
|
||||
|
||||
return [r for each (r in [places, cookies, passwords, formData,
|
||||
|
@ -32,6 +32,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkHTMLUtils",
|
||||
"resource://gre/modules/BookmarkHTMLUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkJSONUtils",
|
||||
"resource://gre/modules/BookmarkJSONUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "webappsUI",
|
||||
"resource:///modules/webappsUI.jsm");
|
||||
|
||||
@ -59,6 +62,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups",
|
||||
"resource://gre/modules/PlacesBackups.jsm");
|
||||
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
@ -928,10 +935,10 @@ BrowserGlue.prototype = {
|
||||
// from bookmarks.html, we will try to restore from JSON
|
||||
if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
|
||||
// get latest JSON backup
|
||||
var bookmarksBackupFile = PlacesUtils.backups.getMostRecent("json");
|
||||
var bookmarksBackupFile = PlacesBackups.getMostRecent("json");
|
||||
if (bookmarksBackupFile) {
|
||||
// restore from JSON backup
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(bookmarksBackupFile);
|
||||
yield BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true);
|
||||
importBookmarks = false;
|
||||
}
|
||||
else {
|
||||
@ -1031,6 +1038,8 @@ BrowserGlue.prototype = {
|
||||
this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
|
||||
this._isIdleObserver = true;
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "places-browser-init-complete", "");
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
@ -1097,12 +1106,12 @@ BrowserGlue.prototype = {
|
||||
* @return true if bookmarks should be backed up, false if not.
|
||||
*/
|
||||
_shouldBackupBookmarks: function BG__shouldBackupBookmarks() {
|
||||
let lastBackupFile = PlacesUtils.backups.getMostRecent();
|
||||
let lastBackupFile = PlacesBackups.getMostRecent();
|
||||
|
||||
// Should backup bookmarks if there are no backups or the maximum interval between
|
||||
// backups elapsed.
|
||||
return (!lastBackupFile ||
|
||||
new Date() - PlacesUtils.backups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL);
|
||||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1118,7 +1127,7 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
catch(ex) { /* Use default. */ }
|
||||
|
||||
yield PlacesUtils.backups.create(maxBackups); // Don't force creation.
|
||||
yield PlacesBackups.create(maxBackups); // Don't force creation.
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -3,7 +3,14 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource:///modules/MigrationUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BookmarkJSONUtils",
|
||||
"resource://gre/modules/BookmarkJSONUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups",
|
||||
"resource://gre/modules/PlacesBackups.jsm");
|
||||
|
||||
var PlacesOrganizer = {
|
||||
_places: null,
|
||||
@ -360,13 +367,13 @@ var PlacesOrganizer = {
|
||||
while (restorePopup.childNodes.length > 1)
|
||||
restorePopup.removeChild(restorePopup.firstChild);
|
||||
|
||||
let backupFiles = PlacesUtils.backups.entries;
|
||||
let backupFiles = PlacesBackups.entries;
|
||||
if (backupFiles.length == 0)
|
||||
return;
|
||||
|
||||
// Populate menu with backups.
|
||||
for (let i = 0; i < backupFiles.length; i++) {
|
||||
let backupDate = PlacesUtils.backups.getDateForFile(backupFiles[i]);
|
||||
let backupDate = PlacesBackups.getDateForFile(backupFiles[i]);
|
||||
let m = restorePopup.insertBefore(document.createElement("menuitem"),
|
||||
document.getElementById("restoreFromFile"));
|
||||
m.setAttribute("label",
|
||||
@ -390,7 +397,7 @@ var PlacesOrganizer = {
|
||||
*/
|
||||
onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) {
|
||||
let backupName = aMenuItem.getAttribute("value");
|
||||
let backupFiles = PlacesUtils.backups.entries;
|
||||
let backupFiles = PlacesBackups.entries;
|
||||
for (let i = 0; i < backupFiles.length; i++) {
|
||||
if (backupFiles[i].leafName == backupName) {
|
||||
this.restoreBookmarksFromFile(backupFiles[i]);
|
||||
@ -441,12 +448,13 @@ var PlacesOrganizer = {
|
||||
PlacesUIUtils.getString("bookmarksRestoreAlert")))
|
||||
return;
|
||||
|
||||
try {
|
||||
PlacesUtils.restoreBookmarksFromJSONFile(aFile);
|
||||
}
|
||||
catch(ex) {
|
||||
this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
|
||||
}
|
||||
Task.spawn(function() {
|
||||
try {
|
||||
yield BookmarkJSONUtils.importFromFile(aFile, true);
|
||||
} catch(ex) {
|
||||
PlacesOrganizer._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_showErrorAlert: function PO__showErrorAlert(aMsg) {
|
||||
@ -478,7 +486,7 @@ var PlacesOrganizer = {
|
||||
Ci.nsIFilePicker.modeSave);
|
||||
fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
|
||||
PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
|
||||
fp.defaultString = PlacesUtils.backups.getFilenameForDate();
|
||||
fp.defaultString = PlacesBackups.getFilenameForDate();
|
||||
fp.displayDirectory = backupsDir;
|
||||
fp.open(fpCallback);
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ function waitForImportAndSmartBookmarks(aCallback) {
|
||||
// Wait for Places init notification.
|
||||
Services.obs.addObserver(function(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee,
|
||||
PlacesUtils.TOPIC_INIT_COMPLETE);
|
||||
"places-browser-init-complete");
|
||||
do_execute_soon(function () {
|
||||
// Ensure preferences status.
|
||||
do_check_false(Services.prefs.getBoolPref(PREF_AUTO_EXPORT_HTML));
|
||||
@ -58,7 +58,7 @@ function waitForImportAndSmartBookmarks(aCallback) {
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
}, PlacesUtils.TOPIC_INIT_COMPLETE, false);
|
||||
}, "places-browser-init-complete", false);
|
||||
},
|
||||
|
||||
function test_import()
|
||||
|
@ -128,15 +128,8 @@ chatbar {
|
||||
}
|
||||
|
||||
chatbox {
|
||||
height: 285px;
|
||||
width: 260px;
|
||||
-moz-margin-start: 4px;
|
||||
background-color: white;
|
||||
border: 1px solid #ccc;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
chatbox[minimized="true"] {
|
||||
width: 160px;
|
||||
height: 20px;
|
||||
}
|
||||
|
@ -805,7 +805,13 @@ public:
|
||||
* See nsIDOMEventTarget
|
||||
*/
|
||||
NS_DECL_NSIDOMEVENTTARGET
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
using nsIDOMEventTarget::AddEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
using nsIDOMEventTarget::AddSystemEventListener;
|
||||
|
||||
/**
|
||||
|
@ -591,9 +591,17 @@ static nsSize GetScrollRectSizeForOverflowVisibleFrame(nsIFrame* aFrame)
|
||||
|
||||
nsRect paddingRect = aFrame->GetPaddingRectRelativeToSelf();
|
||||
nsOverflowAreas overflowAreas(paddingRect, paddingRect);
|
||||
// Add the scrollable overflow areas of children (if any) to the paddingRect.
|
||||
// It's important to start with the paddingRect, otherwise if there are no
|
||||
// children the overflow rect will be 0,0,0,0 which will force the point 0,0
|
||||
// to be included in the final rect.
|
||||
nsLayoutUtils::UnionChildOverflow(aFrame, overflowAreas);
|
||||
// Make sure that an empty padding-rect's edges are included, by adding
|
||||
// the padding-rect in again with UnionEdges.
|
||||
nsRect overflowRect =
|
||||
overflowAreas.ScrollableOverflow().UnionEdges(paddingRect);
|
||||
return nsLayoutUtils::GetScrolledRect(aFrame,
|
||||
overflowAreas.ScrollableOverflow(), paddingRect.Size(),
|
||||
overflowRect, paddingRect.Size(),
|
||||
aFrame->StyleVisibility()->mDirection).Size();
|
||||
}
|
||||
|
||||
|
@ -1153,6 +1153,20 @@ WebSocket::RemoveEventListener(const nsAString& aType,
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener,
|
||||
aUseCapture, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocket::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
@ -1172,6 +1186,20 @@ WebSocket::AddEventListener(const nsAString& aType,
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
WebSocket::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
|
||||
nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture,
|
||||
aWantsUntrusted, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// WebSocket - methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -77,9 +77,18 @@ public:
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted,
|
||||
uint8_t optional_argc);
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
NS_IMETHOD RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture);
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DisconnectFromOwner();
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
nsDOMCaretPosition::nsDOMCaretPosition(nsINode* aNode, uint32_t aOffset)
|
||||
: mOffset(aOffset), mOffsetNode(aNode)
|
||||
: mOffset(aOffset), mOffsetNode(aNode), mAnonymousContentNode(nullptr)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
@ -21,6 +21,37 @@ nsINode* nsDOMCaretPosition::GetOffsetNode() const
|
||||
return mOffsetNode;
|
||||
}
|
||||
|
||||
already_AddRefed<nsClientRect>
|
||||
nsDOMCaretPosition::GetClientRect() const
|
||||
{
|
||||
if (!mOffsetNode) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<nsClientRect> rect;
|
||||
nsRefPtr<nsRange> domRange;
|
||||
nsCOMPtr<nsINode> node;
|
||||
|
||||
if (mAnonymousContentNode) {
|
||||
node = mAnonymousContentNode;
|
||||
} else {
|
||||
node = mOffsetNode;
|
||||
}
|
||||
|
||||
nsresult creationRv = nsRange::CreateRange(node, mOffset, node,
|
||||
mOffset,
|
||||
getter_AddRefs<nsRange>(domRange));
|
||||
if (!NS_SUCCEEDED(creationRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ASSERTION(domRange, "unable to retrieve valid dom range from CaretPosition");
|
||||
|
||||
rect = domRange->GetBoundingClientRect();
|
||||
|
||||
return rect.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDOMCaretPosition::WrapObject(JSContext *aCx, JSObject *aScope)
|
||||
{
|
||||
|
@ -8,7 +8,10 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsRange.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsClientRect.h"
|
||||
|
||||
/**
|
||||
* Implementation of a DOM Caret Position, which is a node and offset within
|
||||
@ -46,6 +49,32 @@ public:
|
||||
*/
|
||||
nsINode* GetOffsetNode() const;
|
||||
|
||||
/**
|
||||
* Retrieve the bounding rectangle of this CaretPosition object.
|
||||
*
|
||||
* @returns An nsClientRect representing the bounding rectangle of this
|
||||
* CaretPosition, if one can be successfully determined, otherwise
|
||||
* nullptr.
|
||||
*/
|
||||
already_AddRefed<nsClientRect> GetClientRect() const;
|
||||
|
||||
/**
|
||||
* Set the anonymous content node that is the actual parent of this
|
||||
* CaretPosition object. In situations where the DOM node for a CaretPosition
|
||||
* actually lies within an anonymous content node (e.g. a textarea), the
|
||||
* actual parent is not set as the offset node. This is used to get the
|
||||
* correct bounding box of a CaretPosition object that lies within a textarea
|
||||
* or input element.
|
||||
*
|
||||
* @param aNode A pointer to an nsINode object that is the actual element
|
||||
* within which this CaretPosition lies, but is an anonymous content
|
||||
* node.
|
||||
*/
|
||||
void SetAnonymousContentNode(nsINode* aNode)
|
||||
{
|
||||
mAnonymousContentNode = aNode;
|
||||
}
|
||||
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return GetOffsetNode();
|
||||
@ -56,8 +85,10 @@ public:
|
||||
|
||||
protected:
|
||||
virtual ~nsDOMCaretPosition();
|
||||
|
||||
uint32_t mOffset;
|
||||
nsCOMPtr<nsINode> mOffsetNode;
|
||||
nsCOMPtr<nsINode> mAnonymousContentNode;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -62,6 +62,7 @@ public:
|
||||
// Don't call us anymore! Likely isn't an issue (or maybe just less of
|
||||
// one) once we block GC until all the (appropriate) onXxxx handlers
|
||||
// are dropped. (See WebRTC spec)
|
||||
LOG(("Close()ing %p", mDataChannel.get()));
|
||||
mDataChannel->SetListener(nullptr, nullptr);
|
||||
mDataChannel->Close();
|
||||
}
|
||||
@ -71,7 +72,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMDATACHANNEL
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDataChannel,
|
||||
nsDOMEventTargetHelper)
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
|
||||
NS_DECL_NSIDOMFILEREADER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
|
@ -1852,6 +1852,13 @@ nsDocument::Init()
|
||||
mRadioGroups.Init();
|
||||
mCustomPrototypes.Init();
|
||||
|
||||
// If after creation the owner js global is not set for a document
|
||||
// we use the default compartment for this document, instead of creating
|
||||
// wrapper in some random compartment when the document is exposed to js
|
||||
// via some events.
|
||||
mScopeObject = do_GetWeakReference(xpc::GetNativeForGlobal(xpc::GetJunkScope()));
|
||||
MOZ_ASSERT(mScopeObject);
|
||||
|
||||
// Force initialization.
|
||||
nsINode::nsSlots* slots = Slots();
|
||||
|
||||
@ -3758,7 +3765,7 @@ nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
|
||||
nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
|
||||
|
||||
if (!mStyleSheets.RemoveObject(aSheet)) {
|
||||
NS_NOTREACHED("stylesheet not found");
|
||||
NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -9323,6 +9330,13 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
||||
if (textArea || (input &&
|
||||
NS_SUCCEEDED(input->MozIsTextField(false, &isText)) &&
|
||||
isText)) {
|
||||
// If the anonymous content node has a child, then we need to make sure
|
||||
// that we get the appropriate child, as otherwise the offset may not be
|
||||
// correct when we construct a range for it.
|
||||
nsCOMPtr<nsIContent> firstChild = anonNode->GetFirstChild();
|
||||
if (firstChild) {
|
||||
anonNode = firstChild;
|
||||
}
|
||||
offset = nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame, offset);
|
||||
node = nonanon;
|
||||
} else {
|
||||
@ -9332,6 +9346,9 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMCaretPosition> aCaretPos = new nsDOMCaretPosition(node, offset);
|
||||
if (nodeIsAnonymous) {
|
||||
aCaretPos->SetAnonymousContentNode(anonNode);
|
||||
}
|
||||
return aCaretPos.forget();
|
||||
}
|
||||
|
||||
|
@ -1044,6 +1044,29 @@ nsINode::AddEventListener(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsINode::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool wantsUntrusted;
|
||||
if (aWantsUntrusted.IsNull()) {
|
||||
wantsUntrusted = !nsContentUtils::IsChromeDoc(OwnerDoc());
|
||||
} else {
|
||||
wantsUntrusted = aWantsUntrusted.Value();
|
||||
}
|
||||
|
||||
nsEventListenerManager* listener_manager = GetListenerManager(true);
|
||||
if (!listener_manager) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
listener_manager->AddEventListener(aType, aListener, aUseCapture,
|
||||
wantsUntrusted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsINode::AddSystemEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
aWantsUntrusted,
|
||||
optional_argc);
|
||||
}
|
||||
using nsDOMEventTargetHelper::AddEventListener;
|
||||
|
||||
virtual nsIScriptObjectPrincipal* GetObjectPrincipal() { return this; }
|
||||
virtual JSContext* GetJSContextForEventHandlers() { return mCx; }
|
||||
|
@ -211,6 +211,22 @@ nsRange::~nsRange()
|
||||
DoSetRange(nullptr, 0, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
|
||||
nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
|
||||
|
||||
nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
|
||||
aRange);
|
||||
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
|
@ -65,6 +65,9 @@ public:
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
nsIDOMRange** aRange);
|
||||
static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
nsRange** aRange);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsRange, nsIDOMRange)
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXHREventTarget,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_DECL_NSIXMLHTTPREQUESTEVENTTARGET
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
IMPL_EVENT_HANDLER(loadstart)
|
||||
IMPL_EVENT_HANDLER(progress)
|
||||
@ -91,7 +91,7 @@ public:
|
||||
}
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_FORWARD_NSIXMLHTTPREQUESTEVENTTARGET(nsXHREventTarget::)
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget)
|
||||
NS_DECL_NSIXMLHTTPREQUESTUPLOAD
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *cx, JSObject *scope) MOZ_OVERRIDE
|
||||
@ -226,7 +226,7 @@ public:
|
||||
virtual size_t
|
||||
SizeOfEventTargetIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsXHREventTarget)
|
||||
|
||||
#ifdef DEBUG
|
||||
void StaticAssertions();
|
||||
|
@ -17,6 +17,8 @@ class nsDOMEvent;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class EventListener;
|
||||
|
||||
// IID for the dom::EventTarget interface
|
||||
#define NS_EVENTTARGET_IID \
|
||||
{ 0x0a5aed21, 0x0bab, 0x48b3, \
|
||||
@ -32,21 +34,15 @@ public:
|
||||
using nsIDOMEventTarget::AddEventListener;
|
||||
using nsIDOMEventTarget::RemoveEventListener;
|
||||
using nsIDOMEventTarget::DispatchEvent;
|
||||
void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aCallback, // XXX nullable
|
||||
bool aCapture, const Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv)
|
||||
{
|
||||
aRv = AddEventListener(aType, aCallback, aCapture,
|
||||
!aWantsUntrusted.IsNull() && aWantsUntrusted.Value(),
|
||||
aWantsUntrusted.IsNull() ? 1 : 2);
|
||||
}
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aCallback,
|
||||
bool aCapture, mozilla::ErrorResult& aRv)
|
||||
{
|
||||
aRv = RemoveEventListener(aType, aCallback, aCapture);
|
||||
}
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aCallback,
|
||||
bool aCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) = 0;
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aCallback,
|
||||
bool aCapture,
|
||||
ErrorResult& aRv);
|
||||
bool DispatchEvent(nsDOMEvent& aEvent, ErrorResult& aRv);
|
||||
};
|
||||
|
||||
|
26
content/events/src/EventTarget.cpp
Normal file
26
content/events/src/EventTarget.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "nsEventListenerManager.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
EventTarget::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsEventListenerManager* elm = GetListenerManager(false);
|
||||
if (elm) {
|
||||
elm->RemoveEventListener(aType, aListener, aUseCapture);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -15,6 +15,7 @@ LIBXUL_LIBRARY = 1
|
||||
FAIL_ON_WARNINGS = 1
|
||||
|
||||
CPPSRCS = \
|
||||
EventTarget.cpp \
|
||||
nsEventListenerManager.cpp \
|
||||
nsEventStateManager.cpp \
|
||||
nsDOMEvent.cpp \
|
||||
|
@ -192,6 +192,36 @@ nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMEventTargetHelper::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool wantsUntrusted;
|
||||
if (aWantsUntrusted.IsNull()) {
|
||||
nsresult rv;
|
||||
nsIScriptContext* context = GetContextForEventHandlers(&rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
nsContentUtils::GetDocumentFromScriptContext(context);
|
||||
wantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc);
|
||||
} else {
|
||||
wantsUntrusted = aWantsUntrusted.Value();
|
||||
}
|
||||
|
||||
nsEventListenerManager* elm = GetListenerManager(true);
|
||||
if (!elm) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
|
@ -31,6 +31,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsDOMEventTargetHelper)
|
||||
|
||||
NS_DECL_NSIDOMEVENTTARGET
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aCapture,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMEVENTTARGETHELPER_IID)
|
||||
|
||||
@ -205,6 +211,11 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEventTargetHelper,
|
||||
} \
|
||||
virtual JSContext * GetJSContextForEventHandlers(void) { \
|
||||
return _to GetJSContextForEventHandlers(); \
|
||||
}
|
||||
}
|
||||
|
||||
#define NS_REALLY_FORWARD_NSIDOMEVENTTARGET(_class) \
|
||||
using _class::AddEventListener; \
|
||||
using _class::RemoveEventListener; \
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(_class::)
|
||||
|
||||
#endif // nsDOMEventTargetHelper_h_
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "nsSandboxFlags.h"
|
||||
#include "mozilla/dom/time/TimeChangeObserver.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
@ -159,7 +160,8 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
const char* aName,
|
||||
unsigned aFlags)
|
||||
{
|
||||
CycleCollectionNoteChild(aCallback, aField.mListener.get(), aName, aFlags);
|
||||
CycleCollectionNoteChild(aCallback, aField.mListener.GetISupports(), aName,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEventListenerManager)
|
||||
@ -199,7 +201,7 @@ nsEventListenerManager::GetTargetAsInnerWindow() const
|
||||
|
||||
void
|
||||
nsEventListenerManager::AddEventListenerInternal(
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aTypeAtom,
|
||||
const EventListenerFlags& aFlags,
|
||||
@ -212,7 +214,9 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = aListener;
|
||||
// Since there is no public API to call us with an EventListenerHolder, we
|
||||
// know that there's an EventListenerHolder on the stack holding a strong ref
|
||||
// to the listener.
|
||||
|
||||
nsListenerStruct* ls;
|
||||
uint32_t count = mListeners.Length();
|
||||
@ -241,8 +245,11 @@ nsEventListenerManager::AddEventListenerInternal(
|
||||
// Detect the type of event listener.
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wjs;
|
||||
if (aFlags.mListenerIsJSListener) {
|
||||
MOZ_ASSERT(!aListener.HasWebIDLCallback());
|
||||
ls->mListenerType = eJSEventListener;
|
||||
} else if ((wjs = do_QueryInterface(aListener))) {
|
||||
} else if (aListener.HasWebIDLCallback()) {
|
||||
ls->mListenerType = eWebIDLListener;
|
||||
} else if ((wjs = do_QueryInterface(aListener.GetXPCOMCallback()))) {
|
||||
ls->mListenerType = eWrappedJSListener;
|
||||
} else {
|
||||
ls->mListenerType = eNativeListener;
|
||||
@ -425,7 +432,7 @@ nsEventListenerManager::DisableDevice(uint32_t aType)
|
||||
|
||||
void
|
||||
nsEventListenerManager::RemoveEventListenerInternal(
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aUserType,
|
||||
const EventListenerFlags& aFlags,
|
||||
@ -499,7 +506,7 @@ ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
|
||||
}
|
||||
|
||||
void
|
||||
nsEventListenerManager::AddEventListenerByType(nsIDOMEventListener *aListener,
|
||||
nsEventListenerManager::AddEventListenerByType(const EventListenerHolder& aListener,
|
||||
const nsAString& aType,
|
||||
const EventListenerFlags& aFlags)
|
||||
{
|
||||
@ -510,7 +517,7 @@ nsEventListenerManager::AddEventListenerByType(nsIDOMEventListener *aListener,
|
||||
|
||||
void
|
||||
nsEventListenerManager::RemoveEventListenerByType(
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
const nsAString& aType,
|
||||
const EventListenerFlags& aFlags)
|
||||
{
|
||||
@ -563,7 +570,8 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
aHandler, getter_AddRefs(scriptListener));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AddEventListenerInternal(scriptListener, eventType, aName, flags, true);
|
||||
EventListenerHolder holder(scriptListener);
|
||||
AddEventListenerInternal(holder, eventType, aName, flags, true);
|
||||
|
||||
ls = FindEventHandler(eventType, aName);
|
||||
}
|
||||
@ -906,7 +914,7 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
nsIDOMEvent* aDOMEvent,
|
||||
EventTarget* aCurrentTarget,
|
||||
nsCxPusher* aPusher)
|
||||
@ -927,7 +935,14 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
nsAutoMicroTask mt;
|
||||
// nsIDOMEvent::currentTarget is set in nsEventDispatcher.
|
||||
result = aListener->HandleEvent(aDOMEvent);
|
||||
if (aListener.HasWebIDLCallback()) {
|
||||
ErrorResult rv;
|
||||
aListener.GetWebIDLCallback()->
|
||||
HandleEvent(aCurrentTarget, *(aDOMEvent->InternalDOMEvent()), rv);
|
||||
result = rv.ErrorCode();
|
||||
} else {
|
||||
result = aListener.GetXPCOMCallback()->HandleEvent(aDOMEvent);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -996,7 +1011,7 @@ nsEventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
continue;
|
||||
}
|
||||
|
||||
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener;
|
||||
EventListenerHolder kungFuDeathGrip(ls->mListener);
|
||||
if (NS_FAILED(HandleEventSubType(ls, ls->mListener, *aDOMEvent,
|
||||
aCurrentTarget, aPusher))) {
|
||||
aEvent->mFlags.mExceptionHasBeenRisen = true;
|
||||
@ -1027,7 +1042,7 @@ nsEventListenerManager::Disconnect()
|
||||
|
||||
void
|
||||
nsEventListenerManager::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted)
|
||||
{
|
||||
@ -1039,7 +1054,7 @@ nsEventListenerManager::AddEventListener(const nsAString& aType,
|
||||
|
||||
void
|
||||
nsEventListenerManager::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
const EventListenerHolder& aListener,
|
||||
bool aUseCapture)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
@ -1057,7 +1072,8 @@ nsEventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aListener,
|
||||
flags.mCapture = aUseCapture;
|
||||
flags.mAllowUntrustedEvents = aWantsUntrusted;
|
||||
flags.mInSystemGroup = aSystemEventGroup;
|
||||
AddEventListenerInternal(aListener, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
EventListenerHolder holder(aListener);
|
||||
AddEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
false, true);
|
||||
}
|
||||
|
||||
@ -1069,7 +1085,8 @@ nsEventListenerManager::RemoveListenerForAllEvents(nsIDOMEventListener* aListene
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture = aUseCapture;
|
||||
flags.mInSystemGroup = aSystemEventGroup;
|
||||
RemoveEventListenerInternal(aListener, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
EventListenerHolder holder(aListener);
|
||||
RemoveEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
|
||||
true);
|
||||
}
|
||||
|
||||
@ -1159,8 +1176,11 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
|
||||
}
|
||||
const nsDependentSubstring& eventType =
|
||||
Substring(nsDependentAtomString(ls.mTypeAtom), 2);
|
||||
// EventListenerInfo is defined in XPCOM, so we have to go ahead
|
||||
// and convert to an XPCOM callback here...
|
||||
nsRefPtr<nsEventListenerInfo> info =
|
||||
new nsEventListenerInfo(eventType, ls.mListener, ls.mFlags.mCapture,
|
||||
new nsEventListenerInfo(eventType, ls.mListener.ToXPCOMCallback(),
|
||||
ls.mFlags.mCapture,
|
||||
ls.mFlags.mAllowUntrustedEvents,
|
||||
ls.mFlags.mInSystemGroup);
|
||||
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -1285,7 +1305,10 @@ nsEventListenerManager::MarkForCC()
|
||||
}
|
||||
xpc_UnmarkGrayObject(jsl->GetEventScope());
|
||||
} else if (ls.mListenerType == eWrappedJSListener) {
|
||||
xpc_TryUnmarkWrappedGrayObject(ls.mListener);
|
||||
xpc_TryUnmarkWrappedGrayObject(ls.mListener.GetXPCOMCallback());
|
||||
} else if (ls.mListenerType == eWebIDLListener) {
|
||||
// Callback() unmarks gray
|
||||
ls.mListener.GetWebIDLCallback()->Callback();
|
||||
}
|
||||
}
|
||||
if (mRefCnt.IsPurple()) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIJSEventListener.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "mozilla/dom/EventListenerBinding.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
class nsIAtom;
|
||||
@ -35,6 +36,9 @@ class nsEventListenerManager;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
typedef CallbackObjectHolder<EventListener, nsIDOMEventListener>
|
||||
EventListenerHolder;
|
||||
|
||||
struct EventListenerFlags
|
||||
{
|
||||
friend struct ::nsListenerStruct;
|
||||
@ -149,12 +153,14 @@ typedef enum
|
||||
{
|
||||
eNativeListener = 0,
|
||||
eJSEventListener,
|
||||
eWrappedJSListener
|
||||
eWrappedJSListener,
|
||||
eWebIDLListener,
|
||||
eListenerTypeCount
|
||||
} nsListenerType;
|
||||
|
||||
struct nsListenerStruct
|
||||
{
|
||||
nsRefPtr<nsIDOMEventListener> mListener;
|
||||
mozilla::dom::EventListenerHolder mListener;
|
||||
nsCOMPtr<nsIAtom> mTypeAtom;
|
||||
uint32_t mEventType;
|
||||
uint8_t mListenerType;
|
||||
@ -166,13 +172,19 @@ struct nsListenerStruct
|
||||
|
||||
nsIJSEventListener* GetJSListener() const {
|
||||
return (mListenerType == eJSEventListener) ?
|
||||
static_cast<nsIJSEventListener *>(mListener.get()) : nullptr;
|
||||
static_cast<nsIJSEventListener *>(mListener.GetXPCOMCallback()) : nullptr;
|
||||
}
|
||||
|
||||
nsListenerStruct()
|
||||
{
|
||||
MOZ_ASSERT(sizeof(mListenerType) == 1);
|
||||
MOZ_ASSERT(eListenerTypeCount < 255);
|
||||
}
|
||||
|
||||
~nsListenerStruct()
|
||||
{
|
||||
if ((mListenerType == eJSEventListener) && mListener) {
|
||||
static_cast<nsIJSEventListener*>(mListener.get())->Disconnect();
|
||||
static_cast<nsIJSEventListener*>(mListener.GetXPCOMCallback())->Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,10 +219,33 @@ public:
|
||||
void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted);
|
||||
bool aWantsUntrusted)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
|
||||
}
|
||||
void AddEventListener(const nsAString& aType,
|
||||
mozilla::dom::EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
|
||||
}
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture);
|
||||
bool aUseCapture)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
RemoveEventListener(aType, holder, aUseCapture);
|
||||
}
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
mozilla::dom::EventListener* aListener,
|
||||
bool aUseCapture)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
RemoveEventListener(aType, holder, aUseCapture);
|
||||
}
|
||||
|
||||
void AddListenerForAllEvents(nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
@ -225,9 +260,23 @@ public:
|
||||
* @param an event listener
|
||||
*/
|
||||
void AddEventListenerByType(nsIDOMEventListener *aListener,
|
||||
const nsAString& type,
|
||||
const mozilla::dom::EventListenerFlags& aFlags)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
AddEventListenerByType(holder, type, aFlags);
|
||||
}
|
||||
void AddEventListenerByType(const mozilla::dom::EventListenerHolder& aListener,
|
||||
const nsAString& type,
|
||||
const mozilla::dom::EventListenerFlags& aFlags);
|
||||
void RemoveEventListenerByType(nsIDOMEventListener *aListener,
|
||||
const nsAString& type,
|
||||
const mozilla::dom::EventListenerFlags& aFlags)
|
||||
{
|
||||
mozilla::dom::EventListenerHolder holder(aListener);
|
||||
RemoveEventListenerByType(holder, type, aFlags);
|
||||
}
|
||||
void RemoveEventListenerByType(const mozilla::dom::EventListenerHolder& aListener,
|
||||
const nsAString& type,
|
||||
const mozilla::dom::EventListenerFlags& aFlags);
|
||||
|
||||
@ -364,7 +413,7 @@ protected:
|
||||
nsCxPusher* aPusher);
|
||||
|
||||
nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
|
||||
nsIDOMEventListener* aListener,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
nsIDOMEvent* aDOMEvent,
|
||||
mozilla::dom::EventTarget* aCurrentTarget,
|
||||
nsCxPusher* aPusher);
|
||||
@ -445,15 +494,23 @@ protected:
|
||||
*/
|
||||
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName);
|
||||
|
||||
void AddEventListener(const nsAString& aType,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted);
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
bool aUseCapture);
|
||||
|
||||
void AddEventListenerInternal(
|
||||
nsIDOMEventListener* aListener,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aTypeAtom,
|
||||
const mozilla::dom::EventListenerFlags& aFlags,
|
||||
bool aHandler = false,
|
||||
bool aAllEvents = false);
|
||||
void RemoveEventListenerInternal(
|
||||
nsIDOMEventListener* aListener,
|
||||
const mozilla::dom::EventListenerHolder& aListener,
|
||||
uint32_t aType,
|
||||
nsIAtom* aUserType,
|
||||
const mozilla::dom::EventListenerFlags& aFlags,
|
||||
|
@ -18,7 +18,8 @@
|
||||
class nsEventListenerInfo : public nsIEventListenerInfo
|
||||
{
|
||||
public:
|
||||
nsEventListenerInfo(const nsAString& aType, nsIDOMEventListener* aListener,
|
||||
nsEventListenerInfo(const nsAString& aType,
|
||||
already_AddRefed<nsIDOMEventListener> aListener,
|
||||
bool aCapturing, bool aAllowsUntrusted,
|
||||
bool aInSystemEventGroup)
|
||||
: mType(aType), mListener(aListener), mCapturing(aCapturing),
|
||||
|
@ -6,6 +6,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=328885
|
||||
<head>
|
||||
<title>Test for Bug 328885</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
@ -29,7 +30,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=328885
|
||||
}
|
||||
|
||||
function clickTest() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
inputelement.addEventListener("DOMSubtreeModified", mutationListener, false);
|
||||
inputelement.addEventListener("DOMNodeInserted", mutationListener, false);
|
||||
inputelement.addEventListener("DOMNodeRemoved", mutationListener, false);
|
||||
@ -39,10 +39,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=328885
|
||||
inputelement.addEventListener("DOMCharacterDataModified", mutationListener, false);
|
||||
|
||||
inputelement.addEventListener('click',
|
||||
function(evt) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
ok(evt.originalTarget instanceof HTMLDivElement, "(1) Wrong originalTarget!");
|
||||
ok(evt.originalTarget.parentNode == inputelement, "(2) Wront parent node!");
|
||||
function(event) {
|
||||
var evt = SpecialPowers.wrap(event);
|
||||
ok(SpecialPowers.unwrap(evt.originalTarget) instanceof HTMLDivElement,
|
||||
"(1) Wrong originalTarget!");
|
||||
is(SpecialPowers.unwrap(evt.originalTarget.parentNode), inputelement,
|
||||
"(2) Wront parent node!");
|
||||
ok(mutationCount == 0, "(3) No mutations should have happened! [" + mutationCount + "]");
|
||||
evt.originalTarget.textContent = "foo";
|
||||
ok(mutationCount == 0, "(4) Mutation listener shouldn't have been called! [" + mutationCount + "]");
|
||||
@ -51,14 +53,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=328885
|
||||
evt.originalTarget.lastChild.data = "bar";
|
||||
ok(mutationCount == 0, "(6) Mutation listener shouldn't have been called! [" + mutationCount + "]");
|
||||
|
||||
var r = document.createRange();
|
||||
var r = SpecialPowers.wrap(document.createRange());
|
||||
r.selectNodeContents(evt.originalTarget);
|
||||
r.deleteContents();
|
||||
ok(mutationCount == 0, "(7) Mutation listener shouldn't have been called! [" + mutationCount + "]");
|
||||
|
||||
evt.originalTarget.textContent = "foo";
|
||||
ok(mutationCount == 0, "(8) Mutation listener shouldn't have been called! [" + mutationCount + "]");
|
||||
r = document.createRange();
|
||||
r = SpecialPowers.wrap(document.createRange());
|
||||
r.selectNodeContents(evt.originalTarget);
|
||||
r.extractContents();
|
||||
ok(mutationCount == 0, "(9) Mutation listener shouldn't have been called! [" + mutationCount + "]");
|
||||
@ -111,10 +113,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=328885
|
||||
ok(mutationCount == 19, "(20) Mutation listener should have been called! ["+ mutationCount + "]");
|
||||
}
|
||||
,false);
|
||||
var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
|
||||
utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
|
||||
synthesizeMouseAtPoint(5, 5, {}, window);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ MOCHITEST_FILES = \
|
||||
test_input_attributes_reflection.html \
|
||||
test_input_list_attribute.html \
|
||||
test_input_email.html \
|
||||
test_input_range_attr_order.html \
|
||||
test_input_range_key_events.html \
|
||||
test_input_range_mouse_and_touch_events.html \
|
||||
test_input_url.html \
|
||||
|
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=841941
|
||||
-->
|
||||
<head>
|
||||
<title>Test @min/@max/@step order for range</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841941">Mozilla Bug 841941</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input type=range value=2 max=1.5 step=0.5>
|
||||
<input type=range value=2 step=0.5 max=1.5>
|
||||
<input type=range value=2 max=1.5 step=0.5>
|
||||
<input type=range value=2 step=0.5 max=1.5>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/**
|
||||
* Test for Bug 841941
|
||||
* This test checks that the order in which @min/@max/@step are specified in
|
||||
* markup makes no difference to the value that <input type=range> will be
|
||||
* given. Basically this checks that sanitization of the value does not occur
|
||||
* until after the parser has finished with the element.
|
||||
*/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
test();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function test() {
|
||||
var ranges = document.querySelectorAll("input[type=range]");
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
is(ranges.item(i).value, "1.5", "Check sanitization order for range " + i);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
20
content/media/AudioStreamTrack.cpp
Normal file
20
content/media/AudioStreamTrack.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AudioStreamTrack.h"
|
||||
|
||||
#include "mozilla/dom/AudioStreamTrackBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
JSObject*
|
||||
AudioStreamTrack::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return AudioStreamTrackBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
30
content/media/AudioStreamTrack.h
Normal file
30
content/media/AudioStreamTrack.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef AUDIOSTREAMTRACK_H_
|
||||
#define AUDIOSTREAMTRACK_H_
|
||||
|
||||
#include "MediaStreamTrack.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AudioStreamTrack : public MediaStreamTrack {
|
||||
public:
|
||||
AudioStreamTrack(DOMMediaStream* aStream, TrackID aTrackID)
|
||||
: MediaStreamTrack(aStream, aTrackID) {}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
|
||||
|
||||
virtual AudioStreamTrack* AsAudioStreamTrack() { return this; }
|
||||
|
||||
// WebIDL
|
||||
virtual void GetKind(nsAString& aKind) { aKind.AssignLiteral("audio"); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* AUDIOSTREAMTRACK_H_ */
|
@ -9,8 +9,11 @@
|
||||
#include "mozilla/dom/MediaStreamBinding.h"
|
||||
#include "mozilla/dom/LocalMediaStreamBinding.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AudioStreamTrack.h"
|
||||
#include "VideoStreamTrack.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
@ -20,13 +23,95 @@ NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMMediaStream)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMMediaStream)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMMediaStream, mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(DOMMediaStream, mWindow, mTracks)
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(DOMLocalMediaStream, DOMMediaStream,
|
||||
nsIDOMLocalMediaStream)
|
||||
|
||||
class DOMMediaStream::StreamListener : public MediaStreamListener {
|
||||
public:
|
||||
StreamListener(DOMMediaStream* aStream)
|
||||
: mStream(aStream)
|
||||
{}
|
||||
|
||||
// Main thread only
|
||||
void Forget() { mStream = nullptr; }
|
||||
DOMMediaStream* GetStream() { return mStream; }
|
||||
|
||||
class TrackChange : public nsRunnable {
|
||||
public:
|
||||
TrackChange(StreamListener* aListener,
|
||||
TrackID aID, TrackTicks aTrackOffset,
|
||||
uint32_t aEvents, MediaSegment::Type aType)
|
||||
: mListener(aListener), mID(aID), mEvents(aEvents), mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "main thread only");
|
||||
|
||||
DOMMediaStream* stream = mListener->GetStream();
|
||||
if (!stream) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaStreamTrack> track;
|
||||
if (mEvents & MediaStreamListener::TRACK_EVENT_CREATED) {
|
||||
track = stream->CreateDOMTrack(mID, mType);
|
||||
} else {
|
||||
track = stream->GetDOMTrackFor(mID);
|
||||
}
|
||||
if (mEvents & MediaStreamListener::TRACK_EVENT_ENDED) {
|
||||
track->NotifyEnded();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
StreamTime mEndTime;
|
||||
nsRefPtr<StreamListener> mListener;
|
||||
TrackID mID;
|
||||
uint32_t mEvents;
|
||||
MediaSegment::Type mType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify that changes to one of the stream tracks have been queued.
|
||||
* aTrackEvents can be any combination of TRACK_EVENT_CREATED and
|
||||
* TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
|
||||
* at aTrackOffset (relative to the start of the stream).
|
||||
* aQueuedMedia can be null if there is no output.
|
||||
*/
|
||||
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
|
||||
TrackRate aTrackRate,
|
||||
TrackTicks aTrackOffset,
|
||||
uint32_t aTrackEvents,
|
||||
const MediaSegment& aQueuedMedia)
|
||||
{
|
||||
if (aTrackEvents & (TRACK_EVENT_CREATED | TRACK_EVENT_ENDED)) {
|
||||
nsRefPtr<TrackChange> runnable =
|
||||
new TrackChange(this, aID, aTrackOffset, aTrackEvents,
|
||||
aQueuedMedia.GetType());
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// These fields may only be accessed on the main thread
|
||||
DOMMediaStream* mStream;
|
||||
};
|
||||
|
||||
DOMMediaStream::DOMMediaStream()
|
||||
: mStream(nullptr), mHintContents(0)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
DOMMediaStream::~DOMMediaStream()
|
||||
{
|
||||
if (mListener) {
|
||||
mListener->Forget();
|
||||
}
|
||||
if (mStream) {
|
||||
mStream->Destroy();
|
||||
}
|
||||
@ -44,6 +129,28 @@ DOMMediaStream::CurrentTime()
|
||||
return mStream ? MediaTimeToSeconds(mStream->GetCurrentTime()) : 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks)
|
||||
{
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
AudioStreamTrack* t = mTracks[i]->AsAudioStreamTrack();
|
||||
if (t) {
|
||||
aTracks.AppendElement(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks)
|
||||
{
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
VideoStreamTrack* t = mTracks[i]->AsVideoStreamTrack();
|
||||
if (t) {
|
||||
aTracks.AppendElement(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DOMMediaStream::IsFinished()
|
||||
{
|
||||
@ -56,7 +163,7 @@ DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents)
|
||||
mWindow = aWindow;
|
||||
SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
mStream = gm->CreateSourceStream(this);
|
||||
InitStreamCommon(gm->CreateSourceStream(this));
|
||||
}
|
||||
|
||||
void
|
||||
@ -65,7 +172,17 @@ DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintConten
|
||||
mWindow = aWindow;
|
||||
SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
mStream = gm->CreateTrackUnionStream(this);
|
||||
InitStreamCommon(gm->CreateTrackUnionStream(this));
|
||||
}
|
||||
|
||||
void
|
||||
DOMMediaStream::InitStreamCommon(MediaStream* aStream)
|
||||
{
|
||||
mStream = aStream;
|
||||
|
||||
// Setup track listener
|
||||
mListener = new StreamListener(this);
|
||||
aStream->AddListener(mListener);
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
@ -90,6 +207,40 @@ DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
|
||||
return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
|
||||
}
|
||||
|
||||
MediaStreamTrack*
|
||||
DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
|
||||
{
|
||||
MediaStreamTrack* track;
|
||||
switch (aType) {
|
||||
case MediaSegment::AUDIO:
|
||||
track = new AudioStreamTrack(this, aTrackID);
|
||||
break;
|
||||
case MediaSegment::VIDEO:
|
||||
track = new VideoStreamTrack(this, aTrackID);
|
||||
break;
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unhandled track type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mTracks.AppendElement(track);
|
||||
return track;
|
||||
}
|
||||
|
||||
MediaStreamTrack*
|
||||
DOMMediaStream::GetDOMTrackFor(TrackID aTrackID)
|
||||
{
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
MediaStreamTrack* t = mTracks[i];
|
||||
// We may add streams to our track list that are actually owned by
|
||||
// a different DOMMediaStream. Ignore those.
|
||||
if (t->GetTrackID() == aTrackID && t->GetStream() == this) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DOMLocalMediaStream::~DOMLocalMediaStream()
|
||||
{
|
||||
if (mStream) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
class nsXPCClassInfo;
|
||||
|
||||
@ -30,6 +31,12 @@ namespace mozilla {
|
||||
|
||||
class MediaStream;
|
||||
|
||||
namespace dom {
|
||||
class MediaStreamTrack;
|
||||
class AudioStreamTrack;
|
||||
class VideoStreamTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM wrapper for MediaStreams.
|
||||
*/
|
||||
@ -37,12 +44,12 @@ class DOMMediaStream : public nsIDOMMediaStream,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class DOMLocalMediaStream;
|
||||
typedef dom::MediaStreamTrack MediaStreamTrack;
|
||||
typedef dom::AudioStreamTrack AudioStreamTrack;
|
||||
typedef dom::VideoStreamTrack VideoStreamTrack;
|
||||
|
||||
public:
|
||||
DOMMediaStream() : mStream(nullptr), mHintContents(0)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
DOMMediaStream();
|
||||
virtual ~DOMMediaStream();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMMediaStream)
|
||||
@ -54,7 +61,11 @@ public:
|
||||
}
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
|
||||
|
||||
// WebIDL
|
||||
double CurrentTime();
|
||||
void GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks);
|
||||
void GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks);
|
||||
|
||||
MediaStream* GetStream() { return mStream; }
|
||||
bool IsFinished();
|
||||
/**
|
||||
@ -92,9 +103,17 @@ public:
|
||||
static already_AddRefed<DOMMediaStream>
|
||||
CreateTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents = 0);
|
||||
|
||||
// Notifications from StreamListener
|
||||
MediaStreamTrack* CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType);
|
||||
MediaStreamTrack* GetDOMTrackFor(TrackID aTrackID);
|
||||
|
||||
protected:
|
||||
void InitSourceStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
|
||||
void InitTrackUnionStream(nsIDOMWindow* aWindow, uint32_t aHintContents);
|
||||
void InitStreamCommon(MediaStream* aStream);
|
||||
|
||||
class StreamListener;
|
||||
friend class StreamListener;
|
||||
|
||||
// We need this to track our parent object.
|
||||
nsCOMPtr<nsIDOMWindow> mWindow;
|
||||
@ -106,6 +125,9 @@ protected:
|
||||
// If null, this stream can be used by anyone because it has no content yet.
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
nsAutoTArray<nsRefPtr<MediaStreamTrack>,2> mTracks;
|
||||
nsRefPtr<StreamListener> mListener;
|
||||
|
||||
// tells the SDP generator about whether this
|
||||
// MediaStream probably has audio and/or video
|
||||
uint32_t mHintContents;
|
||||
|
@ -16,24 +16,27 @@ FAIL_ON_WARNINGS := 1
|
||||
endif # !_MSC_VER
|
||||
|
||||
CPPSRCS = \
|
||||
AudioAvailableEventManager.cpp \
|
||||
AudioChannelFormat.cpp \
|
||||
AudioNodeEngine.cpp \
|
||||
AudioNodeStream.cpp \
|
||||
AudioSegment.cpp \
|
||||
AudioStream.cpp \
|
||||
AudioStreamTrack.cpp \
|
||||
DecoderTraits.cpp \
|
||||
DOMMediaStream.cpp \
|
||||
FileBlockCache.cpp \
|
||||
MediaResource.cpp \
|
||||
MediaStreamGraph.cpp \
|
||||
AudioAvailableEventManager.cpp \
|
||||
MediaCache.cpp \
|
||||
MediaDecoder.cpp \
|
||||
MediaDecoderStateMachine.cpp \
|
||||
MediaDecoderReader.cpp \
|
||||
MediaCache.cpp \
|
||||
MediaResource.cpp \
|
||||
MediaStreamGraph.cpp \
|
||||
MediaStreamTrack.cpp \
|
||||
StreamBuffer.cpp \
|
||||
VideoFrameContainer.cpp \
|
||||
VideoSegment.cpp \
|
||||
VideoStreamTrack.cpp \
|
||||
VideoUtils.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
51
content/media/MediaStreamTrack.cpp
Normal file
51
content/media/MediaStreamTrack.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaStreamTrack.h"
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID)
|
||||
: mStream(aStream), mTrackID(aTrackID), mEnded(false)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
|
||||
memset(&mID, 0, sizeof(mID));
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
if (uuidgen) {
|
||||
uuidgen->GenerateUUIDInPlace(&mID);
|
||||
}
|
||||
}
|
||||
|
||||
MediaStreamTrack::~MediaStreamTrack()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(MediaStreamTrack, nsDOMEventTargetHelper,
|
||||
mStream)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, nsDOMEventTargetHelper)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamTrack)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
void
|
||||
MediaStreamTrack::GetId(nsAString& aID)
|
||||
{
|
||||
char chars[NSID_LENGTH];
|
||||
mID.ToProvidedString(chars);
|
||||
aID = NS_ConvertASCIItoUTF16(chars);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
63
content/media/MediaStreamTrack.h
Normal file
63
content/media/MediaStreamTrack.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MEDIASTREAMTRACK_H_
|
||||
#define MEDIASTREAMTRACK_H_
|
||||
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsID.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class DOMMediaStream;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AudioStreamTrack;
|
||||
class VideoStreamTrack;
|
||||
|
||||
/**
|
||||
* Class representing a track in a DOMMediaStream.
|
||||
*/
|
||||
class MediaStreamTrack : public nsDOMEventTargetHelper {
|
||||
public:
|
||||
/**
|
||||
* aTrackID is the MediaStreamGraph track ID for the track in the
|
||||
* MediaStream owned by aStream.
|
||||
*/
|
||||
MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID);
|
||||
virtual ~MediaStreamTrack();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack, nsDOMEventTargetHelper)
|
||||
|
||||
DOMMediaStream* GetParentObject() const { return mStream; }
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) = 0;
|
||||
|
||||
DOMMediaStream* GetStream() const { return mStream; }
|
||||
TrackID GetTrackID() const { return mTrackID; }
|
||||
virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; }
|
||||
virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; }
|
||||
|
||||
// WebIDL
|
||||
virtual void GetKind(nsAString& aKind) = 0;
|
||||
void GetId(nsAString& aID);
|
||||
void GetLabel(nsAString& aLabel) { aLabel.Truncate(); }
|
||||
|
||||
// Notifications from the MediaStreamGraph
|
||||
void NotifyEnded() { mEnded = true; }
|
||||
|
||||
protected:
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
TrackID mTrackID;
|
||||
nsID mID;
|
||||
bool mEnded;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MEDIASTREAMTRACK_H_ */
|
20
content/media/VideoStreamTrack.cpp
Normal file
20
content/media/VideoStreamTrack.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "VideoStreamTrack.h"
|
||||
|
||||
#include "mozilla/dom/VideoStreamTrackBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
JSObject*
|
||||
VideoStreamTrack::WrapObject(JSContext* aCx, JSObject* aScope)
|
||||
{
|
||||
return VideoStreamTrackBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
30
content/media/VideoStreamTrack.h
Normal file
30
content/media/VideoStreamTrack.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef VIDEOSTREAMTRACK_H_
|
||||
#define VIDEOSTREAMTRACK_H_
|
||||
|
||||
#include "MediaStreamTrack.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class VideoStreamTrack : public MediaStreamTrack {
|
||||
public:
|
||||
VideoStreamTrack(DOMMediaStream* aStream, TrackID aTrackID)
|
||||
: MediaStreamTrack(aStream, aTrackID) {}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope);
|
||||
|
||||
virtual VideoStreamTrack* AsVideoStreamTrack() { return this; }
|
||||
|
||||
// WebIDL
|
||||
virtual void GetKind(nsAString& aKind) { aKind.AssignLiteral("video"); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* VIDEOSTREAMTRACK_H_ */
|
@ -74,3 +74,9 @@ EXPORTS += [
|
||||
'VorbisUtils.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'AudioStreamTrack.h',
|
||||
'MediaStreamTrack.h',
|
||||
'VideoStreamTrack.h',
|
||||
]
|
||||
|
||||
|
@ -135,6 +135,7 @@ MOCHITEST_FILES = \
|
||||
test_streams_srcObject.html \
|
||||
test_reset_src.html \
|
||||
test_streams_gc.html \
|
||||
test_streams_tracks.html \
|
||||
test_streams_autoplay.html \
|
||||
$(filter disabled-for-intermittent-failures--bug-608634, test_error_in_video_document.html) \
|
||||
$(NULL)
|
||||
|
@ -62,12 +62,13 @@ var gPausedAfterEndedTests = gSmallTests.concat([
|
||||
{ name:"small-shot.ogg", type:"video/ogg", duration:0.276 }
|
||||
]);
|
||||
|
||||
// Test the mozHasAudio property
|
||||
var gMozHasAudioTests = [
|
||||
{ name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444, hasAudio:undefined },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false },
|
||||
{ name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529, hasAudio:false },
|
||||
// Test the mozHasAudio property, and APIs that detect different kinds of
|
||||
// tracks
|
||||
var gTrackTests = [
|
||||
{ name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444, hasAudio:true, hasVideo:false },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false, hasVideo:true },
|
||||
{ name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true, hasVideo:true },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966, size:215529, hasAudio:false, hasVideo:true },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
];
|
||||
|
||||
|
@ -27,13 +27,13 @@ function startTest(test, token) {
|
||||
|
||||
element.src = test.name;
|
||||
element.name = test.name;
|
||||
element.hasAudio = test.hasAudio;
|
||||
element.hasAudio = elemType == "video" ? test.hasAudio : undefined;
|
||||
element.addEventListener("loadedmetadata", onloadedmetadata, false);
|
||||
|
||||
element.load();
|
||||
}
|
||||
|
||||
manager.runTests(gMozHasAudioTests, startTest);
|
||||
manager.runTests(gTrackTests, startTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
54
content/media/test/test_streams_tracks.html
Normal file
54
content/media/test/test_streams_tracks.html
Normal file
@ -0,0 +1,54 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test MediaStreamTrack interfaces</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function testTracks(tracks, hasTrack, kind, src) {
|
||||
is(tracks.length, hasTrack ? 1 : 0, "Correct track count for " + src);
|
||||
for (var i = 0; i < tracks.length; ++i) {
|
||||
var track = tracks[i];
|
||||
is(track.kind, kind, "Correct track kind for track " + i + " of " + src);
|
||||
var id = track.id;
|
||||
ok(/\{........-....-....-....-............\}/.test(track.id),
|
||||
"id " + track.id + " for track " + i + " of " + src + " has correct form");
|
||||
}
|
||||
}
|
||||
|
||||
function onended(e) {
|
||||
var t = e.target;
|
||||
var audioTracks = t.stream.getAudioTracks();
|
||||
var videoTracks = t.stream.getVideoTracks();
|
||||
|
||||
testTracks(audioTracks, t.test.hasAudio, "audio", t.src);
|
||||
testTracks(videoTracks, t.test.hasVideo, "video", t.src);
|
||||
|
||||
manager.finished(t.token);
|
||||
}
|
||||
|
||||
function startTest(test, token) {
|
||||
var element = document.createElement("video");
|
||||
|
||||
element.token = token;
|
||||
manager.started(token);
|
||||
|
||||
element.src = test.name;
|
||||
element.test = test;
|
||||
element.stream = element.mozCaptureStreamUntilEnded();
|
||||
element.addEventListener("ended", onended, false);
|
||||
|
||||
element.play();
|
||||
}
|
||||
|
||||
manager.runTests(gTrackTests, startTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -35,7 +35,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
|
@ -1517,6 +1517,29 @@ XULDocument::GetHeight(ErrorResult& aRv)
|
||||
return height;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
GetScopeObjectOfNode(nsIDOMNode* node)
|
||||
{
|
||||
MOZ_ASSERT(node, "Must not be called with null.");
|
||||
|
||||
// Window root occasionally keeps alive a node of a document whose
|
||||
// window is already dead. If in this brief period someone calls
|
||||
// GetPopupNode and we return that node, nsNodeSH::PreCreate will throw,
|
||||
// because it will not know which scope this node belongs to. Returning
|
||||
// an orphan node like that to JS would be a bug anyway, so to avoid
|
||||
// this, let's do the same check as nsNodeSH::PreCreate does to
|
||||
// determine the scope and if it fails let's just return null in
|
||||
// XULDocument::GetPopupNode.
|
||||
nsCOMPtr<nsINode> inode = do_QueryInterface(node);
|
||||
MOZ_ASSERT(inode, "How can this happen?");
|
||||
|
||||
nsIDocument* doc = inode->OwnerDoc();
|
||||
MOZ_ASSERT(inode, "This should never happen.");
|
||||
|
||||
nsIGlobalObject* global = doc->GetScopeObject();
|
||||
return global ? global->GetGlobalJSObject() : nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsIDOMXULDocument interface
|
||||
@ -1539,8 +1562,10 @@ XULDocument::GetPopupNode(nsIDOMNode** aNode)
|
||||
}
|
||||
}
|
||||
|
||||
if (node && nsContentUtils::CanCallerAccess(node))
|
||||
node.swap(*aNode);
|
||||
if (node && nsContentUtils::CanCallerAccess(node)
|
||||
&& GetScopeObjectOfNode(node)) {
|
||||
node.swap(*aNode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -239,19 +239,51 @@ DOMRequestService::FireError(nsIDOMDOMRequest* aRequest,
|
||||
|
||||
class FireSuccessAsyncTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
||||
FireSuccessAsyncTask(DOMRequest* aRequest,
|
||||
const JS::Value& aResult) :
|
||||
mReq(aRequest),
|
||||
mResult(aResult)
|
||||
mResult(aResult),
|
||||
mIsSetup(false)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
nsresult
|
||||
Setup()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
nsresult rv;
|
||||
nsIScriptContext* sc = mReq->GetContextForEventHandlers(&rv);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
AutoPushJSContext cx(sc->GetNativeContext());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && cx);
|
||||
if (!cx) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JSAutoRequest ar(cx);
|
||||
JS_AddValueRoot(cx, &mResult);
|
||||
mIsSetup = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Due to the fact that initialization can fail during shutdown (since we
|
||||
// can't fetch a js context), set up an initiatization function to make sure
|
||||
// we can return the failure appropriately
|
||||
static nsresult
|
||||
Dispatch(DOMRequest* aRequest,
|
||||
const JS::Value& aResult)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(aRequest, aResult);
|
||||
nsresult rv = asyncTask->Setup();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
|
||||
NS_WARNING("Failed to dispatch to main thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -264,10 +296,15 @@ public:
|
||||
~FireSuccessAsyncTask()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
if(!mIsSetup) {
|
||||
// If we never set up, no reason to unroot
|
||||
return;
|
||||
}
|
||||
nsresult rv;
|
||||
nsIScriptContext* sc = mReq->GetContextForEventHandlers(&rv);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
AutoPushJSContext cx(sc->GetNativeContext());
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) && cx);
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// We need to build a new request, otherwise we assert since there won't be
|
||||
// a request available yet.
|
||||
@ -277,6 +314,7 @@ public:
|
||||
private:
|
||||
nsRefPtr<DOMRequest> mReq;
|
||||
JS::Value mResult;
|
||||
bool mIsSetup;
|
||||
};
|
||||
|
||||
class FireErrorAsyncTask : public nsRunnable
|
||||
@ -305,13 +343,7 @@ DOMRequestService::FireSuccessAsync(nsIDOMDOMRequest* aRequest,
|
||||
const JS::Value& aResult)
|
||||
{
|
||||
NS_ENSURE_STATE(aRequest);
|
||||
nsCOMPtr<nsIRunnable> asyncTask =
|
||||
new FireSuccessAsyncTask(static_cast<DOMRequest*>(aRequest), aResult);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
|
||||
NS_WARNING("Failed to dispatch to main thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
return FireSuccessAsyncTask::Dispatch(static_cast<DOMRequest*>(aRequest), aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -30,7 +30,7 @@ protected:
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMDOMREQUEST
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
|
@ -5550,18 +5550,6 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
|
||||
// See http://bugzilla.mozilla.org/show_bug.cgi?id=227417
|
||||
nsIDocument* doc = node->OwnerDoc();
|
||||
|
||||
// If we have a document, make sure one of these is true
|
||||
// (1) it has a script handling object,
|
||||
// (2) has had one, or has been marked to have had one,
|
||||
// (3) we are running a privileged script.
|
||||
// Event handling is possible only if (1). If (2) event handling is prevented.
|
||||
// If document has never had a script handling object,
|
||||
// untrusted scripts (3) shouldn't touch it!
|
||||
bool hasHadScriptHandlingObject = false;
|
||||
NS_ENSURE_STATE(doc->GetScriptHandlingObject(hasHadScriptHandlingObject) ||
|
||||
hasHadScriptHandlingObject ||
|
||||
nsContentUtils::IsCallerChrome());
|
||||
|
||||
nsINode *native_parent;
|
||||
|
||||
bool nodeIsElement = node->IsElement();
|
||||
@ -5610,26 +5598,17 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
|
||||
}
|
||||
} else {
|
||||
// We're called for a document object; set the parent to be the
|
||||
// document's global object, if there is one
|
||||
// document's global object
|
||||
|
||||
// Get the scope object from the document.
|
||||
nsISupports *scope = doc->GetScopeObject();
|
||||
// Document should know its global but if the owner window of the
|
||||
// document is already dead at this point, then just throw.
|
||||
nsIGlobalObject* scope = doc->GetScopeObject();
|
||||
NS_ENSURE_TRUE(scope, NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (scope) {
|
||||
jsval v;
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv = WrapNative(cx, globalObj, scope, false, &v,
|
||||
getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
holder->GetJSObject(parentObj);
|
||||
}
|
||||
else {
|
||||
// No global object reachable from this document, use the
|
||||
// global object that was passed to this method.
|
||||
|
||||
*parentObj = globalObj;
|
||||
}
|
||||
*parentObj = scope->GetGlobalJSObject();
|
||||
// Guarding against the case when the native global is still alive
|
||||
// but the JS global is not.
|
||||
NS_ENSURE_TRUE(*parentObj, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// No slim wrappers for a document's scope object.
|
||||
return node->ChromeOnlyAccess() ?
|
||||
|
@ -1018,6 +1018,23 @@ nsFocusManager::FocusPlugin(nsIContent* aContent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsFocusManager::ThemeDisplaysFocusForContent(nsIContent* aContent)
|
||||
{
|
||||
// We don't want to draw the focusring if the element is themed and
|
||||
// the theme displays an indication of focus for the element.
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsPresContext *presContext = frame->PresContext();
|
||||
const nsStyleDisplay *disp = frame->StyleDisplay();
|
||||
if (frame->IsThemed(disp) &&
|
||||
presContext->GetTheme()->ThemeDrawsFocusForWidget(presContext, frame, disp->mAppearance)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
|
||||
@ -1028,7 +1045,9 @@ nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
|
||||
return;
|
||||
}
|
||||
nsEventStates eventState = NS_EVENT_STATE_FOCUS;
|
||||
if (aWindowShouldShowFocusRing) {
|
||||
if (!aGettingFocus ||
|
||||
(aWindowShouldShowFocusRing &&
|
||||
!ThemeDisplaysFocusForContent(aContent))) {
|
||||
eventState |= NS_EVENT_STATE_FOCUSRING;
|
||||
}
|
||||
if (aGettingFocus) {
|
||||
|
@ -116,6 +116,8 @@ public:
|
||||
|
||||
static bool sMouseFocusesFormControl;
|
||||
|
||||
static bool ThemeDisplaysFocusForContent(nsIContent* aContent);
|
||||
|
||||
protected:
|
||||
|
||||
nsFocusManager();
|
||||
|
@ -8018,6 +8018,34 @@ nsGlobalWindow::AddEventListener(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (IsOuterWindow() && mInnerWindow &&
|
||||
!nsContentUtils::CanCallerAccess(mInnerWindow)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
bool wantsUntrusted;
|
||||
if (aWantsUntrusted.IsNull()) {
|
||||
wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
|
||||
} else {
|
||||
wantsUntrusted = aWantsUntrusted.Value();
|
||||
}
|
||||
|
||||
nsEventListenerManager* manager = GetListenerManager(true);
|
||||
if (!manager) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalWindow::AddSystemEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
@ -8435,7 +8463,8 @@ nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
|
||||
oldShouldShowFocusRing != newShouldShowFocusRing &&
|
||||
mFocusedNode->IsElement()) {
|
||||
// Update mFocusedNode's state.
|
||||
if (newShouldShowFocusRing) {
|
||||
if (newShouldShowFocusRing &&
|
||||
!nsFocusManager::ThemeDisplaysFocusForContent(mFocusedNode.get())) {
|
||||
mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
|
||||
} else {
|
||||
mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
|
||||
|
@ -340,6 +340,12 @@ public:
|
||||
|
||||
// nsIDOMEventTarget
|
||||
NS_DECL_NSIDOMEVENTTARGET
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
// nsITouchEventReceiver
|
||||
NS_DECL_NSITOUCHEVENTRECEIVER
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMSCREEN
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsIDOMXULElement.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static NS_DEFINE_CID(kEventListenerManagerCID, NS_EVENTLISTENERMANAGER_CID);
|
||||
@ -110,6 +111,23 @@ nsWindowRoot::AddEventListener(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindowRoot::AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value();
|
||||
nsEventListenerManager* elm = GetListenerManager(true);
|
||||
if (!elm) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowRoot::AddSystemEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
|
@ -27,6 +27,12 @@ public:
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTTARGET
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
// nsPIWindowRoot
|
||||
|
||||
|
@ -126,6 +126,9 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMBeforeUnloadEvent',
|
||||
},
|
||||
|
||||
'AudioStreamTrack': {
|
||||
},
|
||||
|
||||
'BiquadFilterNode': {
|
||||
'resultNotAddRefed': [ 'frequency', 'q', 'gain' ],
|
||||
},
|
||||
@ -553,6 +556,11 @@ DOMInterfaces = {
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'LocalMediaStream': {
|
||||
'headerFile': 'DOMMediaStream.h',
|
||||
'nativeType': 'mozilla::DOMLocalMediaStream'
|
||||
},
|
||||
|
||||
'Location': {
|
||||
# NOTE: Before you turn on codegen for Location, make sure all the
|
||||
# Unforgeable stuff is dealt with.
|
||||
@ -571,11 +579,6 @@ DOMInterfaces = {
|
||||
'skipGen': True
|
||||
}],
|
||||
|
||||
'LocalMediaStream': {
|
||||
'headerFile': 'DOMMediaStream.h',
|
||||
'nativeType': 'mozilla::DOMLocalMediaStream'
|
||||
},
|
||||
|
||||
'MediaStreamList': {
|
||||
'headerFile': 'MediaStreamList.h',
|
||||
'wrapperCache': False,
|
||||
@ -584,6 +587,10 @@ DOMInterfaces = {
|
||||
'binaryNames': { '__indexedGetter': 'IndexedGetter' }
|
||||
},
|
||||
|
||||
'MediaStreamTrack': {
|
||||
'concrete': False
|
||||
},
|
||||
|
||||
'MessageEvent': {
|
||||
'nativeType': 'nsDOMMessageEvent',
|
||||
},
|
||||
@ -1022,6 +1029,9 @@ DOMInterfaces = {
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'VideoStreamTrack': {
|
||||
},
|
||||
|
||||
'WebGLActiveInfo': {
|
||||
'nativeType': 'mozilla::WebGLActiveInfo',
|
||||
'headerFile': 'WebGLContext.h',
|
||||
|
@ -18,6 +18,7 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallbackObject)
|
||||
NS_INTERFACE_MAP_ENTRY(mozilla::dom::CallbackObject)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -184,7 +185,7 @@ CallbackObject::CallSetup::~CallSetup()
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback,
|
||||
const nsIID& aIID)
|
||||
const nsIID& aIID) const
|
||||
{
|
||||
if (!aCallback) {
|
||||
return nullptr;
|
||||
|
@ -34,9 +34,15 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#define DOM_CALLBACKOBJECT_IID \
|
||||
{ 0xbe74c190, 0x6d76, 0x4991, \
|
||||
{ 0x84, 0xb9, 0x65, 0x06, 0x99, 0xe6, 0x93, 0x2b } }
|
||||
|
||||
class CallbackObject : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(DOM_CALLBACKOBJECT_IID)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CallbackObject)
|
||||
|
||||
@ -201,7 +207,7 @@ class CallbackObjectHolderBase
|
||||
protected:
|
||||
// Returns null on all failures
|
||||
already_AddRefed<nsISupports> ToXPCOMCallback(CallbackObject* aCallback,
|
||||
const nsIID& aIID);
|
||||
const nsIID& aIID) const;
|
||||
};
|
||||
|
||||
template<class WebIDLCallbackT, class XPCOMCallbackT>
|
||||
@ -244,11 +250,38 @@ public:
|
||||
UnlinkSelf();
|
||||
}
|
||||
|
||||
void operator=(WebIDLCallbackT* aCallback)
|
||||
{
|
||||
UnlinkSelf();
|
||||
mPtrBits = reinterpret_cast<uintptr_t>(aCallback);
|
||||
NS_IF_ADDREF(aCallback);
|
||||
}
|
||||
|
||||
void operator=(XPCOMCallbackT* aCallback)
|
||||
{
|
||||
UnlinkSelf();
|
||||
mPtrBits = reinterpret_cast<uintptr_t>(aCallback) | XPCOMCallbackFlag;
|
||||
NS_IF_ADDREF(aCallback);
|
||||
}
|
||||
|
||||
void operator=(const CallbackObjectHolder& aOther)
|
||||
{
|
||||
UnlinkSelf();
|
||||
mPtrBits = aOther.mPtrBits;
|
||||
NS_IF_ADDREF(GetISupports());
|
||||
}
|
||||
|
||||
nsISupports* GetISupports() const
|
||||
{
|
||||
return reinterpret_cast<nsISupports*>(mPtrBits & ~XPCOMCallbackFlag);
|
||||
}
|
||||
|
||||
// Boolean conversion operator so people can use this in boolean tests
|
||||
operator bool() const
|
||||
{
|
||||
return GetISupports();
|
||||
}
|
||||
|
||||
// Even if HasWebIDLCallback returns true, GetWebIDLCallback() might still
|
||||
// return null.
|
||||
bool HasWebIDLCallback() const
|
||||
@ -304,7 +337,7 @@ public:
|
||||
}
|
||||
|
||||
// Try to return an XPCOMCallbackT version of this object.
|
||||
already_AddRefed<XPCOMCallbackT> ToXPCOMCallback()
|
||||
already_AddRefed<XPCOMCallbackT> ToXPCOMCallback() const
|
||||
{
|
||||
if (!HasWebIDLCallback()) {
|
||||
nsRefPtr<XPCOMCallbackT> callback = GetXPCOMCallback();
|
||||
@ -319,7 +352,7 @@ public:
|
||||
}
|
||||
|
||||
// Try to return a WebIDLCallbackT version of this object.
|
||||
already_AddRefed<WebIDLCallbackT> ToWebIDLCallback()
|
||||
already_AddRefed<WebIDLCallbackT> ToWebIDLCallback() const
|
||||
{
|
||||
if (HasWebIDLCallback()) {
|
||||
nsRefPtr<WebIDLCallbackT> callback = GetWebIDLCallback();
|
||||
@ -371,6 +404,8 @@ private:
|
||||
uintptr_t mPtrBits;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(CallbackObject, DOM_CALLBACKOBJECT_IID)
|
||||
|
||||
template<class T, class U>
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
|
@ -168,11 +168,11 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
|
||||
|
||||
BluetoothAdapter::~BluetoothAdapter()
|
||||
{
|
||||
Unroot();
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
// We can be null on shutdown, where this might happen
|
||||
NS_ENSURE_TRUE_VOID(bs);
|
||||
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
|
||||
Unroot();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMBLUETOOTHADAPTER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothAdapter,
|
||||
nsDOMEventTargetHelper)
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMBLUETOOTHDEVICE
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothDevice,
|
||||
nsDOMEventTargetHelper)
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMBLUETOOTHMANAGER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
static already_AddRefed<BluetoothManager>
|
||||
Create(nsPIDOMWindow* aWindow);
|
||||
|
@ -123,7 +123,8 @@ BluetoothUnixSocketConnector::SetUp(int aFd)
|
||||
if (mType == BluetoothSocketType::L2CAP ||
|
||||
mType == BluetoothSocketType::EL2CAP) {
|
||||
struct l2cap_options opts;
|
||||
int optlen = sizeof(opts), err;
|
||||
socklen_t optlen = sizeof(opts);
|
||||
int err;
|
||||
err = getsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
|
||||
if (!err) {
|
||||
/* setting MTU for [E]L2CAP */
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
NS_DECL_NSIDOMMOZCELLBROADCAST
|
||||
NS_DECL_NSICELLBROADCASTLISTENER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
CellBroadcast() MOZ_DELETE;
|
||||
CellBroadcast(nsPIDOMWindow *aWindow,
|
||||
|
@ -20,10 +20,16 @@ XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
|
||||
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "pm",
|
||||
"@mozilla.org/permissionmanager;1",
|
||||
"nsIPermissionManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
const CONTACTS_SENDMORE_MINIMUM = 5;
|
||||
|
||||
function stringOrBust(aObj) {
|
||||
if (typeof aObj != "string") {
|
||||
if (DEBUG) debug("Field is not a string and was ignored.");
|
||||
@ -559,6 +565,15 @@ ContactManager.prototype = {
|
||||
access = "unknown";
|
||||
}
|
||||
|
||||
// Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
|
||||
let type = "contacts-" + access;
|
||||
let permValue =
|
||||
pm.testExactPermissionFromPrincipal(this._window.document.nodePrincipal, type);
|
||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
aAllowCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
let requestID = this.getRequestId({
|
||||
request: aRequest,
|
||||
allow: function() {
|
||||
@ -684,6 +699,9 @@ ContactManager.prototype = {
|
||||
if (DEBUG) debug("contact in cache");
|
||||
let contact = data.cachedContacts.shift();
|
||||
this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
|
||||
if (data.cachedContacts.length < CONTACTS_SENDMORE_MINIMUM) {
|
||||
cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) debug("waiting for contact");
|
||||
data.waitingForNext = true;
|
||||
|
@ -23,6 +23,64 @@ const DB_VERSION = 8;
|
||||
const STORE_NAME = "contacts";
|
||||
const SAVED_GETALL_STORE_NAME = "getallcache";
|
||||
const CHUNK_SIZE = 20;
|
||||
const CHUNK_INTERVAL = 500;
|
||||
|
||||
function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher) {
|
||||
this.nextIndex = 0;
|
||||
|
||||
this.cancelTimeout = function() {
|
||||
if (this.interval) {
|
||||
clearTimeout(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (aFullContacts) {
|
||||
this.sendChunk = function() {
|
||||
if (aContacts.length > 0) {
|
||||
aCallback(aContacts.splice(0, CHUNK_SIZE));
|
||||
this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
|
||||
} else {
|
||||
aCallback(null);
|
||||
this.cancelTimeout();
|
||||
aClearDispatcher();
|
||||
}
|
||||
}.bind(this);
|
||||
} else {
|
||||
this.count = 0;
|
||||
this.sendChunk = function() {
|
||||
let chunk = [];
|
||||
aNewTxn("readonly", STORE_NAME, function(txn, store) {
|
||||
for (let i = this.nextIndex; i < Math.min(this.nextIndex+CHUNK_SIZE, aContacts.length); ++i) {
|
||||
store.get(aContacts[i]).onsuccess = function(e) {
|
||||
chunk.push(e.target.result);
|
||||
this.count++;
|
||||
if (this.count == aContacts.length) {
|
||||
aCallback(chunk)
|
||||
aCallback(null);
|
||||
this.cancelTimeout();
|
||||
aClearDispatcher();
|
||||
} else if (chunk.length == CHUNK_SIZE) {
|
||||
aCallback(chunk);
|
||||
chunk.length = 0;
|
||||
this.nextIndex += CHUNK_SIZE;
|
||||
this.interval = setTimeout(this.sendChunk, CHUNK_INTERVAL);
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
this.sendChunk(0);
|
||||
}
|
||||
|
||||
ContactDispatcher.prototype = {
|
||||
sendNow: function() {
|
||||
this.cancelTimeout();
|
||||
this.interval = setTimeout(this.sendChunk, 0);
|
||||
}
|
||||
};
|
||||
|
||||
this.ContactDB = function ContactDB(aGlobal) {
|
||||
if (DEBUG) debug("Constructor");
|
||||
@ -32,6 +90,8 @@ this.ContactDB = function ContactDB(aGlobal) {
|
||||
ContactDB.prototype = {
|
||||
__proto__: IndexedDBHelper.prototype,
|
||||
|
||||
_dispatcher: {},
|
||||
|
||||
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
|
||||
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
|
||||
let db = aDb;
|
||||
@ -513,45 +573,31 @@ ContactDB.prototype = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions) {
|
||||
sendNow: function CDB_sendNow(aCursorId) {
|
||||
if (aCursorId in this._dispatcher) {
|
||||
this._dispatcher[aCursorId].sendNow();
|
||||
}
|
||||
},
|
||||
|
||||
_clearDispatcher: function CDB_clearDispatcher(aCursorId) {
|
||||
if (aCursorId in this._dispatcher) {
|
||||
delete this._dispatcher[aCursorId];
|
||||
}
|
||||
},
|
||||
|
||||
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
|
||||
if (DEBUG) debug("getAll")
|
||||
let optionStr = JSON.stringify(aOptions);
|
||||
this.getCacheForQuery(optionStr, function(aCachedResults, aFullContacts) {
|
||||
// aFullContacts is true if the cache didn't exist and had to be created.
|
||||
// In that case, we receive the full contacts since we already have them
|
||||
// in memory to create the cache anyway. This allows us to avoid accessing
|
||||
// the main object store again.
|
||||
// in memory to create the cache. This allows us to avoid accessing the
|
||||
// object store again.
|
||||
if (aCachedResults && aCachedResults.length > 0) {
|
||||
if (DEBUG) debug("query returned " + aCachedResults.length + " contacts");
|
||||
if (aFullContacts) {
|
||||
if (DEBUG) debug("full contacts: " + aCachedResults.length);
|
||||
while(aCachedResults.length) {
|
||||
aSuccessCb(aCachedResults.splice(0, CHUNK_SIZE));
|
||||
}
|
||||
aSuccessCb(null);
|
||||
} else {
|
||||
let count = 0;
|
||||
let sendChunk = function(start) {
|
||||
let chunk = [];
|
||||
this.newTxn("readonly", STORE_NAME, function(txn, store) {
|
||||
for (let i = start; i < Math.min(start+CHUNK_SIZE, aCachedResults.length); ++i) {
|
||||
store.get(aCachedResults[i]).onsuccess = function(e) {
|
||||
chunk.push(e.target.result);
|
||||
count++;
|
||||
if (count == aCachedResults.length) {
|
||||
aSuccessCb(chunk);
|
||||
aSuccessCb(null);
|
||||
} else if (chunk.length == CHUNK_SIZE) {
|
||||
aSuccessCb(chunk);
|
||||
chunk.length = 0;
|
||||
setTimeout(sendChunk.bind(this, start+CHUNK_SIZE), 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}.bind(this);
|
||||
sendChunk(0);
|
||||
}
|
||||
let newTxnFn = this.newTxn.bind(this);
|
||||
let clearDispatcherFn = this._clearDispatcher.bind(this, aCursorId);
|
||||
this._dispatcher[aCursorId] = new ContactDispatcher(aCachedResults, aFullContacts,
|
||||
aSuccessCb, newTxnFn, clearDispatcherFn);
|
||||
} else { // no contacts
|
||||
if (DEBUG) debug("query returned no contacts");
|
||||
aSuccessCb(null);
|
||||
|
@ -39,7 +39,8 @@ let myGlobal = this;
|
||||
let ContactService = {
|
||||
init: function() {
|
||||
if (DEBUG) debug("Init");
|
||||
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:Clear", "Contact:Save",
|
||||
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
|
||||
"Contacts:Clear", "Contact:Save",
|
||||
"Contact:Remove", "Contacts:GetSimContacts",
|
||||
"Contacts:RegisterForMessages", "child-process-shutdown"];
|
||||
this._children = [];
|
||||
@ -116,7 +117,12 @@ let ContactService = {
|
||||
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
|
||||
},
|
||||
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
|
||||
msg.findOptions);
|
||||
msg.findOptions, msg.cursorId);
|
||||
break;
|
||||
case "Contacts:GetAll:SendNow":
|
||||
// sendNow is a no op if there isn't an existing cursor in the DB, so we
|
||||
// don't need to assert the permission again.
|
||||
this._db.sendNow(msg.cursorId);
|
||||
break;
|
||||
case "Contact:Save":
|
||||
if (msg.options.reason === "create") {
|
||||
|
@ -59,8 +59,16 @@ function onFailure() {
|
||||
}
|
||||
|
||||
function checkStr(str1, str2, msg) {
|
||||
if (str1)
|
||||
ok(typeof str1 == "string" ? [str1] : str1, (typeof str2 == "string") ? [str2] : str2, msg);
|
||||
// comparing /[null(,null)+]/ and undefined should pass
|
||||
function nonNull(e) {
|
||||
return e != null;
|
||||
}
|
||||
if ((Array.isArray(str1) && str1.filter(nonNull).length == 0 && str2 == undefined)
|
||||
||(Array.isArray(str2) && str2.filter(nonNull).length == 0 && str1 == undefined)) {
|
||||
ok(true, msg);
|
||||
} else if (str1) {
|
||||
is(JSON.stringify(typeof str1 == "string" ? [str1] : str1), JSON.stringify(typeof str2 == "string" ? [str2] : str2), msg);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAddress(adr1, adr2) {
|
||||
@ -157,10 +165,11 @@ function clearDatabase() {
|
||||
req.onerror = onFailure;
|
||||
}
|
||||
|
||||
function add20Contacts() {
|
||||
ok(true, "Adding 20 contacts");
|
||||
for (let i=0; i<19; i++) {
|
||||
function addContacts() {
|
||||
ok(true, "Adding 40 contacts");
|
||||
for (let i = 0; i < 39; ++i) {
|
||||
createResult1 = new mozContact();
|
||||
properties1.familyName[0] = "Testname" + (i < 10 ? "0" + i : i);
|
||||
createResult1.init(properties1);
|
||||
req = mozContacts.save(createResult1);
|
||||
req.onsuccess = function() {
|
||||
@ -169,6 +178,7 @@ function add20Contacts() {
|
||||
req.onerror = onFailure;
|
||||
};
|
||||
createResult1 = new mozContact();
|
||||
properties1.familyName[0] = "Testname39";
|
||||
createResult1.init(properties1);
|
||||
req = mozContacts.save(createResult1);
|
||||
req.onsuccess = function() {
|
||||
@ -216,19 +226,27 @@ let steps = [
|
||||
},
|
||||
|
||||
clearDatabase,
|
||||
add20Contacts,
|
||||
addContacts,
|
||||
|
||||
function() {
|
||||
ok(true, "Retrieving 20 contacts with getAll");
|
||||
req = mozContacts.getAll({});
|
||||
ok(true, "Retrieving 40 contacts with getAll");
|
||||
req = mozContacts.getAll({
|
||||
sortBy: "familyName",
|
||||
sortOrder: "ascending"
|
||||
});
|
||||
let count = 0;
|
||||
let result;
|
||||
let props;
|
||||
req.onsuccess = function(event) {
|
||||
if (req.result) {
|
||||
ok(true, "result is valid");
|
||||
result = req.result;
|
||||
properties1.familyName[0] = "Testname" + (count < 10 ? "0" + count : count);
|
||||
is(result.familyName[0], properties1.familyName[0], "Same familyName");
|
||||
count++;
|
||||
req.continue();
|
||||
} else {
|
||||
is(count, 20, "last contact - 20 contacts returned");
|
||||
is(count, 40, "last contact - 40 contacts returned");
|
||||
next();
|
||||
}
|
||||
};
|
||||
@ -253,7 +271,7 @@ let steps = [
|
||||
count++;
|
||||
req.continue();
|
||||
} else {
|
||||
is(count, 19, "last contact - 19 contacts returned");
|
||||
is(count, 39, "last contact - 39 contacts returned");
|
||||
next();
|
||||
}
|
||||
};
|
||||
@ -261,7 +279,7 @@ let steps = [
|
||||
},
|
||||
|
||||
clearDatabase,
|
||||
add20Contacts,
|
||||
addContacts,
|
||||
|
||||
function() {
|
||||
ok(true, "Test cache consistency when deleting contact during getAll");
|
||||
@ -288,7 +306,7 @@ let steps = [
|
||||
count++;
|
||||
req.continue();
|
||||
} else {
|
||||
is(count, 20, "last contact - 20 contacts returned");
|
||||
is(count, 40, "last contact - 40 contacts returned");
|
||||
next();
|
||||
}
|
||||
}
|
||||
@ -297,7 +315,7 @@ let steps = [
|
||||
},
|
||||
|
||||
clearDatabase,
|
||||
add20Contacts,
|
||||
addContacts,
|
||||
|
||||
function() {
|
||||
ok(true, "Delete the current contact while iterating");
|
||||
@ -318,14 +336,14 @@ let steps = [
|
||||
req.continue();
|
||||
};
|
||||
} else {
|
||||
is(count, 20, "returned 20 contacts");
|
||||
is(count, 40, "returned 40 contacts");
|
||||
next();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
clearDatabase,
|
||||
add20Contacts,
|
||||
addContacts,
|
||||
|
||||
function() {
|
||||
ok(true, "Iterating through the contact list inside a cursor callback");
|
||||
@ -341,7 +359,7 @@ let steps = [
|
||||
count2++;
|
||||
req2.continue();
|
||||
} else {
|
||||
is(count2, 20, "inner cursor returned 20 contacts");
|
||||
is(count2, 40, "inner cursor returned 40 contacts");
|
||||
req1.continue();
|
||||
}
|
||||
};
|
||||
@ -350,7 +368,7 @@ let steps = [
|
||||
count1++;
|
||||
req1.continue();
|
||||
} else {
|
||||
is(count1, 20, "outer cursor returned 20 contacts");
|
||||
is(count1, 40, "outer cursor returned 40 contacts");
|
||||
next();
|
||||
}
|
||||
}
|
||||
@ -358,7 +376,7 @@ let steps = [
|
||||
},
|
||||
|
||||
clearDatabase,
|
||||
add20Contacts,
|
||||
addContacts,
|
||||
|
||||
function() {
|
||||
ok(true, "20 concurrent cursors");
|
||||
@ -373,7 +391,7 @@ let steps = [
|
||||
count++;
|
||||
req.continue();
|
||||
} else {
|
||||
is(count, 20, "cursor " + i + " returned 20 contacts");
|
||||
is(count, 40, "cursor " + i + " returned 40 contacts");
|
||||
if (++completed == NUM_CURSORS) {
|
||||
next();
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -80,6 +82,15 @@ public:
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTTARGET
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture,
|
||||
mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
nsDOMDeviceStorage();
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
@ -1527,15 +1529,14 @@ public:
|
||||
nsIPrincipal *aPrincipal,
|
||||
DeviceStorageFile *aFile,
|
||||
DOMRequest* aRequest,
|
||||
nsDOMDeviceStorage *aDeviceStorage,
|
||||
nsIDOMEventListener *aListener)
|
||||
nsDOMDeviceStorage *aDeviceStorage)
|
||||
: mRequestType(aRequestType)
|
||||
, mWindow(aWindow)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mFile(aFile)
|
||||
, mRequest(aRequest)
|
||||
, mDeviceStorage(aDeviceStorage)
|
||||
, mListener(aListener) {}
|
||||
{}
|
||||
|
||||
DeviceStorageRequest(const DeviceStorageRequestType aRequestType,
|
||||
nsPIDOMWindow *aWindow,
|
||||
@ -1821,7 +1822,6 @@ private:
|
||||
nsRefPtr<DOMRequest> mRequest;
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
|
||||
nsCOMPtr<nsIDOMEventListener> mListener;
|
||||
};
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeviceStorageRequest)
|
||||
@ -1833,12 +1833,11 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DeviceStorageRequest)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DeviceStorageRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_5(DeviceStorageRequest,
|
||||
NS_IMPL_CYCLE_COLLECTION_4(DeviceStorageRequest,
|
||||
mRequest,
|
||||
mWindow,
|
||||
mBlob,
|
||||
mDeviceStorage,
|
||||
mListener)
|
||||
mDeviceStorage)
|
||||
|
||||
|
||||
DOMCI_DATA(DeviceStorage, nsDOMDeviceStorage)
|
||||
@ -2455,11 +2454,32 @@ nsDOMDeviceStorage::AddEventListener(const nsAString & aType,
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(win);
|
||||
nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory);
|
||||
nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH,
|
||||
win, mPrincipal, dsf, request, this, aListener);
|
||||
win, mPrincipal, dsf, request, this);
|
||||
NS_DispatchToMainThread(r);
|
||||
return nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aArgc);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMDeviceStorage::AddEventListener(const nsAString & aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
bool aUseCapture,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<DOMRequest> request = new DOMRequest(win);
|
||||
nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(mStorageType, mRootDirectory);
|
||||
nsCOMPtr<nsIRunnable> r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_WATCH,
|
||||
win, mPrincipal, dsf, request, this);
|
||||
NS_DispatchToMainThread(r);
|
||||
nsDOMEventTargetHelper::AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted, aRv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
@ -2491,6 +2511,21 @@ nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMDeviceStorage::RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aCapture,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener, aCapture, aRv);
|
||||
|
||||
if (mIsWatchingFile && !HasListenersFor(nsGkAtoms::onchange)) {
|
||||
mIsWatchingFile = false;
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
obs->RemoveObserver(this, "file-watcher-update");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMDeviceStorage::RemoveSystemEventListener(const nsAString & aType,
|
||||
nsIDOMEventListener *aListener,
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
NS_DECL_NSIFMRADIO
|
||||
NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
FMRadio();
|
||||
virtual void Notify(const hal::FMRadioOperationInformation& info);
|
||||
virtual void Notify(const hal::SwitchEvent& aEvent);
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
NS_DECL_NSIDOMMOZICCMANAGER
|
||||
NS_DECL_NSIICCLISTENER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
IccManager();
|
||||
|
||||
|
@ -113,6 +113,7 @@ public:
|
||||
return nsDOMEventTargetHelper::AddEventListener(aType, aListener,
|
||||
aUseCapture, false, 2);
|
||||
}
|
||||
using nsDOMEventTargetHelper::AddEventListener;
|
||||
NS_IMETHOD AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
bool aUseCapture, bool aWantsUntrusted,
|
||||
|
@ -727,14 +727,12 @@ PeerConnection.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
// This is a separate object because we don't want to expose it to DOM.
|
||||
function PeerConnectionObserver(dompc) {
|
||||
this._dompc = dompc;
|
||||
function RTCError(code, message) {
|
||||
this.name = this.reasonName[Math.min(code, this.reasonName.length - 1)];
|
||||
this.message = (typeof message === "string")? message : this.name;
|
||||
this.__exposedProps__ = { name: "rw", message: "rw" };
|
||||
}
|
||||
PeerConnectionObserver.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
RTCError.prototype = {
|
||||
// These strings must match those defined in the WebRTC spec.
|
||||
reasonName: [
|
||||
"NO_ERROR", // Should never happen -- only used for testing
|
||||
@ -747,69 +745,106 @@ PeerConnectionObserver.prototype = {
|
||||
"INCOMPATIBLE_CONSTRAINTS",
|
||||
"INCOMPATIBLE_MEDIASTREAMTRACK",
|
||||
"INTERNAL_ERROR"
|
||||
],
|
||||
]
|
||||
};
|
||||
|
||||
callErrorCallback: function(callback, code, message) {
|
||||
if (code > Ci.IPeerConnection.kMaxErrorType) {
|
||||
code = Ci.IPeerConnection.kInternalError;
|
||||
}
|
||||
|
||||
if (typeof message !== "string") {
|
||||
message = this.reasonName[code];
|
||||
}
|
||||
// This is a separate object because we don't want to expose it to DOM.
|
||||
function PeerConnectionObserver(dompc) {
|
||||
this._dompc = dompc;
|
||||
}
|
||||
PeerConnectionObserver.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
callCB: function(callback, arg) {
|
||||
if (callback) {
|
||||
try {
|
||||
callback.onCallback({
|
||||
name: this.reasonName[code], message: message,
|
||||
__exposedProps__: { name: "rw", message: "rw" }
|
||||
});
|
||||
} catch(e) {}
|
||||
callback.onCallback(arg);
|
||||
} catch(e) {
|
||||
// A content script (user-provided) callback threw an error. We don't
|
||||
// want this to take down peerconnection, but we still want the user
|
||||
// to see it, so we catch it, report it, and move on.
|
||||
//
|
||||
// We do stack parsing in two different places for different reasons:
|
||||
|
||||
var msg;
|
||||
if (e.result == Cr.NS_ERROR_XPC_JS_THREW_JS_OBJECT) {
|
||||
// TODO(jib@mozilla.com): Revisit once bug 862153 is fixed.
|
||||
//
|
||||
// The actual content script frame is unavailable due to bug 862153,
|
||||
// so users see file and line # into this file, which is not helpful.
|
||||
//
|
||||
// 1) Fix up the error message itself to differentiate between the
|
||||
// 22 places we call callCB() in this file, using plain JS stack.
|
||||
//
|
||||
// Tweak the existing NS_ERROR_XPC_JS_THREW_JS_OBJECT message:
|
||||
// -'Error: x' when calling method: [RTCPeerConCallback::onCallback]
|
||||
// +'Error: x' when calling method: [RTCPeerConCallback::onCreateOfferError]
|
||||
|
||||
let caller = Error().stack.split("\n")[1].split("@")[0];
|
||||
// caller ~= "PeerConnectionObserver.prototype.onCreateOfferError"
|
||||
|
||||
msg = e.message.replace("::onCallback", "::" + caller.split(".")[2]);
|
||||
} else {
|
||||
msg = e.message;
|
||||
}
|
||||
|
||||
// Log error message to web console and window.onerror, if present.
|
||||
//
|
||||
// 2) nsIScriptError doesn't understand the nsIStackFrame format, so
|
||||
// do the translation by extracting file and line from XPCOM stack:
|
||||
//
|
||||
// e.location ~= "JS frame :: file://.js :: RTCPCCb::onCallback :: line 1"
|
||||
|
||||
let stack = e.location.toString().split(" :: ");
|
||||
let file = stack[1];
|
||||
let line = parseInt(stack[3].split(" ")[1]);
|
||||
|
||||
let scriptError = Cc["@mozilla.org/scripterror;1"].
|
||||
createInstance(Ci.nsIScriptError);
|
||||
scriptError.initWithWindowID(msg, file, null, line, 0,
|
||||
Ci.nsIScriptError.exceptionFlag,
|
||||
"content javascript",
|
||||
this._dompc._winID);
|
||||
Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService).logMessage(scriptError);
|
||||
|
||||
// Call onerror directly if present (necessary for testing)
|
||||
if (typeof this._dompc._win.onerror === "function") {
|
||||
this._dompc._win.onerror(msg, file, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onCreateOfferSuccess: function(offer) {
|
||||
if (this._dompc._onCreateOfferSuccess) {
|
||||
try {
|
||||
this._dompc._onCreateOfferSuccess.onCallback({
|
||||
type: "offer", sdp: offer,
|
||||
__exposedProps__: { type: "rw", sdp: "rw" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc._onCreateOfferSuccess,
|
||||
{ type: "offer", sdp: offer,
|
||||
__exposedProps__: { type: "rw", sdp: "rw" } });
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onCreateOfferError: function(code, message) {
|
||||
this.callErrorCallback (this._dompc._onCreateOfferFailure, code, message);
|
||||
this.callCB(this._dompc._onCreateOfferFailure, new RTCError(code, message));
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onCreateAnswerSuccess: function(answer) {
|
||||
if (this._dompc._onCreateAnswerSuccess) {
|
||||
try {
|
||||
this._dompc._onCreateAnswerSuccess.onCallback({
|
||||
type: "answer", sdp: answer,
|
||||
__exposedProps__: { type: "rw", sdp: "rw" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB (this._dompc._onCreateAnswerSuccess,
|
||||
{ type: "answer", sdp: answer,
|
||||
__exposedProps__: { type: "rw", sdp: "rw" } });
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onCreateAnswerError: function(code, message) {
|
||||
this.callErrorCallback (this._dompc._onCreateAnswerFailure, code, message);
|
||||
this.callCB(this._dompc._onCreateAnswerFailure, new RTCError(code, message));
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onSetLocalDescriptionSuccess: function() {
|
||||
this._dompc._localType = this._dompc._pendingType;
|
||||
this._dompc._pendingType = null;
|
||||
if (this._dompc._onSetLocalDescriptionSuccess) {
|
||||
try {
|
||||
this._dompc._onSetLocalDescriptionSuccess.onCallback();
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc._onSetLocalDescriptionSuccess);
|
||||
|
||||
// Until we support generating trickle ICE candidates,
|
||||
// we go ahead and trigger a call of onicecandidate here.
|
||||
@ -825,39 +860,33 @@ PeerConnectionObserver.prototype = {
|
||||
onSetRemoteDescriptionSuccess: function() {
|
||||
this._dompc._remoteType = this._dompc._pendingType;
|
||||
this._dompc._pendingType = null;
|
||||
if (this._dompc._onSetRemoteDescriptionSuccess) {
|
||||
try {
|
||||
this._dompc._onSetRemoteDescriptionSuccess.onCallback();
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc._onSetRemoteDescriptionSuccess);
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onSetLocalDescriptionError: function(code, message) {
|
||||
this._dompc._pendingType = null;
|
||||
this.callErrorCallback (this._dompc._onSetLocalDescriptionFailure, code,
|
||||
message);
|
||||
this.callCB(this._dompc._onSetLocalDescriptionFailure,
|
||||
new RTCError(code, message));
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onSetRemoteDescriptionError: function(code, message) {
|
||||
this._dompc._pendingType = null;
|
||||
this.callErrorCallback (this._dompc._onSetRemoteDescriptionFailure, code,
|
||||
message);
|
||||
this.callCB(this._dompc._onSetRemoteDescriptionFailure,
|
||||
new RTCError(code, message));
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onAddIceCandidateSuccess: function() {
|
||||
this._dompc._pendingType = null;
|
||||
if (this._dompc._onAddIceCandidateSuccess) {
|
||||
this._dompc._onAddIceCandidateSuccess.onCallback();
|
||||
}
|
||||
this.callCB(this._dompc._onAddIceCandidateSuccess);
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
onAddIceCandidateError: function(code, message) {
|
||||
this._dompc._pendingType = null;
|
||||
this.callErrorCallback (this._dompc._onAddIceCandidateError, code, message);
|
||||
this.callCB(this._dompc._onAddIceCandidateError, new RTCError(code, message));
|
||||
this._dompc._executeNext();
|
||||
},
|
||||
|
||||
@ -866,42 +895,24 @@ PeerConnectionObserver.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let iceCb = function() {};
|
||||
let iceGatherCb = function() {};
|
||||
if (this._dompc.onicechange) {
|
||||
iceCb = function(args) {
|
||||
try {
|
||||
self._dompc.onicechange(args);
|
||||
} catch(e) {}
|
||||
};
|
||||
}
|
||||
if (this._dompc.ongatheringchange) {
|
||||
iceGatherCb = function(args) {
|
||||
try {
|
||||
self._dompc.ongatheringchange(args);
|
||||
} catch(e) {}
|
||||
};
|
||||
}
|
||||
|
||||
switch (this._dompc._pc.iceState) {
|
||||
case Ci.IPeerConnection.kIceGathering:
|
||||
iceGatherCb("gathering");
|
||||
this.callCB(this._dompc.ongatheringchange, "gathering");
|
||||
break;
|
||||
case Ci.IPeerConnection.kIceWaiting:
|
||||
iceCb("starting");
|
||||
this.callCB(this._dompc.onicechange, "starting");
|
||||
this._dompc._executeNext();
|
||||
break;
|
||||
case Ci.IPeerConnection.kIceChecking:
|
||||
iceCb("checking");
|
||||
this.callCB(this._dompc.onicechange, "checking");
|
||||
break;
|
||||
case Ci.IPeerConnection.kIceConnected:
|
||||
// ICE gathering complete.
|
||||
iceCb("connected");
|
||||
iceGatherCb("complete");
|
||||
this.callCB(this._dompc.onicechange, "connected");
|
||||
this.callCB(this._dompc.ongatheringchange, "complete");
|
||||
break;
|
||||
case Ci.IPeerConnection.kIceFailed:
|
||||
iceCb("failed");
|
||||
this.callCB(this._dompc.onicechange, "failed");
|
||||
break;
|
||||
default:
|
||||
// Unknown state!
|
||||
@ -910,63 +921,33 @@ PeerConnectionObserver.prototype = {
|
||||
},
|
||||
|
||||
onAddStream: function(stream, type) {
|
||||
if (this._dompc.onaddstream) {
|
||||
try {
|
||||
this._dompc.onaddstream.onCallback({
|
||||
stream: stream, type: type,
|
||||
__exposedProps__: { stream: "r", type: "r" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc.onaddstream,
|
||||
{ stream: stream, type: type,
|
||||
__exposedProps__: { stream: "r", type: "r" } });
|
||||
},
|
||||
|
||||
onRemoveStream: function(stream, type) {
|
||||
if (this._dompc.onremovestream) {
|
||||
try {
|
||||
this._dompc.onremovestream.onCallback({
|
||||
stream: stream, type: type,
|
||||
__exposedProps__: { stream: "r", type: "r" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc.onremovestream,
|
||||
{ stream: stream, type: type,
|
||||
__exposedProps__: { stream: "r", type: "r" } });
|
||||
},
|
||||
|
||||
foundIceCandidate: function(cand) {
|
||||
if (this._dompc.onicecandidate) {
|
||||
try {
|
||||
this._dompc.onicecandidate.onCallback({
|
||||
candidate: cand,
|
||||
__exposedProps__: { candidate: "rw" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc.onicecandidate,
|
||||
{candidate: cand, __exposedProps__: { candidate: "rw" } });
|
||||
},
|
||||
|
||||
notifyDataChannel: function(channel) {
|
||||
if (this._dompc.ondatachannel) {
|
||||
try {
|
||||
this._dompc.ondatachannel.onCallback({
|
||||
channel: channel,
|
||||
__exposedProps__: { channel: "r" }
|
||||
});
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB(this._dompc.ondatachannel,
|
||||
{ channel: channel, __exposedProps__: { channel: "r" } });
|
||||
},
|
||||
|
||||
notifyConnection: function() {
|
||||
if (this._dompc.onconnection) {
|
||||
try {
|
||||
this._dompc.onconnection.onCallback();
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB (this._dompc.onconnection);
|
||||
},
|
||||
|
||||
notifyClosedConnection: function() {
|
||||
if (this._dompc.onclosedconnection) {
|
||||
try {
|
||||
this._dompc.onclosedconnection.onCallback();
|
||||
} catch(e) {}
|
||||
}
|
||||
this.callCB (this._dompc.onclosedconnection);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -33,6 +33,7 @@ MOCHITEST_FILES = \
|
||||
test_peerConnection_offerRequiresReceiveAudio.html \
|
||||
test_peerConnection_offerRequiresReceiveVideo.html \
|
||||
test_peerConnection_offerRequiresReceiveVideoAudio.html \
|
||||
test_peerConnection_throwInCallbacks.html \
|
||||
test_peerConnection_bug822674.html \
|
||||
test_peerConnection_bug825703.html \
|
||||
test_peerConnection_bug827843.html \
|
||||
|
@ -0,0 +1,83 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
createHTML({
|
||||
bug: "857765",
|
||||
title: "Throw in PeerConnection callbacks"
|
||||
});
|
||||
|
||||
let error_count = 0;
|
||||
let oldOnError = window.onerror;
|
||||
window.onerror = function (errorMsg, url, lineNumber) {
|
||||
if (errorMsg.indexOf("Expected") == -1) {
|
||||
getFail(new Error)(errorMsg);
|
||||
}
|
||||
error_count += 1;
|
||||
info("onerror " + error_count + ": " + errorMsg);
|
||||
if (error_count == 7) {
|
||||
finish();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
let pc0, pc1, pc2;
|
||||
|
||||
runTest(function () {
|
||||
error_count = 0;
|
||||
|
||||
// Test failure callbacks (limited to 1 for now)
|
||||
pc0 = new mozRTCPeerConnection();
|
||||
pc0.createOffer(getFail(new Error), function(err) {
|
||||
pc1 = new mozRTCPeerConnection();
|
||||
pc2 = new mozRTCPeerConnection();
|
||||
|
||||
// Test success callbacks (happy path)
|
||||
navigator.mozGetUserMedia({video:true, fake: true}, function(video1) {
|
||||
pc1.addStream(video1);
|
||||
pc1.createOffer(function(offer) {
|
||||
pc1.setLocalDescription(offer, function() {
|
||||
pc2.setRemoteDescription(offer, function() {
|
||||
pc2.createAnswer(function(answer) {
|
||||
pc2.setLocalDescription(answer, function() {
|
||||
pc1.setRemoteDescription(answer, function() {
|
||||
throw new Error("Expected");
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
});
|
||||
}, getFail(new Error));
|
||||
throw new Error("Expected");
|
||||
});
|
||||
}, 1);
|
||||
|
||||
function finish() {
|
||||
window.onerror = oldOnError;
|
||||
ok(error_count == 7, "Seven expected errors verified.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function getFail(where) {
|
||||
return function (err) {
|
||||
window.onerror = onOldError;
|
||||
unexpectedCallbackAndFinish(where)(err);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -164,13 +164,13 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the roaming status of data connection.
|
||||
* Return the roaming status of voice call.
|
||||
*
|
||||
* @return true if data connection is roaming.
|
||||
* @return true if voice call is roaming.
|
||||
*/
|
||||
isDataConnRoaming: function isDataConnRoaming() {
|
||||
let isRoaming = gRIL.rilContext.data.roaming;
|
||||
debug("isDataConnRoaming = " + isRoaming);
|
||||
isVoiceRoaming: function isVoiceRoaming() {
|
||||
let isRoaming = gRIL.rilContext.voice.roaming;
|
||||
debug("isVoiceRoaming = " + isRoaming);
|
||||
return isRoaming;
|
||||
},
|
||||
|
||||
@ -1166,9 +1166,14 @@ MmsService.prototype = {
|
||||
retrievalMode = Services.prefs.getCharPref(PREF_RETRIEVAL_MODE);
|
||||
} catch (e) {}
|
||||
|
||||
let isRoaming = gMmsConnection.isDataConnRoaming();
|
||||
if ((retrievalMode === RETRIEVAL_MODE_AUTOMATIC_HOME && isRoaming) ||
|
||||
RETRIEVAL_MODE_MANUAL === retrievalMode ||
|
||||
// In roaming environment, we send notify response only in
|
||||
// automatic retrieval mode.
|
||||
if ((retrievalMode !== RETRIEVAL_MODE_AUTOMATIC) &&
|
||||
gMmsConnection.isVoiceRoaming()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (RETRIEVAL_MODE_MANUAL === retrievalMode ||
|
||||
RETRIEVAL_MODE_NEVER === retrievalMode) {
|
||||
let mmsStatus = RETRIEVAL_MODE_NEVER === retrievalMode
|
||||
? MMS.MMS_PDU_STATUS_REJECTED
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMMOZMOBILEMESSAGEMANAGER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
void Init(nsPIDOMWindow *aWindow);
|
||||
void Shutdown();
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMMOZSMSMANAGER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
static already_AddRefed<SmsManager>
|
||||
CreateInstanceIfAllowed(nsPIDOMWindow *aWindow);
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMMOZCONNECTION
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
Connection();
|
||||
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
NS_DECL_NSIDOMMOZMOBILECONNECTION
|
||||
NS_DECL_NSIMOBILECONNECTIONLISTENER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
MobileConnection();
|
||||
|
||||
|
@ -149,22 +149,6 @@ nsPluginInstanceOwner::NotifyPaintWaiter(nsDisplayListBuilder* aBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
static void DrawPlugin(ImageContainer* aContainer, void* aPluginInstanceOwner)
|
||||
{
|
||||
nsObjectFrame* frame = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner)->GetFrame();
|
||||
if (frame) {
|
||||
frame->UpdateImageLayer(gfxRect(0,0,0,0));
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDestroyImage(void* aPluginInstanceOwner)
|
||||
{
|
||||
nsPluginInstanceOwner* owner = static_cast<nsPluginInstanceOwner*>(aPluginInstanceOwner);
|
||||
NS_IF_RELEASE(owner);
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
nsPluginInstanceOwner::GetImageContainer()
|
||||
{
|
||||
@ -206,22 +190,7 @@ nsPluginInstanceOwner::GetImageContainer()
|
||||
#endif
|
||||
|
||||
mInstance->GetImageContainer(getter_AddRefs(container));
|
||||
if (container) {
|
||||
#ifdef XP_MACOSX
|
||||
AutoLockImage autoLock(container);
|
||||
Image* image = autoLock.GetImage();
|
||||
if (image && image->GetFormat() == MAC_IO_SURFACE && mObjectFrame) {
|
||||
// With this drawing model, every call to
|
||||
// nsIPluginInstance::GetImage() creates a new image.
|
||||
MacIOSurfaceImage *oglImage = static_cast<MacIOSurfaceImage*>(image);
|
||||
NS_ADDREF_THIS();
|
||||
oglImage->SetUpdateCallback(&DrawPlugin, this);
|
||||
oglImage->SetDestroyCallback(&OnDestroyImage);
|
||||
}
|
||||
#endif
|
||||
return container.forget();
|
||||
}
|
||||
return nullptr;
|
||||
return container.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@ -634,7 +603,6 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
|
||||
#if defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID)
|
||||
// Each time an asynchronously-drawing plugin sends a new surface to display,
|
||||
// the image in the ImageContainer is updated and InvalidateRect is called.
|
||||
// MacIOSurfaceImages callbacks are attached here.
|
||||
// There are different side effects for (sync) Android plugins.
|
||||
nsRefPtr<ImageContainer> container;
|
||||
mInstance->GetImageContainer(getter_AddRefs(container));
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "gfxUtils.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "Layers.h"
|
||||
#include "SharedTextureImage.h"
|
||||
#include "GLContext.h"
|
||||
#include "GLContextProvider.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windowsx.h>
|
||||
@ -47,6 +50,7 @@ extern const PRUnichar* kFlashFullscreenClass;
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
bool
|
||||
StreamNotifyParent::RecvRedirectNotifyResponse(const bool& allow)
|
||||
@ -739,18 +743,26 @@ PluginInstanceParent::GetImageContainer(ImageContainer** aContainer)
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (ioSurface) {
|
||||
ImageFormat format = MAC_IO_SURFACE;
|
||||
ImageFormat format = SHARED_TEXTURE;
|
||||
nsRefPtr<Image> image = container->CreateImage(&format, 1);
|
||||
if (!image) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(image->GetFormat() == MAC_IO_SURFACE, "Wrong format?");
|
||||
MacIOSurfaceImage* ioImage = static_cast<MacIOSurfaceImage*>(image.get());
|
||||
MacIOSurfaceImage::Data ioData;
|
||||
ioData.mIOSurface = ioSurface;
|
||||
ioImage->SetData(ioData);
|
||||
container->SetCurrentImageInTransaction(ioImage);
|
||||
NS_ASSERTION(image->GetFormat() == SHARED_TEXTURE, "Wrong format?");
|
||||
|
||||
SharedTextureImage::Data data;
|
||||
data.mShareType = GLContext::SameProcess;
|
||||
data.mHandle = GLContextProviderCGL::CreateSharedHandle(data.mShareType,
|
||||
ioSurface,
|
||||
GLContext::IOSurface);
|
||||
data.mInverted = false;
|
||||
data.mSize = gfxIntSize(ioSurface->GetWidth(), ioSurface->GetHeight());
|
||||
|
||||
SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(image.get());
|
||||
pluginImage->SetData(data);
|
||||
|
||||
container->SetCurrentImageInTransaction(pluginImage);
|
||||
|
||||
NS_IF_ADDREF(container);
|
||||
*aContainer = container;
|
||||
|
@ -308,7 +308,6 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
|
||||
}
|
||||
case WM_DESTROY: {
|
||||
EnableWindow(mParentWindow, TRUE);
|
||||
SetForegroundWindow(mParentWindow);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -141,11 +141,6 @@ MOCHITEST_CHROME_FILES += \
|
||||
test_idle_hang.xul \
|
||||
test_busy_hang.xul \
|
||||
hang_test.js \
|
||||
test_hangui.xul \
|
||||
hangui_subpage.html \
|
||||
hangui_common.js \
|
||||
hangui_iface.js \
|
||||
dialog_watcher.js \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
|
@ -1,172 +0,0 @@
|
||||
const EVENT_OBJECT_SHOW = 0x8002;
|
||||
const EVENT_OBJECT_HIDE = 0x8003;
|
||||
const WINEVENT_OUTOFCONTEXT = 0;
|
||||
const WINEVENT_SKIPOWNPROCESS = 2;
|
||||
const QS_ALLINPUT = 0x04FF;
|
||||
const INFINITE = 0xFFFFFFFF;
|
||||
const WAIT_OBJECT_0 = 0;
|
||||
const WAIT_TIMEOUT = 258;
|
||||
const PM_NOREMOVE = 0;
|
||||
|
||||
function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
|
||||
this.titleText = titleText;
|
||||
this.onDialogStart = onDialogStart;
|
||||
this.onDialogEnd = onDialogEnd;
|
||||
}
|
||||
|
||||
DialogWatcher.prototype.init = function() {
|
||||
this.hwnd = undefined;
|
||||
if (!this.user32) {
|
||||
this.user32 = ctypes.open("user32.dll");
|
||||
}
|
||||
if (!this.findWindow) {
|
||||
this.findWindow = user32.declare("FindWindowW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.jschar.ptr);
|
||||
}
|
||||
if (!this.winEventProcType) {
|
||||
this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
|
||||
ctypes.void_t,
|
||||
[ctypes.uintptr_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.long,
|
||||
ctypes.long,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t]).ptr;
|
||||
}
|
||||
if (!this.setWinEventHook) {
|
||||
this.setWinEventHook = user32.declare("SetWinEventHook",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uintptr_t,
|
||||
this.winEventProcType,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
if (!this.unhookWinEvent) {
|
||||
this.unhookWinEvent = user32.declare("UnhookWinEvent",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t);
|
||||
}
|
||||
if (!this.pointType) {
|
||||
this.pointType = ctypes.StructType("tagPOINT",
|
||||
[ { "x": ctypes.long },
|
||||
{ "y": ctypes.long } ] );
|
||||
}
|
||||
if (!this.msgType) {
|
||||
this.msgType = ctypes.StructType("tagMSG",
|
||||
[ { "hwnd": ctypes.uintptr_t },
|
||||
{ "message": ctypes.uint32_t },
|
||||
{ "wParam": ctypes.uintptr_t },
|
||||
{ "lParam": ctypes.intptr_t },
|
||||
{ "time": ctypes.uint32_t },
|
||||
{ "pt": this.pointType } ] );
|
||||
}
|
||||
if (!this.peekMessage) {
|
||||
this.peekMessage = user32.declare("PeekMessageW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
this.msgType.ptr,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
if (!this.msgWaitForMultipleObjects) {
|
||||
this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uintptr_t.ptr,
|
||||
ctypes.int,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
if (!this.getWindowTextW) {
|
||||
this.getWindowTextW = user32.declare("GetWindowTextW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.int);
|
||||
}
|
||||
};
|
||||
|
||||
DialogWatcher.prototype.getWindowText = function(hwnd) {
|
||||
var bufType = ctypes.ArrayType(ctypes.jschar);
|
||||
var buffer = new bufType(256);
|
||||
|
||||
if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
|
||||
return buffer.readString();
|
||||
}
|
||||
};
|
||||
|
||||
DialogWatcher.prototype.processWindowEvents = function(timeout) {
|
||||
var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
|
||||
var nhwnd = Number(hwnd)
|
||||
if (event == EVENT_OBJECT_SHOW) {
|
||||
if (nhwnd == self.hwnd) {
|
||||
// We've already picked up this event via FindWindow
|
||||
return;
|
||||
}
|
||||
var windowText = self.getWindowText(hwnd);
|
||||
if (windowText == self.titleText && self.onDialogStart) {
|
||||
self.hwnd = nhwnd;
|
||||
self.onDialogStart(nhwnd);
|
||||
}
|
||||
} else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
|
||||
self.onDialogEnd();
|
||||
self.hwnd = null;
|
||||
}
|
||||
};
|
||||
var self = this;
|
||||
var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
|
||||
idChild, dwEventThread,
|
||||
dwmsEventTime) {
|
||||
onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
|
||||
dwmsEventTime);
|
||||
} );
|
||||
var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
|
||||
0, callback, 0, 0,
|
||||
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
|
||||
if (!hook) {
|
||||
return;
|
||||
}
|
||||
// Check if the window is already showing
|
||||
var hwnd = this.findWindow(null, this.titleText);
|
||||
if (hwnd && hwnd > 0) {
|
||||
this.hwnd = Number(hwnd);
|
||||
if (this.onDialogStart) {
|
||||
this.onDialogStart(this.hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
timeout = INFINITE;
|
||||
}
|
||||
|
||||
var waitStatus = WAIT_OBJECT_0;
|
||||
var expectingStart = this.onDialogStart && this.hwnd === undefined;
|
||||
while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
|
||||
waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
|
||||
INFINITE : timeout, 0);
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
var msg = new this.msgType;
|
||||
this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
|
||||
} else if (waitStatus == WAIT_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.unhookWinEvent(hook);
|
||||
// Returns true if the hook was successful, something was found, and we never timed out
|
||||
return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
|
||||
};
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Plugin Hang UI constants
|
||||
const HANGUIOP_NOTHING = 0;
|
||||
const HANGUIOP_CANCEL = 1;
|
||||
const HANGUIOP_COMMAND = 2;
|
||||
const IDC_CONTINUE = 1001;
|
||||
const IDC_STOP = 1002;
|
||||
const IDC_NOFUTURE = 1003;
|
||||
|
||||
// Windows constants
|
||||
const WM_CLOSE = 0x0010;
|
||||
const WM_COMMAND = 0x0111;
|
||||
const BM_GETCHECK = 0x00F0;
|
||||
const BM_SETCHECK = 0x00F1;
|
||||
const BN_CLICKED = 0;
|
||||
const BST_CHECKED = 1;
|
||||
|
||||
// Test-specific constants
|
||||
const EPSILON_MS = 1000;
|
||||
const STALL_DURATION = 5;
|
||||
|
@ -1,121 +0,0 @@
|
||||
var user32;
|
||||
var sendMessage;
|
||||
var getDlgItem;
|
||||
var messageBox;
|
||||
var watcher;
|
||||
|
||||
importScripts("hangui_common.js");
|
||||
importScripts("dialog_watcher.js");
|
||||
|
||||
function initCTypes() {
|
||||
if (!user32) {
|
||||
user32 = ctypes.open("user32.dll");
|
||||
}
|
||||
if (!getDlgItem) {
|
||||
getDlgItem = user32.declare("GetDlgItem",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.int);
|
||||
}
|
||||
if (!sendMessage) {
|
||||
sendMessage = user32.declare("SendMessageW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.intptr_t,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.uint32_t,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.intptr_t);
|
||||
}
|
||||
if (!messageBox) {
|
||||
// Handy for debugging the test itself
|
||||
messageBox = user32.declare("MessageBoxW",
|
||||
ctypes.winapi_abi,
|
||||
ctypes.int,
|
||||
ctypes.uintptr_t,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.jschar.ptr,
|
||||
ctypes.uint32_t);
|
||||
}
|
||||
if (!watcher) {
|
||||
watcher = new DialogWatcher("Warning: Unresponsive plugin");
|
||||
}
|
||||
}
|
||||
|
||||
function postSuccess(params) {
|
||||
self.postMessage({"status": true, "params": params});
|
||||
}
|
||||
|
||||
function postFail(params, msg) {
|
||||
self.postMessage({"status": false, "params": params, "msg": msg});
|
||||
}
|
||||
|
||||
function onDialogStart(inparams, hwnd) {
|
||||
var params = Object.create(inparams);
|
||||
params.testName += " (Start)";
|
||||
params.callback = null;
|
||||
if (!params.expectToFind) {
|
||||
postFail(params, "Dialog showed when we weren't expecting it to!");
|
||||
return;
|
||||
}
|
||||
if (params.opCode == HANGUIOP_CANCEL) {
|
||||
sendMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
} else if (params.opCode == HANGUIOP_COMMAND) {
|
||||
if (params.check) {
|
||||
var checkbox = getDlgItem(hwnd, IDC_NOFUTURE);
|
||||
if (!checkbox) {
|
||||
postFail(params, "Couldn't find checkbox");
|
||||
return;
|
||||
}
|
||||
sendMessage(checkbox, BM_SETCHECK, BST_CHECKED, 0);
|
||||
sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | IDC_NOFUTURE, checkbox);
|
||||
}
|
||||
var button = getDlgItem(hwnd, params.commandId);
|
||||
if (!button) {
|
||||
postFail(params,
|
||||
"GetDlgItem failed to find button with ID " + params.commandId);
|
||||
return;
|
||||
}
|
||||
sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | params.commandId, button);
|
||||
}
|
||||
postSuccess(params);
|
||||
}
|
||||
|
||||
function onDialogEnd(inparams) {
|
||||
var params = Object.create(inparams);
|
||||
params.testName += " (End)";
|
||||
params.callback = inparams.callback;
|
||||
postSuccess(params);
|
||||
}
|
||||
|
||||
self.onmessage = function(event) {
|
||||
initCTypes();
|
||||
watcher.init();
|
||||
var params = event.data;
|
||||
var timeout = params.timeoutMs;
|
||||
if (params.expectToFind) {
|
||||
watcher.onDialogStart = function(hwnd) { onDialogStart(params, hwnd); };
|
||||
if (params.expectToClose) {
|
||||
watcher.onDialogEnd = function() { onDialogEnd(params); };
|
||||
}
|
||||
} else {
|
||||
watcher.onDialogStart = null;
|
||||
watcher.onDialogEnd = null;
|
||||
}
|
||||
var result = watcher.processWindowEvents(timeout);
|
||||
if (result === null) {
|
||||
postFail(params, "Hook failed");
|
||||
} else if (!result) {
|
||||
if (params.expectToFind) {
|
||||
postFail(params, "The dialog didn't show but we were expecting it to");
|
||||
} else {
|
||||
postSuccess(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.onerror = function(event) {
|
||||
var msg = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
|
||||
postFail(null, msg);
|
||||
};
|
||||
|
@ -1,4 +0,0 @@
|
||||
<html>
|
||||
<body onload="window.parent.frameLoaded()">
|
||||
<embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
|
||||
|
@ -1,263 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Basic Plugin Tests"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<title>Plugin Hang UI Test</title>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="http://mochi.test:8888/chrome/dom/plugins/test/hang_test.js" />
|
||||
<script type="application/javascript"
|
||||
src="http://mochi.test:8888/chrome/dom/plugins/test/hangui_common.js" />
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<iframe id="iframe1" src="hangui_subpage.html" width="400" height="400"></iframe>
|
||||
</body>
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const hangUITimeoutPref = "dom.ipc.plugins.hangUITimeoutSecs";
|
||||
const hangUIMinDisplayPref = "dom.ipc.plugins.hangUIMinDisplaySecs";
|
||||
const timeoutPref = "dom.ipc.plugins.timeoutSecs";
|
||||
|
||||
var worker = new ChromeWorker("hangui_iface.js");
|
||||
worker.onmessage = function(event) {
|
||||
var result = event.data;
|
||||
var params = result.params;
|
||||
var output = params.testName;
|
||||
if (result.msg) {
|
||||
output += ": " + result.msg;
|
||||
}
|
||||
ok(result.status, output);
|
||||
if (params.callback) {
|
||||
var cb = eval(params.callback);
|
||||
var timeout = setTimeout(function() { clearTimeout(timeout); cb(); }, 100);
|
||||
}
|
||||
};
|
||||
worker.onerror = function(event) {
|
||||
var output = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
|
||||
ok(false, output);
|
||||
};
|
||||
|
||||
var iframe;
|
||||
var p;
|
||||
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
|
||||
function hanguiOperation(testName, timeoutSec, expectFind, expectClose, opCode,
|
||||
commandId, check, cb) {
|
||||
var timeoutMs = timeoutSec * 1000 + EPSILON_MS;
|
||||
worker.postMessage({ "timeoutMs": timeoutMs, "expectToFind": expectFind,
|
||||
"expectToClose": expectClose, "opCode": opCode,
|
||||
"commandId": commandId, "check": check,
|
||||
"testName": testName, "callback": cb });
|
||||
}
|
||||
|
||||
function hanguiExpect(testName, shouldBeShowing, shouldClose, cb) {
|
||||
var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
|
||||
if (!shouldBeShowing && !timeoutSec) {
|
||||
timeoutSec = Services.prefs.getIntPref(timeoutPref);
|
||||
}
|
||||
hanguiOperation(testName, timeoutSec, shouldBeShowing, shouldClose, HANGUIOP_NOTHING, 0, false, cb);
|
||||
}
|
||||
|
||||
function hanguiContinue(testName, check, cb) {
|
||||
var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
|
||||
hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_CONTINUE, check, cb);
|
||||
}
|
||||
|
||||
function hanguiStop(testName, check, cb) {
|
||||
var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
|
||||
hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_STOP, check, cb);
|
||||
}
|
||||
|
||||
function hanguiCancel(testName, cb) {
|
||||
var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
|
||||
hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_CANCEL, 0, false, cb);
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
if (obsCount > 0) {
|
||||
os.removeObserver(testObserver, "plugin-crashed");
|
||||
--obsCount;
|
||||
}
|
||||
SpecialPowers.clearUserPref(hangUITimeoutPref);
|
||||
SpecialPowers.clearUserPref(hangUIMinDisplayPref);
|
||||
SpecialPowers.clearUserPref(timeoutPref);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
if (!SimpleTest.testPluginIsOOP()) {
|
||||
ok(true, "Skipping this test when test plugin is not OOP.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
resetVars();
|
||||
|
||||
hanguiExpect("Prime ChromeWorker", false, false, "test1");
|
||||
}
|
||||
|
||||
window.frameLoaded = runTests;
|
||||
|
||||
var obsCount = 0;
|
||||
|
||||
function onPluginCrashedHangUI(aEvent) {
|
||||
ok(true, "Plugin crashed notification received");
|
||||
is(aEvent.type, "PluginCrashed", "event is correct type");
|
||||
|
||||
is(p, aEvent.target, "Plugin crashed event target is plugin element");
|
||||
|
||||
ok(aEvent instanceof Components.interfaces.nsIDOMDataContainerEvent,
|
||||
"plugin crashed event has the right interface");
|
||||
|
||||
var minidumpID = aEvent.getData("minidumpID");
|
||||
isnot(minidumpID, "", "got a non-empty dump ID");
|
||||
var pluginName = aEvent.getData("pluginName");
|
||||
is(pluginName, "Test Plug-in", "got correct plugin name");
|
||||
var pluginFilename = aEvent.getData("pluginFilename");
|
||||
isnot(pluginFilename, "", "got a non-empty filename");
|
||||
var didReport = aEvent.getData("submittedCrashReport");
|
||||
// The app itself may or may not have decided to submit the report, so
|
||||
// allow either true or false here.
|
||||
ok((didReport == true || didReport == false), "event said crash report was submitted");
|
||||
os.removeObserver(testObserver, "plugin-crashed");
|
||||
--obsCount;
|
||||
}
|
||||
|
||||
function resetVars() {
|
||||
iframe = document.getElementById('iframe1');
|
||||
p = iframe.contentDocument.getElementById("plugin1");
|
||||
if (obsCount == 0) {
|
||||
os.addObserver(testObserver, "plugin-crashed", true);
|
||||
++obsCount;
|
||||
}
|
||||
iframe.contentDocument.addEventListener("PluginCrashed",
|
||||
onPluginCrashedHangUI,
|
||||
false);
|
||||
}
|
||||
|
||||
function test9b() {
|
||||
hanguiExpect("test9b: Plugin Hang UI is not showing (checkbox)", false);
|
||||
p.stall(STALL_DURATION);
|
||||
hanguiExpect("test9b: Plugin Hang UI is still not showing (checkbox)", false, false, "finishTest");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
function test9a() {
|
||||
resetVars();
|
||||
SpecialPowers.setIntPref(hangUITimeoutPref, 1);
|
||||
SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
|
||||
SpecialPowers.setIntPref(timeoutPref, 45);
|
||||
hanguiContinue("test9a: Continue button works with checkbox", true, "test9b");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
function test9() {
|
||||
window.frameLoaded = test9a;
|
||||
iframe.contentWindow.location.reload();
|
||||
}
|
||||
|
||||
function test8a() {
|
||||
resetVars();
|
||||
SpecialPowers.setIntPref(hangUITimeoutPref, 1);
|
||||
SpecialPowers.setIntPref(hangUIMinDisplayPref, 4);
|
||||
hanguiExpect("test8a: Plugin Hang UI is not showing (disabled due to hangUIMinDisplaySecs)", false, false, "test9");
|
||||
var exceptionThrown = false;
|
||||
try {
|
||||
p.hang();
|
||||
} catch(e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
ok(exceptionThrown, "test8a: Exception thrown from hang() when plugin was terminated");
|
||||
}
|
||||
|
||||
function test8() {
|
||||
window.frameLoaded = test8a;
|
||||
iframe.contentWindow.location.reload();
|
||||
}
|
||||
|
||||
function test7a() {
|
||||
resetVars();
|
||||
SpecialPowers.setIntPref(hangUITimeoutPref, 0);
|
||||
hanguiExpect("test7a: Plugin Hang UI is not showing (disabled)", false, false, "test8");
|
||||
var exceptionThrown = false;
|
||||
try {
|
||||
p.hang();
|
||||
} catch(e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
ok(exceptionThrown, "test7a: Exception thrown from hang() when plugin was terminated");
|
||||
}
|
||||
|
||||
function test7() {
|
||||
window.frameLoaded = test7a;
|
||||
iframe.contentWindow.location.reload();
|
||||
}
|
||||
|
||||
function test6() {
|
||||
SpecialPowers.setIntPref(hangUITimeoutPref, 1);
|
||||
SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
|
||||
SpecialPowers.setIntPref(timeoutPref, 3);
|
||||
hanguiExpect("test6: Plugin Hang UI is showing", true, true, "test7");
|
||||
var exceptionThrown = false;
|
||||
try {
|
||||
p.hang();
|
||||
} catch(e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
ok(exceptionThrown, "test6: Exception thrown from hang() when plugin was terminated (child timeout)");
|
||||
}
|
||||
|
||||
function test5a() {
|
||||
resetVars();
|
||||
hanguiCancel("test5a: Close button works", "test6");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
function test5() {
|
||||
window.frameLoaded = test5a;
|
||||
iframe.contentWindow.location.reload();
|
||||
}
|
||||
|
||||
function test4() {
|
||||
hanguiStop("test4: Stop button works", false);
|
||||
// We'll get an exception here because the plugin was terminated
|
||||
var exceptionThrown = false;
|
||||
try {
|
||||
p.hang();
|
||||
} catch(e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
ok(exceptionThrown, "test4: Exception thrown from hang() when plugin was terminated");
|
||||
SimpleTest.executeSoon(test5);
|
||||
}
|
||||
|
||||
function test3() {
|
||||
hanguiContinue("test3: Continue button works", false, "test4");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
// This test is identical to test1 because there were some bugs where the
|
||||
// Hang UI would show on the first hang but not on subsequent hangs
|
||||
hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
function test1() {
|
||||
SpecialPowers.setIntPref(hangUITimeoutPref, 1);
|
||||
SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
|
||||
SpecialPowers.setIntPref(timeoutPref, 45);
|
||||
hanguiExpect("test1: Plugin Hang UI is showing", true, true, "test2");
|
||||
p.stall(STALL_DURATION);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
@ -147,7 +147,6 @@ static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCoun
|
||||
static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
|
||||
@ -211,7 +210,6 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
|
||||
"asyncCallbackTest",
|
||||
"checkGCRace",
|
||||
"hang",
|
||||
"stall",
|
||||
"getClipboardText",
|
||||
"callOnDestroy",
|
||||
"reinitWidget",
|
||||
@ -276,7 +274,6 @@ static const ScriptableFunction sPluginMethodFunctions[] = {
|
||||
asyncCallbackTest,
|
||||
checkGCRace,
|
||||
hangPlugin,
|
||||
stallPlugin,
|
||||
getClipboardText,
|
||||
callOnDestroy,
|
||||
reinitWidget,
|
||||
@ -3317,24 +3314,6 @@ hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
||||
NPVariant* result)
|
||||
{
|
||||
uint32_t stallTimeSeconds = 0;
|
||||
if ((argCount == 1) && NPVARIANT_IS_INT32(args[0])) {
|
||||
stallTimeSeconds = (uint32_t) NPVARIANT_TO_INT32(args[0]);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
Sleep(stallTimeSeconds * 1000U);
|
||||
#else
|
||||
sleep(stallTimeSeconds);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
bool
|
||||
getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
NS_DECL_NSIDOMTELEPHONY
|
||||
NS_DECL_NSITELEPHONYLISTENER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
|
||||
Telephony,
|
||||
nsDOMEventTargetHelper)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user