Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-04-17 12:45:52 -04:00
commit 73ef0db47a
986 changed files with 5692 additions and 4444 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -1,6 +1,6 @@
[{
"size": 634920651,
"digest": "731237d9fcd51637e1fdb7240f57d11f1bda18770025186c06ff72e960551c764bada3c43bae2347f716acd36492c2f4e6bb8eddd9ced7198cbcd8c994ea0705",
"size": 647503948,
"digest": "9ba4f195052e0d5eaae734375aed52f52b7b3337fa8caf01a61830529266e282be19697095c88135379c984d7242ec36b384cf81155176bb6527e6621f32eed3",
"algorithm": "sha512",
"filename": "emulator.zip"
}]

View File

@ -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 {

View File

@ -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>

View File

@ -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

View File

@ -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,

View File

@ -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.
});
},

View File

@ -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);
},

View File

@ -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()

View File

@ -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;
}

View File

@ -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;
/**

View File

@ -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();
}

View File

@ -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
//-----------------------------------------------------------------------------

View File

@ -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();

View File

@ -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)
{

View File

@ -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

View File

@ -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)

View File

@ -41,7 +41,7 @@ public:
NS_DECL_NSIDOMFILEREADER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR

View File

@ -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();
}

View File

@ -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,

View File

@ -91,6 +91,7 @@ public:
aWantsUntrusted,
optional_argc);
}
using nsDOMEventTargetHelper::AddEventListener;
virtual nsIScriptObjectPrincipal* GetObjectPrincipal() { return this; }
virtual JSContext* GetJSContextForEventHandlers() { return mCx; }

View File

@ -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,

View File

@ -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)

View File

@ -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();

View File

@ -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);
};

View 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

View File

@ -15,6 +15,7 @@ LIBXUL_LIBRARY = 1
FAIL_ON_WARNINGS = 1
CPPSRCS = \
EventTarget.cpp \
nsEventListenerManager.cpp \
nsEventStateManager.cpp \
nsDOMEvent.cpp \

View File

@ -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,

View File

@ -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_

View File

@ -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()) {

View File

@ -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,

View File

@ -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),

View File

@ -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();
}

View File

@ -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 \

View File

@ -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>

View 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);
}
}
}

View 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_ */

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View 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);
}
}
}

View 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_ */

View 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);
}
}
}

View 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_ */

View File

@ -74,3 +74,9 @@ EXPORTS += [
'VorbisUtils.h',
]
EXPORTS.mozilla.dom += [
'AudioStreamTrack.h',
'MediaStreamTrack.h',
'VideoStreamTrack.h',
]

View File

@ -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)

View File

@ -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" }
];

View File

@ -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>

View 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>

View File

@ -35,7 +35,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
nsISupports* GetParentObject() const;

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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() ?

View File

@ -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) {

View File

@ -116,6 +116,8 @@ public:
static bool sMouseFocusesFormControl;
static bool ThemeDisplaysFocusForContent(nsIContent* aContent);
protected:
nsFocusManager();

View File

@ -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);

View File

@ -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

View File

@ -34,7 +34,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMSCREEN
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
nsPIDOMWindow* GetParentObject() const
{

View File

@ -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,

View File

@ -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

View File

@ -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',

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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") {

View File

@ -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();
}

View File

@ -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();

View File

@ -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,

View File

@ -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);

View File

@ -30,7 +30,7 @@ public:
NS_DECL_NSIDOMMOZICCMANAGER
NS_DECL_NSIICCLISTENER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
IccManager();

View File

@ -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,

View File

@ -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);
}
};

View File

@ -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 \

View File

@ -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>

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -29,7 +29,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMMOZCONNECTION
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
Connection();

View File

@ -37,7 +37,7 @@ public:
NS_DECL_NSIDOMMOZMOBILECONNECTION
NS_DECL_NSIMOBILECONNECTIONLISTENER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
MobileConnection();

View File

@ -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));

View File

@ -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;

View File

@ -308,7 +308,6 @@ PluginHangUIChild::HangUIDlgProc(HWND aDlgHandle, UINT aMsgCode, WPARAM aWParam,
}
case WM_DESTROY: {
EnableWindow(mParentWindow, TRUE);
SetForegroundWindow(mParentWindow);
break;
}
default:

View File

@ -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

View File

@ -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;
};

View File

@ -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;

View File

@ -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);
};

View File

@ -1,4 +0,0 @@
<html>
<body onload="window.parent.frameLoaded()">
<embed id="plugin1" type="application/x-test" width="400" height="400"></embed>

View File

@ -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>

View File

@ -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,

View File

@ -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