mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
a1d46b7914
@ -34,6 +34,7 @@
|
||||
#include "nsITreeBoxObject.h"
|
||||
#include "nsITreeColumns.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLLabelElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -41,6 +42,16 @@ using namespace mozilla;
|
||||
// nsCoreUtils
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
nsCoreUtils::IsLabelWithControl(nsIContent* aContent)
|
||||
{
|
||||
dom::HTMLLabelElement* label = dom::HTMLLabelElement::FromContent(aContent);
|
||||
if (label && label->GetControl())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsCoreUtils::HasClickListener(nsIContent *aContent)
|
||||
{
|
||||
|
@ -28,6 +28,11 @@ class nsIWidget;
|
||||
class nsCoreUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Return true if the given node is a label of a control.
|
||||
*/
|
||||
static bool IsLabelWithControl(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Return true if the given node has registered click, mousedown or mouseup
|
||||
* event listeners.
|
||||
|
@ -115,13 +115,14 @@ LinkableAccessible::Value(nsString& aValue)
|
||||
uint8_t
|
||||
LinkableAccessible::ActionCount()
|
||||
{
|
||||
bool isLink, isOnclick;
|
||||
ActionWalk(&isLink, &isOnclick);
|
||||
return (isLink || isOnclick) ? 1 : 0;
|
||||
bool isLink, isOnclick, isLabelWithControl;
|
||||
ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
|
||||
return (isLink || isOnclick || isLabelWithControl) ? 1 : 0;
|
||||
}
|
||||
|
||||
Accessible*
|
||||
LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
|
||||
LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick,
|
||||
bool* aIsLabelWithControl)
|
||||
{
|
||||
if (aIsOnclick) {
|
||||
*aIsOnclick = false;
|
||||
@ -129,6 +130,9 @@ LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
|
||||
if (aIsLink) {
|
||||
*aIsLink = false;
|
||||
}
|
||||
if (aIsLabelWithControl) {
|
||||
*aIsLabelWithControl = false;
|
||||
}
|
||||
|
||||
if (nsCoreUtils::HasClickListener(mContent)) {
|
||||
if (aIsOnclick) {
|
||||
@ -155,6 +159,13 @@ LinkableAccessible::ActionWalk(bool* aIsLink, bool* aIsOnclick)
|
||||
}
|
||||
return walkUpAcc;
|
||||
}
|
||||
|
||||
if (nsCoreUtils::IsLabelWithControl(walkUpAcc->GetContent())) {
|
||||
if (aIsLabelWithControl) {
|
||||
*aIsLabelWithControl = true;
|
||||
}
|
||||
return walkUpAcc;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -166,11 +177,11 @@ LinkableAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
|
||||
|
||||
// Action 0 (default action): Jump to link
|
||||
if (aIndex == eAction_Jump) {
|
||||
bool isOnclick, isLink;
|
||||
ActionWalk(&isLink, &isOnclick);
|
||||
bool isOnclick, isLink, isLabelWithControl;
|
||||
ActionWalk(&isLink, &isOnclick, &isLabelWithControl);
|
||||
if (isLink) {
|
||||
aName.AssignLiteral("jump");
|
||||
} else if (isOnclick) {
|
||||
} else if (isOnclick || isLabelWithControl) {
|
||||
aName.AssignLiteral("click");
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,8 @@ public:
|
||||
|
||||
// ActionAccessible helpers
|
||||
Accessible* ActionWalk(bool* aIsLink = nullptr,
|
||||
bool* aIsOnclick = nullptr);
|
||||
bool* aIsOnclick = nullptr,
|
||||
bool* aIsLabelWithControl = nullptr);
|
||||
// HyperLinkAccessible
|
||||
virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex) override;
|
||||
|
||||
|
@ -75,6 +75,32 @@ HTMLLabelAccessible::RelationByType(RelationType aType)
|
||||
return rel;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
HTMLLabelAccessible::ActionCount()
|
||||
{
|
||||
return nsCoreUtils::IsLabelWithControl(mContent) ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLabelAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
|
||||
{
|
||||
if (aIndex == 0) {
|
||||
if (nsCoreUtils::IsLabelWithControl(mContent))
|
||||
aName.AssignLiteral("click");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLabelAccessible::DoAction(uint8_t aIndex)
|
||||
{
|
||||
if (aIndex != 0)
|
||||
return false;
|
||||
|
||||
DoCommand();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsHTMLOuputAccessible
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -62,6 +62,11 @@ public:
|
||||
// Accessible
|
||||
virtual Relation RelationByType(RelationType aType) override;
|
||||
|
||||
// ActionAccessible
|
||||
virtual uint8_t ActionCount() override;
|
||||
virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
|
||||
virtual bool DoAction(uint8_t aIndex) override;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLLabelAccessible() {}
|
||||
virtual ENameValueFlag NativeName(nsString& aName) override;
|
||||
|
@ -39,11 +39,19 @@
|
||||
ID: "onclick_img",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "label1",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
testActions(actionsArray);
|
||||
|
||||
is(getAccessible("label1").firstChild.actionCount, 1, "label text should have 1 action");
|
||||
|
||||
getAccessible("onclick_img").takeFocus();
|
||||
is(getAccessible("link1").actionCount, 1, "links should have one action");
|
||||
is(getAccessible("link2").actionCount, 1, "link with onclick handler should have 1 action");
|
||||
@ -87,5 +95,13 @@
|
||||
|
||||
<a id="link1" href="www">linkable textleaf accessible</a>
|
||||
<div id="link2" onclick="">linkable textleaf accessible</div>
|
||||
|
||||
<div>
|
||||
<label for="TextBox_t2" id="label1">
|
||||
<span>Explicit</span>
|
||||
</label>
|
||||
<input name="in2" id="TextBox_t2" type="text" maxlength="17">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -60,6 +60,11 @@
|
||||
actionName: "press",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "name_entry_label",
|
||||
actionName: "click",
|
||||
events: CLICK_EVENTS
|
||||
},
|
||||
{
|
||||
ID: "labelWithPopup",
|
||||
actionName: "click",
|
||||
@ -72,6 +77,8 @@
|
||||
}*/
|
||||
];
|
||||
|
||||
is(getAccessible("name_entry_label").firstChild.actionCount, 1, "label text should have 1 action");
|
||||
|
||||
testActions(actionsArray);
|
||||
}
|
||||
|
||||
@ -125,6 +132,10 @@
|
||||
<label id="labelWithPopup" value="file name"
|
||||
popup="fileContext"
|
||||
tabindex="0"/>
|
||||
<hbox>
|
||||
<label id="name_entry_label" value="Name" control="name_entry"/>
|
||||
<textbox id="name_entry"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</window>
|
||||
|
@ -252,7 +252,9 @@ ReserveFileDescriptors(FdArray& aReservedFds)
|
||||
MOZ_CRASH("ProcLoader error: failed to reserve a magic file descriptor.");
|
||||
}
|
||||
|
||||
aReservedFds.append(target);
|
||||
if (!aReservedFds.append(target)) {
|
||||
MOZ_CRASH("Failed to append to aReservedFds");
|
||||
}
|
||||
|
||||
if (fd == target) {
|
||||
// No need to call dup2(). We already occupy the desired file descriptor.
|
||||
|
@ -10,6 +10,7 @@ var Cc = Components.classes;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NotificationDB.jsm");
|
||||
Cu.import("resource:///modules/RecentWindow.jsm");
|
||||
Cu.import("resource:///modules/UserContextUI.jsm");
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
|
||||
@ -4059,24 +4060,7 @@ function updateUserContextUIIndicator(browser)
|
||||
let label = document.getElementById("userContext-label");
|
||||
let userContextId = browser.getAttribute("usercontextid");
|
||||
hbox.setAttribute("usercontextid", userContextId);
|
||||
switch (userContextId) {
|
||||
case "1":
|
||||
label.value = gBrowserBundle.GetStringFromName("usercontext.personal.label");
|
||||
break;
|
||||
case "2":
|
||||
label.value = gBrowserBundle.GetStringFromName("usercontext.work.label");
|
||||
break;
|
||||
case "3":
|
||||
label.value = gBrowserBundle.GetStringFromName("usercontext.banking.label");
|
||||
break;
|
||||
case "4":
|
||||
label.value = gBrowserBundle.GetStringFromName("usercontext.shopping.label");
|
||||
break;
|
||||
// Display the context IDs for values outside the pre-defined range.
|
||||
// Used for debugging, no localization necessary.
|
||||
default:
|
||||
label.value = "Context " + userContextId;
|
||||
}
|
||||
label.value = UserContextUI.getUserContextLabel(userContextId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -758,7 +758,7 @@
|
||||
if (this.mBrowser.userTypedClear > 0 ||
|
||||
((aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) &&
|
||||
aLocation.spec != "about:blank") ||
|
||||
aFlags && Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
|
||||
aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
|
||||
this.mBrowser.userTypedValue = null;
|
||||
}
|
||||
|
||||
|
@ -417,7 +417,7 @@ skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
|
||||
# Disabled on OS X because of bug 967917
|
||||
[browser_tabfocus.js]
|
||||
[browser_tabkeynavigation.js]
|
||||
skip-if = e10s
|
||||
skip-if = (os == "mac" && !e10s)
|
||||
[browser_tabopen_reflows.js]
|
||||
[browser_tabs_close_beforeunload.js]
|
||||
support-files =
|
||||
|
@ -42,23 +42,19 @@ function test() {
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
|
||||
browser1.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+Tab on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+Tab on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
|
||||
browser3.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+Shift+Tab on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true });
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+Shift+Tab on Tab2");
|
||||
|
||||
@ -67,23 +63,19 @@ function test() {
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
|
||||
browser1.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+PageDown on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+PageDown on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
|
||||
browser3.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+PageUp on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true });
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+PageUp on Tab2");
|
||||
|
||||
@ -98,23 +90,19 @@ function test() {
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
|
||||
browser1.contentWindow);
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true });
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
|
||||
browser3.contentWindow);
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true });
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
|
||||
}
|
||||
@ -125,15 +113,13 @@ function test() {
|
||||
is(gBrowser.tabContainer.selectedIndex, 2,
|
||||
"Tab2 index should be 2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true, shiftKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated after Ctrl+Shift+PageDown");
|
||||
is(gBrowser.tabContainer.selectedIndex, 3,
|
||||
"Tab2 index should be 1 after Ctrl+Shift+PageDown");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true, shiftKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated after Ctrl+Shift+PageUp");
|
||||
is(gBrowser.tabContainer.selectedIndex, 2,
|
||||
@ -153,45 +139,38 @@ function test() {
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true },
|
||||
browser1.contentWindow);
|
||||
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true },
|
||||
browser2.contentWindow);
|
||||
todo_is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true });
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
|
||||
|
||||
if (gBrowser.selectedTab != tab3) {
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true },
|
||||
browser3.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
|
||||
}
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true });
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true },
|
||||
browser2.contentWindow);
|
||||
todo_is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true });
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
|
||||
} else {
|
||||
gBrowser.selectedTab = tab2;
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keydown", ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keydown", ctrlKey: true });
|
||||
|
||||
isnot(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be closed by pressing Ctrl+F4 on Tab2");
|
||||
is(gBrowser.tabs.length, 3,
|
||||
"The count of tabs should be 3 since tab2 should be closed");
|
||||
"The count of tabs should be 3 since tab2 should be closed");
|
||||
|
||||
let activeWindow =
|
||||
gBrowser.getBrowserForTab(gBrowser.selectedTab).contentWindow;
|
||||
// NOTE: keypress event shouldn't be fired since the keydown event should
|
||||
// be consumed by tab2.
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keyup", ctrlKey: true },
|
||||
activeWindow);
|
||||
is(gBrowser.tabs.length, 3,
|
||||
"The count of tabs should be 3 since renaming key events shouldn't close other tabs");
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keyup", ctrlKey: true });
|
||||
is(gBrowser.tabs.length, 3,
|
||||
"The count of tabs should be 3 since renaming key events shouldn't close other tabs");
|
||||
}
|
||||
|
||||
gBrowser.selectedTab = tab3;
|
||||
|
@ -15,30 +15,22 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
|
||||
"@mozilla.org/browser/aboutnewtab-service;1",
|
||||
"nsIAboutNewTabService");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||
"resource://gre/modules/Deprecated.jsm");
|
||||
|
||||
const DepecationURL = "https://bugzilla.mozilla.org/show_bug.cgi?id=1204983#c89";
|
||||
|
||||
this.NewTabURL = {
|
||||
|
||||
get: function() {
|
||||
Deprecated.warning("NewTabURL.get is deprecated, please query aboutNewTabService.newTabURL", DepecationURL);
|
||||
return aboutNewTabService.newTabURL;
|
||||
},
|
||||
|
||||
get overridden() {
|
||||
Deprecated.warning("NewTabURL.overridden is deprecated, please query aboutNewTabService.overridden", DepecationURL);
|
||||
return aboutNewTabService.overridden;
|
||||
},
|
||||
|
||||
override: function(newURL) {
|
||||
Deprecated.warning("NewTabURL.override is deprecated, please set aboutNewTabService.newTabURL", DepecationURL);
|
||||
aboutNewTabService.newTabURL = newURL;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
Deprecated.warning("NewTabURL.reset is deprecated, please use aboutNewTabService.resetNewTabURL()", DepecationURL);
|
||||
aboutNewTabService.resetNewTabURL();
|
||||
}
|
||||
};
|
||||
|
@ -2974,9 +2974,6 @@ var DefaultBrowserCheck = {
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
var E10SUINotification = {
|
||||
// Increase this number each time we want to roll out an
|
||||
// e10s testing period to Nightly users.
|
||||
CURRENT_NOTICE_COUNT: 4,
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
@ -3007,20 +3004,7 @@ var E10SUINotification = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Services.appinfo.browserTabsRemoteAutostart) {
|
||||
if (this.forcedOn) {
|
||||
return;
|
||||
}
|
||||
let notice = 0;
|
||||
try {
|
||||
notice = Services.prefs.getIntPref("browser.displayedE10SNotice");
|
||||
} catch(e) {}
|
||||
let activationNoticeShown = notice >= this.CURRENT_NOTICE_COUNT;
|
||||
|
||||
if (!activationNoticeShown) {
|
||||
this._showE10sActivatedNotice();
|
||||
}
|
||||
} else {
|
||||
if (!Services.appinfo.browserTabsRemoteAutostart) {
|
||||
let displayFeedbackRequest = false;
|
||||
try {
|
||||
displayFeedbackRequest = Services.prefs.getBoolPref("browser.requestE10sFeedback");
|
||||
@ -3032,10 +3016,6 @@ var E10SUINotification = {
|
||||
return;
|
||||
}
|
||||
|
||||
// The user has just voluntarily disabled e10s. Subtract one from displayedE10SNotice
|
||||
// so that the next time e10s is activated (either by the user or forced by us), they
|
||||
// can see the notice again.
|
||||
Services.prefs.setIntPref("browser.displayedE10SNotice", this.CURRENT_NOTICE_COUNT - 1);
|
||||
Services.prefs.clearUserPref("browser.requestE10sFeedback");
|
||||
|
||||
let url = Services.urlFormatter.formatURLPref("app.feedback.baseURL");
|
||||
@ -3084,32 +3064,6 @@ var E10SUINotification = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
|
||||
_showE10sActivatedNotice: function() {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (!win)
|
||||
return;
|
||||
|
||||
Services.prefs.setIntPref("browser.displayedE10SNotice", this.CURRENT_NOTICE_COUNT);
|
||||
|
||||
let nb = win.document.getElementById("high-priority-global-notificationbox");
|
||||
let message = win.gNavigatorBundle.getFormattedString(
|
||||
"e10s.postActivationInfobar.message",
|
||||
[gBrandBundle.GetStringFromName("brandShortName")]
|
||||
);
|
||||
let buttons = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("e10s.postActivationInfobar.learnMore.label"),
|
||||
accessKey: win.gNavigatorBundle.getString("e10s.postActivationInfobar.learnMore.accesskey"),
|
||||
callback: function () {
|
||||
win.openUILinkIn("https://wiki.mozilla.org/Electrolysis", "tab");
|
||||
}
|
||||
}
|
||||
];
|
||||
nb.appendNotification(message, "e10s-activated-noticed",
|
||||
null, nb.PRIORITY_WARNING_MEDIUM, buttons);
|
||||
|
||||
},
|
||||
|
||||
_showE10SPrompt: function BG__showE10SPrompt() {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (!win)
|
||||
|
@ -6,6 +6,8 @@
|
||||
const nsICookie = Components.interfaces.nsICookie;
|
||||
|
||||
Components.utils.import("resource://gre/modules/PluralForm.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm")
|
||||
Components.utils.import("resource:///modules/UserContextUI.jsm");
|
||||
|
||||
var gCookiesWindow = {
|
||||
_cm : Components.classes["@mozilla.org/cookiemanager;1"]
|
||||
@ -29,6 +31,10 @@ var gCookiesWindow = {
|
||||
this._populateList(true);
|
||||
|
||||
document.getElementById("filter").focus();
|
||||
|
||||
if (!Services.prefs.getBoolPref("privacy.userContext.enabled")) {
|
||||
document.getElementById("userContextRow").hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
@ -453,16 +459,17 @@ var gCookiesWindow = {
|
||||
_makeCookieObject: function (aStrippedHost, aCookie) {
|
||||
var host = aCookie.host;
|
||||
var formattedHost = host.charAt(0) == "." ? host.substring(1, host.length) : host;
|
||||
var c = { name : aCookie.name,
|
||||
value : aCookie.value,
|
||||
isDomain : aCookie.isDomain,
|
||||
host : aCookie.host,
|
||||
rawHost : aStrippedHost,
|
||||
path : aCookie.path,
|
||||
isSecure : aCookie.isSecure,
|
||||
expires : aCookie.expires,
|
||||
level : 1,
|
||||
container : false };
|
||||
var c = { name : aCookie.name,
|
||||
value : aCookie.value,
|
||||
isDomain : aCookie.isDomain,
|
||||
host : aCookie.host,
|
||||
rawHost : aStrippedHost,
|
||||
path : aCookie.path,
|
||||
isSecure : aCookie.isSecure,
|
||||
expires : aCookie.expires,
|
||||
level : 1,
|
||||
container : false,
|
||||
originAttributes: aCookie.originAttributes };
|
||||
return c;
|
||||
},
|
||||
|
||||
@ -500,7 +507,7 @@ var gCookiesWindow = {
|
||||
|
||||
_updateCookieData: function (aItem) {
|
||||
var seln = this._view.selection;
|
||||
var ids = ["name", "value", "host", "path", "isSecure", "expires"];
|
||||
var ids = ["name", "value", "host", "path", "isSecure", "expires", "userContext"];
|
||||
var properties;
|
||||
|
||||
if (aItem && !aItem.container && seln.count > 0) {
|
||||
@ -509,17 +516,20 @@ var gCookiesWindow = {
|
||||
isDomain: aItem.isDomain ? this._bundle.getString("domainColon")
|
||||
: this._bundle.getString("hostColon"),
|
||||
isSecure: aItem.isSecure ? this._bundle.getString("forSecureOnly")
|
||||
: this._bundle.getString("forAnyConnection") };
|
||||
for (var i = 0; i < ids.length; ++i)
|
||||
: this._bundle.getString("forAnyConnection"),
|
||||
userContext: UserContextUI.getUserContextLabel(aItem.originAttributes.userContextId) };
|
||||
for (var i = 0; i < ids.length; ++i) {
|
||||
document.getElementById(ids[i]).disabled = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var noneSelected = this._bundle.getString("noCookieSelected");
|
||||
properties = { name: noneSelected, value: noneSelected, host: noneSelected,
|
||||
path: noneSelected, expires: noneSelected,
|
||||
isSecure: noneSelected };
|
||||
for (i = 0; i < ids.length; ++i)
|
||||
isSecure: noneSelected, userContext: noneSelected };
|
||||
for (i = 0; i < ids.length; ++i) {
|
||||
document.getElementById(ids[i]).disabled = true;
|
||||
}
|
||||
}
|
||||
for (var property in properties)
|
||||
document.getElementById(property).value = properties[property];
|
||||
|
@ -85,6 +85,10 @@
|
||||
<hbox pack="end"><label id="expiresLabel" control="expires" value="&props.expires.label;"/></hbox>
|
||||
<textbox id="expires" readonly="true" class="plain"/>
|
||||
</row>
|
||||
<row align="center" id="userContextRow">
|
||||
<hbox pack="end"><label id="userContextLabel" control="userContext" value="&props.container.label;"/></hbox>
|
||||
<textbox id="userContext" readonly="true" class="plain"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</hbox>
|
||||
|
@ -746,9 +746,6 @@ appMenuRemoteTabs.mobilePromo.ios = Firefox for iOS
|
||||
# e10s.offerPopup.enableAndRestart.accesskey
|
||||
# e10s.offerPopup.noThanks.label
|
||||
# e10s.offerPopup.noThanks.accesskey
|
||||
# e10s.postActivationInfobar.message
|
||||
# e10s.postActivationInfobar.learnMore.label
|
||||
# e10s.postActivationInfobar.learnMore.accesskey
|
||||
# e10s.accessibilityNotice.mainMessage
|
||||
# e10s.accessibilityNotice.enableAndRestart.label
|
||||
# e10s.accessibilityNotice.enableAndRestart.accesskey
|
||||
@ -763,9 +760,6 @@ e10s.offerPopup.enableAndRestart.label = Enable and Restart
|
||||
e10s.offerPopup.enableAndRestart.accesskey = E
|
||||
e10s.offerPopup.noThanks.label = No, thanks
|
||||
e10s.offerPopup.noThanks.accesskey = N
|
||||
e10s.postActivationInfobar.message = You're now helping to test multi-process in %S! Please report problems you find.
|
||||
e10s.postActivationInfobar.learnMore.label = Learn More
|
||||
e10s.postActivationInfobar.learnMore.accesskey = L
|
||||
e10s.accessibilityNotice.mainMessage2 = Accessibility support is partially disabled due to compatibility issues with new %S features.
|
||||
e10s.accessibilityNotice.acceptButton.label = OK
|
||||
e10s.accessibilityNotice.acceptButton.accesskey = O
|
||||
|
@ -21,6 +21,7 @@
|
||||
<!ENTITY props.path.label "Path:">
|
||||
<!ENTITY props.secure.label "Send For:">
|
||||
<!ENTITY props.expires.label "Expires:">
|
||||
<!ENTITY props.container.label "Container:">
|
||||
|
||||
<!ENTITY window.title "Cookies">
|
||||
<!ENTITY windowClose.key "w">
|
||||
|
32
browser/modules/UserContextUI.jsm
Normal file
32
browser/modules/UserContextUI.jsm
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["UserContextUI"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
||||
return Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
});
|
||||
|
||||
this.UserContextUI = {
|
||||
getUserContextLabel(userContextId) {
|
||||
switch (userContextId) {
|
||||
// No UserContext:
|
||||
case 0: return "";
|
||||
|
||||
case 1: return gBrowserBundle.GetStringFromName("usercontext.personal.label");
|
||||
case 2: return gBrowserBundle.GetStringFromName("usercontext.work.label");
|
||||
case 3: return gBrowserBundle.GetStringFromName("usercontext.shopping.label");
|
||||
case 4: return gBrowserBundle.GetStringFromName("usercontext.banking.label");
|
||||
|
||||
// Display the context IDs for values outside the pre-defined range.
|
||||
// Used for debugging, no localization necessary.
|
||||
default: return "Context " + userContextId;
|
||||
}
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ EXTRA_JS_MODULES += [
|
||||
'Social.jsm',
|
||||
'TabGroupsMigrator.jsm',
|
||||
'TransientPrefs.jsm',
|
||||
'UserContextUI.jsm',
|
||||
'WebappManager.jsm',
|
||||
'webrtcUI.jsm',
|
||||
]
|
||||
|
@ -364,13 +364,25 @@ BasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
BasePrincipal::EnsureCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aCSP)
|
||||
{
|
||||
if (mCSP) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
// if there is a CSP already associated with this principal
|
||||
// then just return that - do not overwrite it!!!
|
||||
NS_IF_ADDREF(*aCSP = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCSP = aCsp;
|
||||
nsresult rv = NS_OK;
|
||||
mCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context for violation reports
|
||||
rv = aDocument ? mCSP->SetRequestContext(aDocument, nullptr)
|
||||
: mCSP->SetRequestContext(nullptr, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_IF_ADDREF(*aCSP = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -382,12 +394,25 @@ BasePrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP)
|
||||
BasePrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aPreloadCSP)
|
||||
{
|
||||
if (mPreloadCSP) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
// if there is a speculative CSP already associated with this principal
|
||||
// then just return that - do not overwrite it!!!
|
||||
NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
mPreloadCSP = aPreloadCSP;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
mPreloadCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context for violation reports
|
||||
rv = aDocument ? mPreloadCSP->SetRequestContext(aDocument, nullptr)
|
||||
: mPreloadCSP->SetRequestContext(nullptr, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -202,9 +202,9 @@ public:
|
||||
NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
|
||||
NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
|
||||
NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
|
||||
NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
|
||||
NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override;
|
||||
NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
|
||||
NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
|
||||
|
@ -15,12 +15,13 @@ struct JSPrincipals;
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIContentSecurityPolicy;
|
||||
interface nsIDOMDocument;
|
||||
|
||||
[ptr] native JSContext(JSContext);
|
||||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
|
||||
[scriptable, builtinclass, uuid(188fc4a2-3157-4956-a7a2-d674991770da)]
|
||||
[scriptable, builtinclass, uuid(d0391e86-1ad7-4ab0-bb7c-14d6d9967369)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
@ -133,12 +134,19 @@ interface nsIPrincipal : nsISerializable
|
||||
/**
|
||||
* A Content Security Policy associated with this principal.
|
||||
*
|
||||
* Please note that if a csp was already set on the
|
||||
* principal, then it should not be destroyed! Instead, the
|
||||
* current csp should be quried and extended by
|
||||
* calling AppendPolicy() on it.
|
||||
* Use this function to query the associated CSP with this principal.
|
||||
*/
|
||||
[noscript] attribute nsIContentSecurityPolicy csp;
|
||||
[noscript] readonly attribute nsIContentSecurityPolicy csp;
|
||||
|
||||
/*
|
||||
* Use this function to query a CSP associated with this principal.
|
||||
* If no CSP is associated with this principal then one is created
|
||||
* internally and setRequestContext is called on the CSP using aDocument.
|
||||
*
|
||||
* Please note if aDocument is null, then setRequestContext on the
|
||||
* CSP object is called using the current principal.
|
||||
*/
|
||||
[noscript] nsIContentSecurityPolicy ensureCSP(in nsIDOMDocument aDocument);
|
||||
|
||||
/**
|
||||
* A speculative Content Security Policy associated with this
|
||||
@ -147,13 +155,19 @@ interface nsIPrincipal : nsISerializable
|
||||
*
|
||||
* If you want to query the CSP associated with that principal,
|
||||
* then this is *not* what you want. Instead query 'csp'.
|
||||
*
|
||||
* Please note that if a preloadCSP was already set on the
|
||||
* principal, then it should not be destroyed! Instead, the
|
||||
* current preloadCSP should be quried and extended by
|
||||
* calling AppendPolicy() on it.
|
||||
*/
|
||||
[noscript] attribute nsIContentSecurityPolicy preloadCsp;
|
||||
[noscript] readonly attribute nsIContentSecurityPolicy preloadCsp;
|
||||
|
||||
/*
|
||||
* Use this function to query a speculative CSP associated with this
|
||||
* principal. If no speculative CSP is associated with this principal
|
||||
* then one is created internally and setRequestContext is called on
|
||||
* the CSP using aDocument.
|
||||
*
|
||||
* Please note if aDocument is null, then setRequestContext on the
|
||||
* speculative CSP object is called using the current principal.
|
||||
*/
|
||||
[noscript] nsIContentSecurityPolicy ensurePreloadCSP(in nsIDOMDocument aDocument);
|
||||
|
||||
/**
|
||||
* The CSP of the principal in JSON notation.
|
||||
|
@ -398,19 +398,14 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
|
||||
rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This may be null.
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp = do_QueryInterface(supports, &rv);
|
||||
|
||||
rv = Init(codebase, attrs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// need to link in the CSP context here (link in the URI of the protected
|
||||
// resource).
|
||||
if (csp) {
|
||||
csp->SetRequestContext(nullptr, this);
|
||||
mCSP = do_QueryInterface(supports, &rv);
|
||||
// make sure setRequestContext is called after Init(),
|
||||
// to make sure the principals URI been initalized.
|
||||
if (mCSP) {
|
||||
mCSP->SetRequestContext(nullptr, this);
|
||||
}
|
||||
|
||||
SetDomain(domain);
|
||||
|
@ -70,7 +70,8 @@ nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aCSP)
|
||||
{
|
||||
// CSP on a system principal makes no sense
|
||||
return NS_OK;
|
||||
@ -84,7 +85,8 @@ nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP)
|
||||
nsSystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aPreloadCSP)
|
||||
{
|
||||
// CSP on a system principal makes no sense
|
||||
return NS_OK;
|
||||
|
@ -30,9 +30,9 @@ public:
|
||||
NS_IMETHOD GetDomain(nsIURI** aDomain) override;
|
||||
NS_IMETHOD SetDomain(nsIURI* aDomain) override;
|
||||
NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
|
||||
NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
|
||||
NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
|
||||
NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override;
|
||||
NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
nsresult GetOriginInternal(nsACString& aOrigin) override;
|
||||
|
||||
|
@ -1187,7 +1187,7 @@ Animation::EffectEnd() const
|
||||
return StickyTimeDuration(0);
|
||||
}
|
||||
|
||||
return mEffect->Timing().mDelay
|
||||
return mEffect->SpecifiedTiming().mDelay
|
||||
+ mEffect->GetComputedTiming().mActiveDuration;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class AnimationEffectTimingReadOnly;
|
||||
struct ComputedTimingProperties;
|
||||
|
||||
class AnimationEffectReadOnly : public nsISupports,
|
||||
@ -30,9 +31,9 @@ public:
|
||||
|
||||
nsISupports* GetParentObject() const { return mParent; }
|
||||
|
||||
virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const
|
||||
{
|
||||
}
|
||||
virtual already_AddRefed<AnimationEffectTimingReadOnly> Timing() const = 0;
|
||||
|
||||
virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~AnimationEffectReadOnly() = default;
|
||||
|
59
dom/animation/AnimationEffectTimingReadOnly.cpp
Normal file
59
dom/animation/AnimationEffectTimingReadOnly.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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/AnimationEffectTimingReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnlyBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
TimingParams&
|
||||
TimingParams::operator=(const dom::AnimationEffectTimingProperties& aRhs)
|
||||
{
|
||||
mDuration = aRhs.mDuration;
|
||||
mDelay = TimeDuration::FromMilliseconds(aRhs.mDelay);
|
||||
mIterations = aRhs.mIterations;
|
||||
mDirection = aRhs.mDirection;
|
||||
mFill = aRhs.mFill;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
TimingParams::operator==(const TimingParams& aOther) const
|
||||
{
|
||||
bool durationEqual;
|
||||
if (mDuration.IsUnrestrictedDouble()) {
|
||||
durationEqual = aOther.mDuration.IsUnrestrictedDouble() &&
|
||||
(mDuration.GetAsUnrestrictedDouble() ==
|
||||
aOther.mDuration.GetAsUnrestrictedDouble());
|
||||
} else {
|
||||
// We consider all string values and uninitialized values as meaning "auto".
|
||||
// Since mDuration is either a string or uninitialized, we consider it equal
|
||||
// if aOther.mDuration is also either a string or uninitialized.
|
||||
durationEqual = !aOther.mDuration.IsUnrestrictedDouble();
|
||||
}
|
||||
return durationEqual &&
|
||||
mDelay == aOther.mDelay &&
|
||||
mIterations == aOther.mIterations &&
|
||||
mDirection == aOther.mDirection &&
|
||||
mFill == aOther.mFill;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectTimingReadOnly, mParent)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AnimationEffectTimingReadOnly, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AnimationEffectTimingReadOnly, Release)
|
||||
|
||||
JSObject*
|
||||
AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
89
dom/animation/AnimationEffectTimingReadOnly.h
Normal file
89
dom/animation/AnimationEffectTimingReadOnly.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 mozilla_dom_AnimationEffectTimingReadOnly_h
|
||||
#define mozilla_dom_AnimationEffectTimingReadOnly_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
// X11 has a #define for None
|
||||
#ifdef None
|
||||
#undef None
|
||||
#endif
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for FillMode
|
||||
// and PlaybackDirection
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct TimingParams
|
||||
{
|
||||
// The unitialized state of mDuration represents "auto".
|
||||
// Bug 1237173: We will replace this with Maybe<TimeDuration>.
|
||||
dom::OwningUnrestrictedDoubleOrString mDuration;
|
||||
TimeDuration mDelay; // Initializes to zero
|
||||
double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
|
||||
dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
|
||||
dom::FillMode mFill = dom::FillMode::Auto;
|
||||
|
||||
TimingParams& operator=(const dom::AnimationEffectTimingProperties& aRhs);
|
||||
|
||||
bool operator==(const TimingParams& aOther) const;
|
||||
bool operator!=(const TimingParams& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AnimationEffectTimingReadOnly : public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
AnimationEffectTimingReadOnly() = default;
|
||||
explicit AnimationEffectTimingReadOnly(const TimingParams& aTiming)
|
||||
: mTiming(aTiming) { }
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AnimationEffectTimingReadOnly)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AnimationEffectTimingReadOnly)
|
||||
|
||||
protected:
|
||||
virtual ~AnimationEffectTimingReadOnly() = default;
|
||||
|
||||
public:
|
||||
nsISupports* GetParentObject() const { return mParent; }
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
double Delay() const { return mTiming.mDelay.ToMilliseconds(); }
|
||||
double EndDelay() const { return 0.0; }
|
||||
FillMode Fill() const { return mTiming.mFill; }
|
||||
double IterationStart() const { return 0.0; }
|
||||
double Iterations() const { return mTiming.mIterations; }
|
||||
void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const
|
||||
{
|
||||
aRetVal = mTiming.mDuration;
|
||||
}
|
||||
PlaybackDirection Direction() const { return mTiming.mDirection; }
|
||||
void GetEasing(nsString& aRetVal) const { aRetVal.AssignLiteral("linear"); }
|
||||
|
||||
const TimingParams& AsTimingParams() const { return mTiming; }
|
||||
void SetTimingParams(const TimingParams& aTiming) { mTiming = aTiming; }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
TimingParams mTiming;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_AnimationEffectTimingReadOnly_h
|
@ -50,4 +50,4 @@ private:
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_AnimationEffectReadOnly_h
|
||||
#endif // mozilla_ComputedTimingFunction_h
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "mozilla/dom/KeyframeEffect.h"
|
||||
|
||||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
|
||||
#include "mozilla/dom/KeyframeEffectBinding.h"
|
||||
#include "mozilla/dom/PropertyIndexedKeyframesBinding.h"
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
@ -24,32 +23,19 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
AnimationTiming::FillsForwards() const
|
||||
{
|
||||
return mFillMode == dom::FillMode::Both ||
|
||||
mFillMode == dom::FillMode::Forwards;
|
||||
}
|
||||
|
||||
bool
|
||||
AnimationTiming::FillsBackwards() const
|
||||
{
|
||||
return mFillMode == dom::FillMode::Both ||
|
||||
mFillMode == dom::FillMode::Backwards;
|
||||
}
|
||||
|
||||
// Helper functions for generating a ComputedTimingProperties dictionary
|
||||
static void
|
||||
GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
|
||||
const Nullable<TimeDuration>& aLocalTime,
|
||||
const AnimationTiming& aTiming,
|
||||
const TimingParams& aTiming,
|
||||
dom::ComputedTimingProperties& aRetVal)
|
||||
{
|
||||
// AnimationEffectTimingProperties
|
||||
aRetVal.mDelay = aTiming.mDelay.ToMilliseconds();
|
||||
aRetVal.mFill = aTiming.mFillMode;
|
||||
aRetVal.mIterations = aTiming.mIterationCount;
|
||||
aRetVal.mDuration.SetAsUnrestrictedDouble() = aTiming.mIterationDuration.ToMilliseconds();
|
||||
aRetVal.mFill = aComputedTiming.mFill;
|
||||
aRetVal.mIterations = aComputedTiming.mIterations;
|
||||
aRetVal.mDuration.SetAsUnrestrictedDouble() =
|
||||
aComputedTiming.mDuration.ToMilliseconds();
|
||||
aRetVal.mDirection = aTiming.mDirection;
|
||||
|
||||
// ComputedTimingProperties
|
||||
@ -89,14 +75,15 @@ KeyframeEffectReadOnly::KeyframeEffectReadOnly(
|
||||
nsIDocument* aDocument,
|
||||
Element* aTarget,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
const AnimationTiming& aTiming)
|
||||
const TimingParams& aTiming)
|
||||
: AnimationEffectReadOnly(aDocument)
|
||||
, mTarget(aTarget)
|
||||
, mTiming(aTiming)
|
||||
, mPseudoType(aPseudoType)
|
||||
, mInEffectOnLastAnimationTimingUpdate(false)
|
||||
{
|
||||
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
|
||||
|
||||
mTiming = new AnimationEffectTimingReadOnly(aTiming);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
@ -118,13 +105,20 @@ KeyframeEffectReadOnly::Composite() const
|
||||
return CompositeOperation::Replace;
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::SetTiming(const AnimationTiming& aTiming)
|
||||
already_AddRefed<AnimationEffectTimingReadOnly>
|
||||
KeyframeEffectReadOnly::Timing() const
|
||||
{
|
||||
if (mTiming == aTiming) {
|
||||
RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
|
||||
return temp.forget();
|
||||
}
|
||||
|
||||
void
|
||||
KeyframeEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming)
|
||||
{
|
||||
if (mTiming->AsTimingParams() == aTiming) {
|
||||
return;
|
||||
}
|
||||
mTiming = aTiming;
|
||||
mTiming->SetTimingParams(aTiming);
|
||||
if (mAnimation) {
|
||||
mAnimation->NotifyEffectTimingUpdated();
|
||||
}
|
||||
@ -205,31 +199,36 @@ void
|
||||
KeyframeEffectReadOnly::GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const
|
||||
{
|
||||
const Nullable<TimeDuration> currentTime = GetLocalTime();
|
||||
GetComputedTimingDictionary(GetComputedTimingAt(currentTime, mTiming),
|
||||
GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
|
||||
SpecifiedTiming()),
|
||||
currentTime,
|
||||
mTiming,
|
||||
SpecifiedTiming(),
|
||||
aRetVal);
|
||||
}
|
||||
|
||||
ComputedTiming
|
||||
KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
const Nullable<TimeDuration>& aLocalTime,
|
||||
const AnimationTiming& aTiming)
|
||||
const TimingParams& aTiming)
|
||||
{
|
||||
const TimeDuration zeroDuration;
|
||||
|
||||
// Currently we expect negative durations to be picked up during CSS
|
||||
// parsing but when we start receiving timing parameters from other sources
|
||||
// we will need to clamp negative durations here.
|
||||
// For now, if we're hitting this it probably means we're overflowing
|
||||
// integer arithmetic in mozilla::TimeStamp.
|
||||
MOZ_ASSERT(aTiming.mIterationDuration >= zeroDuration,
|
||||
"Expecting iteration duration >= 0");
|
||||
const StickyTimeDuration zeroDuration;
|
||||
|
||||
// Always return the same object to benefit from return-value optimization.
|
||||
ComputedTiming result;
|
||||
|
||||
result.mActiveDuration = ActiveDuration(aTiming);
|
||||
if (aTiming.mDuration.IsUnrestrictedDouble()) {
|
||||
double durationMs = aTiming.mDuration.GetAsUnrestrictedDouble();
|
||||
if (!IsNaN(durationMs) && durationMs >= 0.0f) {
|
||||
result.mDuration = StickyTimeDuration::FromMilliseconds(durationMs);
|
||||
}
|
||||
}
|
||||
result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ?
|
||||
1.0f :
|
||||
aTiming.mIterations;
|
||||
result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations);
|
||||
result.mFill = aTiming.mFill == dom::FillMode::Auto ?
|
||||
dom::FillMode::None :
|
||||
aTiming.mFill;
|
||||
|
||||
// The default constructor for ComputedTiming sets all other members to
|
||||
// values consistent with an animation that has not been sampled.
|
||||
@ -247,7 +246,7 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
StickyTimeDuration activeTime;
|
||||
if (localTime >= aTiming.mDelay + result.mActiveDuration) {
|
||||
result.mPhase = ComputedTiming::AnimationPhase::After;
|
||||
if (!aTiming.FillsForwards()) {
|
||||
if (!result.FillsForwards()) {
|
||||
// The animation isn't active or filling at this time.
|
||||
result.mProgress.SetNull();
|
||||
return result;
|
||||
@ -255,12 +254,11 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
activeTime = result.mActiveDuration;
|
||||
// Note that infinity == floor(infinity) so this will also be true when we
|
||||
// have finished an infinitely repeating animation of zero duration.
|
||||
isEndOfFinalIteration =
|
||||
aTiming.mIterationCount != 0.0 &&
|
||||
aTiming.mIterationCount == floor(aTiming.mIterationCount);
|
||||
isEndOfFinalIteration = result.mIterations != 0.0 &&
|
||||
result.mIterations == floor(result.mIterations);
|
||||
} else if (localTime < aTiming.mDelay) {
|
||||
result.mPhase = ComputedTiming::AnimationPhase::Before;
|
||||
if (!aTiming.FillsBackwards()) {
|
||||
if (!result.FillsBackwards()) {
|
||||
// The animation isn't active or filling at this time.
|
||||
result.mProgress.SetNull();
|
||||
return result;
|
||||
@ -275,19 +273,19 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
|
||||
// Get the position within the current iteration.
|
||||
StickyTimeDuration iterationTime;
|
||||
if (aTiming.mIterationDuration != zeroDuration) {
|
||||
if (result.mDuration != zeroDuration) {
|
||||
iterationTime = isEndOfFinalIteration
|
||||
? StickyTimeDuration(aTiming.mIterationDuration)
|
||||
: activeTime % aTiming.mIterationDuration;
|
||||
? result.mDuration
|
||||
: activeTime % result.mDuration;
|
||||
} /* else, iterationTime is zero */
|
||||
|
||||
// Determine the 0-based index of the current iteration.
|
||||
if (isEndOfFinalIteration) {
|
||||
result.mCurrentIteration =
|
||||
aTiming.mIterationCount == NS_IEEEPositiveInfinity()
|
||||
IsInfinite(result.mIterations) // Positive Infinity?
|
||||
? UINT64_MAX // In GetComputedTimingDictionary(), we will convert this
|
||||
// into Infinity.
|
||||
: static_cast<uint64_t>(aTiming.mIterationCount) - 1;
|
||||
: static_cast<uint64_t>(result.mIterations) - 1;
|
||||
} else if (activeTime == zeroDuration) {
|
||||
// If the active time is zero we're either in the first iteration
|
||||
// (including filling backwards) or we have finished an animation with an
|
||||
@ -295,11 +293,11 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
// the exact end of an iteration since we deal with that above).
|
||||
result.mCurrentIteration =
|
||||
result.mPhase == ComputedTiming::AnimationPhase::After
|
||||
? static_cast<uint64_t>(aTiming.mIterationCount) // floor
|
||||
? static_cast<uint64_t>(result.mIterations) // floor
|
||||
: 0;
|
||||
} else {
|
||||
result.mCurrentIteration =
|
||||
static_cast<uint64_t>(activeTime / aTiming.mIterationDuration); // floor
|
||||
static_cast<uint64_t>(activeTime / result.mDuration); // floor
|
||||
}
|
||||
|
||||
// Normalize the iteration time into a fraction of the iteration duration.
|
||||
@ -308,15 +306,15 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
} else if (result.mPhase == ComputedTiming::AnimationPhase::After) {
|
||||
double progress = isEndOfFinalIteration
|
||||
? 1.0
|
||||
: fmod(aTiming.mIterationCount, 1.0f);
|
||||
: fmod(result.mIterations, 1.0);
|
||||
result.mProgress.SetValue(progress);
|
||||
} else {
|
||||
// We are in the active phase so the iteration duration can't be zero.
|
||||
MOZ_ASSERT(aTiming.mIterationDuration != zeroDuration,
|
||||
MOZ_ASSERT(result.mDuration != zeroDuration,
|
||||
"In the active phase of a zero-duration animation?");
|
||||
double progress = aTiming.mIterationDuration == TimeDuration::Forever()
|
||||
double progress = result.mDuration == StickyTimeDuration::Forever()
|
||||
? 0.0
|
||||
: iterationTime / aTiming.mIterationDuration;
|
||||
: iterationTime / result.mDuration;
|
||||
result.mProgress.SetValue(progress);
|
||||
}
|
||||
|
||||
@ -345,19 +343,19 @@ KeyframeEffectReadOnly::GetComputedTimingAt(
|
||||
}
|
||||
|
||||
StickyTimeDuration
|
||||
KeyframeEffectReadOnly::ActiveDuration(const AnimationTiming& aTiming)
|
||||
KeyframeEffectReadOnly::ActiveDuration(const StickyTimeDuration& aIterationDuration,
|
||||
double aIterationCount)
|
||||
{
|
||||
if (aTiming.mIterationCount == mozilla::PositiveInfinity<float>()) {
|
||||
if (IsInfinite(aIterationCount)) {
|
||||
// An animation that repeats forever has an infinite active duration
|
||||
// unless its iteration duration is zero, in which case it has a zero
|
||||
// active duration.
|
||||
const StickyTimeDuration zeroDuration;
|
||||
return aTiming.mIterationDuration == zeroDuration
|
||||
? zeroDuration
|
||||
: StickyTimeDuration::Forever();
|
||||
return aIterationDuration == zeroDuration ?
|
||||
zeroDuration :
|
||||
StickyTimeDuration::Forever();
|
||||
}
|
||||
return StickyTimeDuration(
|
||||
aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount));
|
||||
return aIterationDuration.MultDouble(aIterationCount);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/web-animations/#in-play
|
||||
@ -641,53 +639,19 @@ DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Extract an iteration duration from an UnrestrictedDoubleOrXXX object.
|
||||
template <typename T>
|
||||
static TimeDuration
|
||||
GetIterationDuration(const T& aDuration) {
|
||||
// Always return the same object to benefit from return-value optimization.
|
||||
TimeDuration result;
|
||||
if (aDuration.IsUnrestrictedDouble()) {
|
||||
double durationMs = aDuration.GetAsUnrestrictedDouble();
|
||||
if (!IsNaN(durationMs) && durationMs >= 0.0f) {
|
||||
result = TimeDuration::FromMilliseconds(durationMs);
|
||||
}
|
||||
}
|
||||
// else, aDuration should be zero
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ AnimationTiming
|
||||
/* static */ TimingParams
|
||||
KeyframeEffectReadOnly::ConvertKeyframeEffectOptions(
|
||||
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
|
||||
{
|
||||
AnimationTiming animationTiming;
|
||||
TimingParams timing;
|
||||
|
||||
if (aOptions.IsKeyframeEffectOptions()) {
|
||||
const KeyframeEffectOptions& opt = aOptions.GetAsKeyframeEffectOptions();
|
||||
|
||||
animationTiming.mIterationDuration = GetIterationDuration(opt.mDuration);
|
||||
animationTiming.mDelay = TimeDuration::FromMilliseconds(opt.mDelay);
|
||||
// FIXME: Covert mIterationCount to a valid value.
|
||||
// Bug 1214536 should revise this and keep the original value, so
|
||||
// AnimationTimingEffectReadOnly can get the original iterations.
|
||||
animationTiming.mIterationCount = (IsNaN(opt.mIterations) ||
|
||||
opt.mIterations < 0.0f) ?
|
||||
1.0f :
|
||||
opt.mIterations;
|
||||
animationTiming.mDirection = opt.mDirection;
|
||||
// FIXME: We should store original value.
|
||||
animationTiming.mFillMode = (opt.mFill == FillMode::Auto) ?
|
||||
FillMode::None :
|
||||
opt.mFill;
|
||||
timing = aOptions.GetAsKeyframeEffectOptions();
|
||||
} else {
|
||||
animationTiming.mIterationDuration = GetIterationDuration(aOptions);
|
||||
animationTiming.mDelay = TimeDuration(0);
|
||||
animationTiming.mIterationCount = 1.0f;
|
||||
animationTiming.mDirection = PlaybackDirection::Normal;
|
||||
animationTiming.mFillMode = FillMode::None;
|
||||
timing.mDuration.SetAsUnrestrictedDouble() =
|
||||
aOptions.GetAsUnrestrictedDouble();
|
||||
}
|
||||
return animationTiming;
|
||||
return timing;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1723,7 +1687,7 @@ KeyframeEffectReadOnly::Constructor(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnimationTiming timing = ConvertKeyframeEffectOptions(aOptions);
|
||||
TimingParams timing = ConvertKeyframeEffectOptions(aOptions);
|
||||
|
||||
InfallibleTArray<AnimationProperty> animationProperties;
|
||||
BuildAnimationPropertyList(aGlobal.Context(), aTarget, aFrames,
|
||||
|
@ -15,14 +15,17 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
|
||||
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
|
||||
#include "mozilla/OwningNonNull.h" // OwningNonNull<...>
|
||||
#include "mozilla/StickyTimeDuration.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/AnimationEffectReadOnly.h"
|
||||
#include "mozilla/dom/AnimationEffectTimingReadOnly.h" // TimingParams
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/KeyframeBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
|
||||
|
||||
struct JSContext;
|
||||
class nsCSSPropertySet;
|
||||
class nsIContent;
|
||||
@ -36,41 +39,11 @@ struct AnimationCollection;
|
||||
class AnimValuesStyleRule;
|
||||
|
||||
namespace dom {
|
||||
struct ComputedTimingProperties;
|
||||
class UnrestrictedDoubleOrKeyframeEffectOptions;
|
||||
enum class IterationCompositeOperation : uint32_t;
|
||||
enum class CompositeOperation : uint32_t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input timing parameters.
|
||||
*
|
||||
* Eventually this will represent all the input timing parameters specified
|
||||
* by content but for now it encapsulates just the subset of those
|
||||
* parameters passed to GetPositionInIteration.
|
||||
*/
|
||||
struct AnimationTiming
|
||||
{
|
||||
TimeDuration mIterationDuration;
|
||||
TimeDuration mDelay;
|
||||
float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
|
||||
dom::PlaybackDirection mDirection;
|
||||
dom::FillMode mFillMode;
|
||||
|
||||
bool FillsForwards() const;
|
||||
bool FillsBackwards() const;
|
||||
bool operator==(const AnimationTiming& aOther) const {
|
||||
return mIterationDuration == aOther.mIterationDuration &&
|
||||
mDelay == aOther.mDelay &&
|
||||
mIterationCount == aOther.mIterationCount &&
|
||||
mDirection == aOther.mDirection &&
|
||||
mFillMode == aOther.mFillMode;
|
||||
}
|
||||
bool operator!=(const AnimationTiming& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores the results of calculating the timing properties of an animation
|
||||
* at a given sample time.
|
||||
@ -88,6 +61,25 @@ struct ComputedTiming
|
||||
Nullable<double> mProgress;
|
||||
// Zero-based iteration index (meaningless if mProgress is null).
|
||||
uint64_t mCurrentIteration = 0;
|
||||
// Unlike TimingParams::mIterations, this value is
|
||||
// guaranteed to be in the range [0, Infinity].
|
||||
double mIterations = 1.0;
|
||||
StickyTimeDuration mDuration;
|
||||
|
||||
// This is the computed fill mode so it is never auto
|
||||
dom::FillMode mFill = dom::FillMode::None;
|
||||
bool FillsForwards() const {
|
||||
MOZ_ASSERT(mFill != dom::FillMode::Auto,
|
||||
"mFill should not be Auto in ComputedTiming.");
|
||||
return mFill == dom::FillMode::Both ||
|
||||
mFill == dom::FillMode::Forwards;
|
||||
}
|
||||
bool FillsBackwards() const {
|
||||
MOZ_ASSERT(mFill != dom::FillMode::Auto,
|
||||
"mFill should not be Auto in ComputedTiming.");
|
||||
return mFill == dom::FillMode::Both ||
|
||||
mFill == dom::FillMode::Backwards;
|
||||
}
|
||||
|
||||
enum class AnimationPhase {
|
||||
Null, // Not sampled (null sample time)
|
||||
@ -178,7 +170,7 @@ public:
|
||||
KeyframeEffectReadOnly(nsIDocument* aDocument,
|
||||
Element* aTarget,
|
||||
nsCSSPseudoElements::Type aPseudoType,
|
||||
const AnimationTiming& aTiming);
|
||||
const TimingParams& aTiming);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
|
||||
@ -227,9 +219,13 @@ public:
|
||||
aRetVal.AssignLiteral("distribute");
|
||||
}
|
||||
|
||||
const AnimationTiming& Timing() const { return mTiming; }
|
||||
AnimationTiming& Timing() { return mTiming; }
|
||||
void SetTiming(const AnimationTiming& aTiming);
|
||||
already_AddRefed<AnimationEffectTimingReadOnly> Timing() const override;
|
||||
|
||||
const TimingParams& SpecifiedTiming() const
|
||||
{
|
||||
return mTiming->AsTimingParams();
|
||||
}
|
||||
void SetSpecifiedTiming(const TimingParams& aTiming);
|
||||
void NotifyAnimationTimingUpdated();
|
||||
|
||||
Nullable<TimeDuration> GetLocalTime() const;
|
||||
@ -246,22 +242,25 @@ public:
|
||||
// (because it is not currently active and is not filling at this time).
|
||||
static ComputedTiming
|
||||
GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
|
||||
const AnimationTiming& aTiming);
|
||||
const TimingParams& aTiming);
|
||||
|
||||
// Shortcut for that gets the computed timing using the current local time as
|
||||
// calculated from the timeline time.
|
||||
ComputedTiming
|
||||
GetComputedTiming(const AnimationTiming* aTiming = nullptr) const
|
||||
GetComputedTiming(const TimingParams* aTiming = nullptr) const
|
||||
{
|
||||
return GetComputedTimingAt(GetLocalTime(), aTiming ? *aTiming : mTiming);
|
||||
return GetComputedTimingAt(GetLocalTime(),
|
||||
aTiming ? *aTiming : SpecifiedTiming());
|
||||
}
|
||||
|
||||
void
|
||||
GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override;
|
||||
|
||||
// Return the duration of the active interval for the given timing parameters.
|
||||
// Return the duration of the active interval for the given duration and
|
||||
// iteration count.
|
||||
static StickyTimeDuration
|
||||
ActiveDuration(const AnimationTiming& aTiming);
|
||||
ActiveDuration(const StickyTimeDuration& aIterationDuration,
|
||||
double aIterationCount);
|
||||
|
||||
bool IsInPlay() const;
|
||||
bool IsCurrent() const;
|
||||
@ -334,7 +333,7 @@ protected:
|
||||
// owning Animation's timing.
|
||||
void UpdateTargetRegistration();
|
||||
|
||||
static AnimationTiming ConvertKeyframeEffectOptions(
|
||||
static TimingParams ConvertKeyframeEffectOptions(
|
||||
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions);
|
||||
|
||||
static void BuildAnimationPropertyList(
|
||||
@ -347,7 +346,7 @@ protected:
|
||||
nsCOMPtr<Element> mTarget;
|
||||
RefPtr<Animation> mAnimation;
|
||||
|
||||
AnimationTiming mTiming;
|
||||
OwningNonNull<AnimationEffectTimingReadOnly> mTiming;
|
||||
nsCSSPseudoElements::Type mPseudoType;
|
||||
|
||||
InfallibleTArray<AnimationProperty> mProperties;
|
||||
|
@ -10,6 +10,7 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
EXPORTS.mozilla.dom += [
|
||||
'Animation.h',
|
||||
'AnimationEffectReadOnly.h',
|
||||
'AnimationEffectTimingReadOnly.h',
|
||||
'AnimationTimeline.h',
|
||||
'DocumentTimeline.h',
|
||||
'KeyframeEffect.h',
|
||||
@ -29,6 +30,7 @@ EXPORTS.mozilla += [
|
||||
UNIFIED_SOURCES += [
|
||||
'Animation.cpp',
|
||||
'AnimationEffectReadOnly.cpp',
|
||||
'AnimationEffectTimingReadOnly.cpp',
|
||||
'AnimationTimeline.cpp',
|
||||
'AnimationUtils.cpp',
|
||||
'AnimValuesStyleRule.cpp',
|
||||
|
@ -344,7 +344,7 @@ TextInputProcessor::PrepareKeyboardEventForComposition(
|
||||
|
||||
aKeyboardEvent =
|
||||
aOptionalArgc && aDOMKeyEvent ?
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent() : nullptr;
|
||||
aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent() : nullptr;
|
||||
if (!aKeyboardEvent || aOptionalArgc < 2) {
|
||||
aKeyFlags = 0;
|
||||
}
|
||||
@ -769,7 +769,7 @@ TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
WidgetKeyboardEvent* originalKeyEvent =
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
if (NS_WARN_IF(!originalKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -875,7 +875,7 @@ TextInputProcessor::Keyup(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
WidgetKeyboardEvent* originalKeyEvent =
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
if (NS_WARN_IF(!originalKeyEvent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
@ -1561,7 +1561,7 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
// to reflect that upgrade. Please note that we can not upgrade from ws:
|
||||
// to wss: before performing content policy checks because CSP needs to
|
||||
// send reports in case the scheme is about to be upgraded.
|
||||
if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests()) {
|
||||
if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests(false)) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
NS_ConvertUTF8toUTF16 reportSpec(mURI);
|
||||
|
||||
|
@ -116,8 +116,8 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
nsContentPolicyType externalType =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
|
||||
|
||||
nsContentPolicyType externalTypeOrScript =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentType);
|
||||
nsContentPolicyType externalTypeOrMCBInternal =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentType);
|
||||
|
||||
nsContentPolicyType externalTypeOrCSPInternal =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(contentType);
|
||||
@ -140,11 +140,13 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
/* check the appropriate policy */
|
||||
// Send the internal content policy type to the mixed content blocker
|
||||
// which needs to know about TYPE_INTERNAL_WORKER,
|
||||
// TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER.
|
||||
// TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER
|
||||
// and also preloads: TYPE_INTERNAL_SCRIPT_PRELOAD,
|
||||
// TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
bool isMixedContentBlocker = mixedContentBlocker == entries[i];
|
||||
nsContentPolicyType type = externalType;
|
||||
if (isMixedContentBlocker) {
|
||||
type = externalTypeOrScript;
|
||||
type = externalTypeOrMCBInternal;
|
||||
}
|
||||
// Send the internal content policy type for CSP which needs to
|
||||
// know about preloads and workers, in particular:
|
||||
|
@ -4955,13 +4955,13 @@ nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
|
||||
|
||||
nsAutoString eventType;
|
||||
aDOMKeyEvent->GetType(eventType);
|
||||
aDOMKeyEvent->AsEvent()->GetType(eventType);
|
||||
// Don't process if aDOMKeyEvent is not a keypress event.
|
||||
if (!eventType.EqualsLiteral("keypress"))
|
||||
return;
|
||||
|
||||
WidgetKeyboardEvent* nativeKeyEvent =
|
||||
aDOMKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
aDOMKeyEvent->AsEvent()->GetInternalNSEvent()->AsKeyboardEvent();
|
||||
if (nativeKeyEvent) {
|
||||
NS_ASSERTION(nativeKeyEvent->mClass == eKeyboardEventClass,
|
||||
"wrong type of native event");
|
||||
@ -7991,7 +7991,7 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType)
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
|
||||
@ -8001,7 +8001,7 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType
|
||||
return aType;
|
||||
|
||||
default:
|
||||
return InternalContentPolicyTypeToExternal(aType);
|
||||
return InternalContentPolicyTypeToExternalOrPreload(aType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -986,16 +986,18 @@ public:
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones or script types:
|
||||
* Map internal content policy types to external ones or script types or preload types:
|
||||
* * TYPE_INTERNAL_SCRIPT
|
||||
* * TYPE_INTERNAL_WORKER
|
||||
* * TYPE_INTERNAL_SHARED_WORKER
|
||||
* * TYPE_INTERNAL_SERVICE_WORKER
|
||||
*
|
||||
* * TYPE_INTERNAL_SCRIPT_PRELOAD
|
||||
* * TYPE_INTERNAL_IMAGE_PRELOAD
|
||||
* * TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
*
|
||||
* Note: DO NOT call this function unless you know what you're doing!
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternalOrScript(nsContentPolicyType aType);
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones or preload types:
|
||||
|
@ -2550,12 +2550,12 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
|
||||
if (sameTypeParent) {
|
||||
mUpgradeInsecureRequests =
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests();
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(false);
|
||||
// if the parent document makes use of upgrade-insecure-requests
|
||||
// then subdocument preloads should always be upgraded.
|
||||
mUpgradeInsecurePreloads =
|
||||
mUpgradeInsecureRequests ||
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecurePreloads();
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2785,19 +2785,8 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Failed to create CSP object: %x", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
// used as a "self" identifier for the CSP.
|
||||
nsCOMPtr<nsIURI> selfURI;
|
||||
aChannel->GetURI(getter_AddRefs(selfURI));
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->SetRequestContext(this, nullptr);
|
||||
rv = principal->EnsureCSP(this, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// ----- if the doc is an app and we want a default CSP, apply it.
|
||||
if (applyAppDefaultCSP) {
|
||||
@ -2847,14 +2836,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug,
|
||||
("Inserted CSP into principal %p", principal));
|
||||
|
||||
ApplySettingsFromCSP(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -321,19 +321,14 @@ public:
|
||||
* of the document's ancestors up to the toplevel document makes use
|
||||
* of the CSP directive 'upgrade-insecure-requests'.
|
||||
*/
|
||||
bool GetUpgradeInsecureRequests() const
|
||||
bool GetUpgradeInsecureRequests(bool aPreload) const
|
||||
{
|
||||
if (aPreload) {
|
||||
return mUpgradeInsecurePreloads;
|
||||
}
|
||||
return mUpgradeInsecureRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as GetUpgradeInsecureRequests() but *only* for preloads.
|
||||
*/
|
||||
bool GetUpgradeInsecurePreloads() const
|
||||
{
|
||||
return mUpgradeInsecurePreloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the principal responsible for this document.
|
||||
*/
|
||||
|
@ -646,6 +646,21 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
// sheets. If the script comes from the network stream, cheat for
|
||||
// performance reasons and avoid a trip through the event loop.
|
||||
if (aElement->GetParserCreated() == FROM_PARSER_NETWORK) {
|
||||
// Attempt to compile script off-thread first -- it reduces locking of
|
||||
// the main thread for long time.
|
||||
if (NumberOfProcessors() > 1 &&
|
||||
AttemptAsyncScriptCompile(request) == NS_OK) {
|
||||
NS_ASSERTION(request->mProgress == nsScriptLoadRequest::Progress_Compiling,
|
||||
"Request should be off-thread compiling now.");
|
||||
NS_ASSERTION(!mParserBlockingRequest,
|
||||
"There can be only one parser-blocking script at a time");
|
||||
NS_ASSERTION(mXSLTRequests.isEmpty(),
|
||||
"Parser-blocking scripts and XSLT scripts in the same doc!");
|
||||
mParserBlockingRequest = request;
|
||||
return true;
|
||||
}
|
||||
// And process a request if off-thread compilation heuristics think that
|
||||
// non-async way will be faster.
|
||||
return ProcessRequest(request) == NS_ERROR_HTMLPARSER_BLOCK;
|
||||
}
|
||||
// Otherwise, we've got a document.written script, make a trip through
|
||||
@ -1791,7 +1806,7 @@ nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
|
||||
|
||||
haveRead += dstLen;
|
||||
MOZ_ASSERT(haveRead <= capacity, "mDecoder produced more data than expected");
|
||||
mBuffer.resizeUninitialized(haveRead);
|
||||
MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3240,7 +3240,7 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
conditions = []
|
||||
iface = self.descriptor.interface
|
||||
|
||||
if not iface.isExposedInWindow():
|
||||
if not iface.isExposedOnMainThread():
|
||||
exposedInWindowCheck = dedent(
|
||||
"""
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Why did we even get called?");
|
||||
@ -3259,7 +3259,7 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
}
|
||||
""", workerCondition=workerCondition.define())
|
||||
exposedInWorkerCheck = CGGeneric(exposedInWorkerCheck)
|
||||
if iface.isExposedInWindow():
|
||||
if iface.isExposedOnMainThread():
|
||||
exposedInWorkerCheck = CGIfWrapper(exposedInWorkerCheck,
|
||||
"!NS_IsMainThread()")
|
||||
body.append(exposedInWorkerCheck)
|
||||
|
@ -501,6 +501,10 @@ class IDLExposureMixins():
|
||||
def isExposedInWindow(self):
|
||||
return 'Window' in self.exposureSet
|
||||
|
||||
def isExposedOnMainThread(self):
|
||||
return (self.isExposedInWindow() or
|
||||
self.isExposedInSystemGlobals())
|
||||
|
||||
def isExposedInAnyWorker(self):
|
||||
return len(self.getWorkerExposureSet()) > 0
|
||||
|
||||
|
@ -122,10 +122,10 @@ WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
|
||||
void
|
||||
WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
|
||||
{
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4iv"))
|
||||
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4iv"))
|
||||
return;
|
||||
|
||||
mVertexAttribType[index] = LOCAL_GL_INT;
|
||||
@ -183,7 +183,7 @@ WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4uiv"))
|
||||
if (!ValidateAttribArraySetter("vertexAttribI4uiv", 4, length))
|
||||
return;
|
||||
|
||||
if (!ValidateAttribIndex(index, "vertexAttribI4uiv"))
|
||||
|
@ -448,8 +448,8 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
|
||||
return false;
|
||||
|
||||
if (arrayLength < setterElemSize) {
|
||||
ErrorInvalidOperation("%s: Array must have >= %d elements.", name,
|
||||
setterElemSize);
|
||||
ErrorInvalidValue("%s: Array must have >= %d elements.", name,
|
||||
setterElemSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -584,7 +584,7 @@ IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
WidgetMouseEvent* internalEvent =
|
||||
aMouseEvent->GetInternalNSEvent()->AsMouseEvent();
|
||||
aMouseEvent->AsEvent()->GetInternalNSEvent()->AsMouseEvent();
|
||||
if (NS_WARN_IF(!internalEvent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
|
||||
@ -597,7 +597,7 @@ IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
|
||||
|
||||
if (MOZ_LOG_TEST(sISMLog, LogLevel::Info)) {
|
||||
nsAutoString eventType;
|
||||
aMouseEvent->GetType(eventType);
|
||||
aMouseEvent->AsEvent()->GetType(eventType);
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnMouseButtonEventInEditor(), "
|
||||
"mouse event (type=%s, button=%d) is %s",
|
||||
@ -630,7 +630,7 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
NS_ENSURE_TRUE_VOID(widget);
|
||||
|
||||
bool isTrusted;
|
||||
nsresult rv = aMouseEvent->GetIsTrusted(&isTrusted);
|
||||
nsresult rv = aMouseEvent->AsEvent()->GetIsTrusted(&isTrusted);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (!isTrusted) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
|
@ -346,6 +346,12 @@ UIEvent::IsChar() const
|
||||
return keyEvent ? keyEvent->isChar : false;
|
||||
}
|
||||
|
||||
mozilla::dom::Event*
|
||||
UIEvent::AsEvent(void)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UIEvent::DuplicatePrivateData()
|
||||
{
|
||||
|
@ -88,7 +88,7 @@ class InternalRequest final
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
|
||||
|
||||
explicit InternalRequest()
|
||||
InternalRequest()
|
||||
: mMethod("GET")
|
||||
, mHeaders(new InternalHeaders(HeadersGuardEnum::None))
|
||||
, mContentPolicyType(nsIContentPolicy::TYPE_FETCH)
|
||||
@ -113,6 +113,36 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
InternalRequest(const nsACString& aURL,
|
||||
const nsACString& aMethod,
|
||||
already_AddRefed<InternalHeaders> aHeaders,
|
||||
RequestMode aMode,
|
||||
RequestRedirect aRequestRedirect,
|
||||
RequestCredentials aRequestCredentials,
|
||||
const nsAString& aReferrer,
|
||||
nsContentPolicyType aContentPolicyType)
|
||||
: mMethod(aMethod)
|
||||
, mURL(aURL)
|
||||
, mHeaders(aHeaders)
|
||||
, mContentPolicyType(aContentPolicyType)
|
||||
, mReferrer(aReferrer)
|
||||
, mMode(aMode)
|
||||
, mCredentialsMode(aRequestCredentials)
|
||||
, mResponseTainting(LoadTainting::Basic)
|
||||
, mCacheMode(RequestCache::Default)
|
||||
, mRedirectMode(aRequestRedirect)
|
||||
, mAuthenticationFlag(false)
|
||||
, mForceOriginHeader(false)
|
||||
, mPreserveContentCodings(false)
|
||||
// FIXME See the above comment in the default constructor.
|
||||
, mSameOriginDataURL(true)
|
||||
, mSkipServiceWorker(false)
|
||||
, mSynchronous(false)
|
||||
, mUnsafeRequest(false)
|
||||
, mUseURLCredentials(false)
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<InternalRequest> Clone();
|
||||
|
||||
void
|
||||
|
@ -331,7 +331,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
|
||||
const int numButtons = gamepad.numButtons();
|
||||
for (unsigned b = 0; b < ArrayLength(newState); b++) {
|
||||
if (newState[b] != oldState[b]) {
|
||||
NewButtonEvent(i, numButtons - 4 + b, newState[b]);
|
||||
NewButtonEvent(gamepad.mSuperIndex, numButtons - 4 + b, newState[b]);
|
||||
}
|
||||
}
|
||||
gamepad.setDpadState(newState);
|
||||
@ -339,7 +339,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
|
||||
double d = IOHIDValueGetIntegerValue(value);
|
||||
double v = 2.0f * (d - axis->min) /
|
||||
(double)(axis->max - axis->min) - 1.0f;
|
||||
NewAxisMoveEvent(i, axis->id, v);
|
||||
NewAxisMoveEvent(gamepad.mSuperIndex, axis->id, v);
|
||||
} else if (const Button* button = gamepad.lookupButton(element)) {
|
||||
int iv = IOHIDValueGetIntegerValue(value);
|
||||
bool pressed = iv != 0;
|
||||
@ -350,7 +350,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
|
||||
} else {
|
||||
v = pressed ? 1.0 : 0.0;
|
||||
}
|
||||
NewButtonEvent(i, button->id, pressed, v);
|
||||
NewButtonEvent(gamepad.mSuperIndex, button->id, pressed, v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ class nsGeolocationRequest final
|
||||
const GeoPositionCallback& aCallback,
|
||||
const GeoPositionErrorCallback& aErrorCallback,
|
||||
PositionOptions* aOptions,
|
||||
uint8_t aProtocolType,
|
||||
bool aWatchPositionRequest = false,
|
||||
int32_t aWatchId = 0);
|
||||
void Shutdown();
|
||||
@ -120,6 +121,7 @@ class nsGeolocationRequest final
|
||||
int32_t mWatchId;
|
||||
bool mShutdown;
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
uint8_t mProtocolType;
|
||||
};
|
||||
|
||||
static PositionOptions*
|
||||
@ -354,6 +356,7 @@ nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
|
||||
const GeoPositionCallback& aCallback,
|
||||
const GeoPositionErrorCallback& aErrorCallback,
|
||||
PositionOptions* aOptions,
|
||||
uint8_t aProtocolType,
|
||||
bool aWatchPositionRequest,
|
||||
int32_t aWatchId)
|
||||
: mIsWatchPositionRequest(aWatchPositionRequest),
|
||||
@ -362,7 +365,8 @@ nsGeolocationRequest::nsGeolocationRequest(Geolocation* aLocator,
|
||||
mOptions(aOptions),
|
||||
mLocator(aLocator),
|
||||
mWatchId(aWatchId),
|
||||
mShutdown(false)
|
||||
mShutdown(false),
|
||||
mProtocolType(aProtocolType)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> win = do_QueryReferent(mLocator->GetOwner());
|
||||
if (win) {
|
||||
@ -453,6 +457,13 @@ nsGeolocationRequest::GetElement(nsIDOMElement * *aRequestingElement)
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::Cancel()
|
||||
{
|
||||
if (mRequester) {
|
||||
// Record the number of denied requests for regular web content.
|
||||
// This method is only called when the user explicitly denies the request,
|
||||
// and is not called when the page is simply unloaded, or similar.
|
||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_REQUEST_GRANTED, mProtocolType);
|
||||
}
|
||||
|
||||
if (mLocator->ClearPendingRequest(this)) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -466,6 +477,11 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
MOZ_ASSERT(aChoices.isUndefined());
|
||||
|
||||
if (mRequester) {
|
||||
// Record the number of granted requests for regular web content.
|
||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_REQUEST_GRANTED, mProtocolType + 10);
|
||||
}
|
||||
|
||||
if (mLocator->ClearPendingRequest(this)) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1193,7 +1209,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Geolocation,
|
||||
mPendingRequests)
|
||||
|
||||
Geolocation::Geolocation()
|
||||
: mLastWatchId(0)
|
||||
: mProtocolType(ProtocolType::OTHER)
|
||||
, mLastWatchId(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1234,6 +1251,24 @@ Geolocation::Init(nsIDOMWindow* aContentDom)
|
||||
/* wants untrusted */ false);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = mPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isHttp;
|
||||
rv = uri->SchemeIs("http", &isHttp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool isHttps;
|
||||
rv = uri->SchemeIs("https", &isHttps);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the protocol to send via telemetry later.
|
||||
if (isHttp) {
|
||||
mProtocolType = ProtocolType::HTTP;
|
||||
} else if (isHttps) {
|
||||
mProtocolType = ProtocolType::HTTPS;
|
||||
}
|
||||
}
|
||||
|
||||
// If no aContentDom was passed into us, we are being used
|
||||
@ -1494,11 +1529,13 @@ Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
RefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
|
||||
callback,
|
||||
errorCallback,
|
||||
options,
|
||||
false);
|
||||
// Count the number of requests per protocol/scheme.
|
||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_GETCURRENTPOSITION_SECURE_ORIGIN,
|
||||
static_cast<uint8_t>(mProtocolType));
|
||||
|
||||
RefPtr<nsGeolocationRequest> request =
|
||||
new nsGeolocationRequest(this, callback, errorCallback, options,
|
||||
static_cast<uint8_t>(mProtocolType), false);
|
||||
|
||||
if (!sGeoEnabled) {
|
||||
nsCOMPtr<nsIRunnable> ev = new RequestAllowEvent(false, request);
|
||||
@ -1583,15 +1620,16 @@ Geolocation::WatchPosition(GeoPositionCallback& aCallback,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Count the number of requests per protocol/scheme.
|
||||
Telemetry::Accumulate(Telemetry::GEOLOCATION_WATCHPOSITION_SECURE_ORIGIN,
|
||||
static_cast<uint8_t>(mProtocolType));
|
||||
|
||||
// The watch ID:
|
||||
*aRv = mLastWatchId++;
|
||||
|
||||
RefPtr<nsGeolocationRequest> request = new nsGeolocationRequest(this,
|
||||
aCallback,
|
||||
aErrorCallback,
|
||||
aOptions,
|
||||
true,
|
||||
*aRv);
|
||||
RefPtr<nsGeolocationRequest> request =
|
||||
new nsGeolocationRequest(this, aCallback, aErrorCallback, aOptions,
|
||||
static_cast<uint8_t>(mProtocolType), true, *aRv);
|
||||
|
||||
if (!sGeoEnabled) {
|
||||
GPSLOG("request allow event");
|
||||
|
@ -218,6 +218,12 @@ private:
|
||||
// where the content was loaded from
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
// the protocols we want to measure
|
||||
enum class ProtocolType: uint8_t { OTHER, HTTP, HTTPS };
|
||||
|
||||
// the protocol used to load the content
|
||||
ProtocolType mProtocolType;
|
||||
|
||||
// owning back pointer.
|
||||
RefPtr<nsGeolocationService> mService;
|
||||
|
||||
|
@ -1746,7 +1746,7 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL,
|
||||
bool isHttpScheme = false;
|
||||
rv = actionURL->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests()) {
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests(false)) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
nsAutoCString spec;
|
||||
rv = actionURL->GetSpec(spec);
|
||||
|
@ -129,26 +129,13 @@ HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
|
||||
nsIPrincipal* principal = aDocument->NodePrincipal();
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
|
||||
rv = principal->EnsureCSP(domDoc, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Multiple CSPs (delivered through either header of meta tag) need to be
|
||||
// joined together, see:
|
||||
// https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
|
||||
if (!csp) {
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context so CSP can resolve 'self'
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
|
||||
rv = csp->SetRequestContext(domDoc, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// set the new CSP
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = csp->AppendPolicy(content,
|
||||
false, // csp via meta tag can not be report only
|
||||
true); // delivered through the meta tag
|
||||
|
@ -343,12 +343,7 @@ HTMLSharedObjectElement::GetCapabilities() const
|
||||
{
|
||||
uint32_t capabilities = eSupportPlugins | eAllowPluginSkipChannel;
|
||||
if (mNodeInfo->Equals(nsGkAtoms::embed)) {
|
||||
capabilities |= eSupportSVG | eSupportImages;
|
||||
}
|
||||
// If this is a rewritten youtube flash embed, add documents to capabilities
|
||||
// so that we can render HTML5 if possible.
|
||||
if (mRewrittenYoutubeEmbed) {
|
||||
capabilities |= eSupportDocuments;
|
||||
capabilities |= eSupportSVG | eSupportImages | eSupportDocuments;
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Animation events are defined in:
|
||||
@ -11,8 +11,9 @@
|
||||
* http://dev.w3.org/csswg/css3-animations/#animation-events-
|
||||
*/
|
||||
|
||||
[builtinclass, uuid(772c7069-3f7d-42cf-97ab-b32f1c0b83da)]
|
||||
interface nsIDOMAnimationEvent : nsIDOMEvent {
|
||||
[builtinclass, uuid(ce6d1db3-53b8-4ade-9baa-70f4947200a2)]
|
||||
interface nsIDOMAnimationEvent : nsISupports
|
||||
{
|
||||
readonly attribute DOMString animationName;
|
||||
readonly attribute float elapsedTime;
|
||||
readonly attribute DOMString pseudoElement;
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* The nsIDOMBeforeUnloadEvent interface is the interface for events
|
||||
@ -15,8 +15,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
[builtinclass, uuid(96abf41b-32a8-4ff6-a0d6-4ade4ddebf89)]
|
||||
interface nsIDOMBeforeUnloadEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(26c83933-a5a4-455e-8c46-69fa24dfa991)]
|
||||
interface nsIDOMBeforeUnloadEvent : nsISupports
|
||||
{
|
||||
/**
|
||||
* Attribute used to pass back a return value from a beforeunload
|
||||
|
@ -4,12 +4,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "domstubs.idl"
|
||||
#include "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMDataTransfer;
|
||||
|
||||
[builtinclass, uuid(4ef84980-52c2-425c-b41a-2ee75ec5d497)]
|
||||
interface nsIDOMClipboardEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(b54d6144-3980-4895-83c7-82f158bc1cf5)]
|
||||
interface nsIDOMClipboardEvent : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMDataTransfer clipboardData;
|
||||
|
||||
|
@ -3,10 +3,10 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[builtinclass, uuid(7efbe68a-811a-4159-801c-226948cfd08f)]
|
||||
interface nsIDOMCommandEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(73a50e55-3eaa-4a38-a588-9b68a6d65032)]
|
||||
interface nsIDOMCommandEvent : nsISupports
|
||||
{
|
||||
readonly attribute DOMString command;
|
||||
|
||||
|
@ -3,11 +3,11 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIVariant.idl"
|
||||
|
||||
[builtinclass, uuid(31ceb43e-5f49-43bf-9a18-3b60a535c814)]
|
||||
interface nsIDOMDataContainerEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(a9f1f528-d106-4fea-8663-2d7f64b627a9)]
|
||||
interface nsIDOMDataContainerEvent : nsISupports
|
||||
{
|
||||
/**
|
||||
* Return the data associated with the given key.
|
||||
|
@ -3,7 +3,8 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMWindow.idl"
|
||||
|
||||
/**
|
||||
* The nsIDOMMessageEvent interface is used for server-sent events and for
|
||||
@ -12,8 +13,8 @@
|
||||
* For more information on this interface, please see
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#messageevent
|
||||
*/
|
||||
[builtinclass, uuid(4408a2f5-614f-40a3-8786-e16bd3f74e32)]
|
||||
interface nsIDOMMessageEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(5d57bc56-30cf-4839-9e98-17f940120ec0)]
|
||||
interface nsIDOMMessageEvent : nsISupports
|
||||
{
|
||||
/**
|
||||
* Custom string data associated with this event.
|
||||
|
@ -3,10 +3,11 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMNode.idl"
|
||||
|
||||
[builtinclass, uuid(df7e4cd9-e41f-4c8e-a764-2e3191d2f463)]
|
||||
interface nsIDOMMutationEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(30c9997f-bc4c-4890-b890-febb6ae3051b)]
|
||||
interface nsIDOMMutationEvent : nsISupports
|
||||
{
|
||||
const unsigned short MODIFICATION = 1;
|
||||
const unsigned short ADDITION = 2;
|
||||
|
@ -3,7 +3,9 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMClientRectList.idl"
|
||||
#include "nsIDOMClientRect.idl"
|
||||
|
||||
interface nsIDOMPaintRequestList;
|
||||
|
||||
@ -12,8 +14,8 @@ interface nsIDOMPaintRequestList;
|
||||
* event, which fires at a window when painting has happened in
|
||||
* that window.
|
||||
*/
|
||||
[builtinclass, uuid(550f660c-65a5-4e17-b828-3dbec7c44304)]
|
||||
interface nsIDOMNotifyPaintEvent : nsIDOMEvent
|
||||
[builtinclass, uuid(63f573a0-3e4e-474b-a0c2-bb4ca93febaa)]
|
||||
interface nsIDOMNotifyPaintEvent : nsISupports
|
||||
{
|
||||
/**
|
||||
* Get a list of rectangles which are affected. The rectangles are in CSS pixels
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* Transition events are defined in:
|
||||
@ -11,8 +11,8 @@
|
||||
* http://dev.w3.org/csswg/css3-transitions/#transition-events-
|
||||
*/
|
||||
|
||||
[builtinclass, uuid(acb69403-0dcb-4db0-9ffc-8a22cc56c4eb)]
|
||||
interface nsIDOMTransitionEvent : nsIDOMEvent {
|
||||
[builtinclass, uuid(ee3499bf-0f14-4bb6-829c-19ad24fd4a85)]
|
||||
interface nsIDOMTransitionEvent : nsISupports {
|
||||
readonly attribute DOMString propertyName;
|
||||
readonly attribute float elapsedTime;
|
||||
readonly attribute DOMString pseudoElement;
|
||||
|
@ -3,7 +3,8 @@
|
||||
* 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 "nsIDOMEvent.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMWindow.idl"
|
||||
|
||||
/**
|
||||
* The nsIDOMUIEvent interface is the datatype for all UI events in the
|
||||
@ -13,8 +14,18 @@
|
||||
* http://www.w3.org/TR/DOM-Level-2-Events/
|
||||
*/
|
||||
|
||||
[builtinclass, uuid(db058d10-1db9-4cf9-bb4c-483c304a137f)]
|
||||
interface nsIDOMUIEvent : nsIDOMEvent
|
||||
%{C++
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Event;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native EventPtr(mozilla::dom::Event);
|
||||
|
||||
[builtinclass, uuid(75996b57-51f0-4c9c-aaaa-e35eaf347b66)]
|
||||
interface nsIDOMUIEvent : nsISupports
|
||||
{
|
||||
readonly attribute nsIDOMWindow view;
|
||||
readonly attribute long detail;
|
||||
@ -38,4 +49,6 @@ interface nsIDOMUIEvent : nsIDOMEvent
|
||||
attribute boolean cancelBubble;
|
||||
|
||||
readonly attribute boolean isChar;
|
||||
|
||||
[notxpcom, nostdcall] EventPtr AsEvent();
|
||||
};
|
||||
|
@ -651,30 +651,34 @@ GeckoMediaPluginServiceParent::UnloadPlugins()
|
||||
NS_LITERAL_CSTRING("Starting to unload plugins"));
|
||||
#endif
|
||||
|
||||
nsTArray<RefPtr<GMPParent>> plugins;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
LOGD(("%s::%s plugins:%u including async:%u", __CLASS__, __FUNCTION__,
|
||||
mPlugins.Length(), mAsyncShutdownPlugins.Length()));
|
||||
// Move all plugins references to a local array. This way mMutex won't be
|
||||
// locked when calling CloseActive (to avoid inter-locking).
|
||||
plugins = Move(mPlugins);
|
||||
}
|
||||
|
||||
LOGD(("%s::%s plugins:%u including async:%u", __CLASS__, __FUNCTION__,
|
||||
plugins.Length(), mAsyncShutdownPlugins.Length()));
|
||||
#ifdef DEBUG
|
||||
for (const auto& plugin : mPlugins) {
|
||||
LOGD(("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
|
||||
plugin->GetDisplayName().get()));
|
||||
}
|
||||
for (const auto& plugin : mAsyncShutdownPlugins) {
|
||||
LOGD(("%s::%s async plugin: '%s'", __CLASS__, __FUNCTION__,
|
||||
plugin->GetDisplayName().get()));
|
||||
}
|
||||
for (const auto& plugin : plugins) {
|
||||
LOGD(("%s::%s plugin: '%s'", __CLASS__, __FUNCTION__,
|
||||
plugin->GetDisplayName().get()));
|
||||
}
|
||||
for (const auto& plugin : mAsyncShutdownPlugins) {
|
||||
LOGD(("%s::%s async plugin: '%s'", __CLASS__, __FUNCTION__,
|
||||
plugin->GetDisplayName().get()));
|
||||
}
|
||||
#endif
|
||||
// Note: CloseActive may be async; it could actually finish
|
||||
// shutting down when all the plugins have unloaded.
|
||||
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||
// Note: CloseActive may be async; it could actually finish
|
||||
// shutting down when all the plugins have unloaded.
|
||||
for (const auto& plugin : plugins) {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
SetAsyncShutdownPluginState(mPlugins[i], 'S',
|
||||
NS_LITERAL_CSTRING("CloseActive"));
|
||||
SetAsyncShutdownPluginState(plugin, 'S',
|
||||
NS_LITERAL_CSTRING("CloseActive"));
|
||||
#endif
|
||||
mPlugins[i]->CloseActive(true);
|
||||
}
|
||||
mPlugins.Clear();
|
||||
plugin->CloseActive(true);
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
@ -1061,6 +1065,13 @@ GeckoMediaPluginServiceParent::RemoveOnGMPThread(const nsAString& aDirectory,
|
||||
}
|
||||
|
||||
if (aDeleteFromDisk && !inUse) {
|
||||
// Ensure the GMP dir and all files in it are writable, so we have
|
||||
// permission to delete them.
|
||||
directory->SetPermissions(0700);
|
||||
DirectoryEnumerator iter(directory, DirectoryEnumerator::FilesAndDirs);
|
||||
for (nsCOMPtr<nsIFile> dirEntry; (dirEntry = iter.Next()) != nullptr;) {
|
||||
dirEntry->SetPermissions(0700);
|
||||
}
|
||||
if (NS_SUCCEEDED(directory->Remove(true))) {
|
||||
mPluginsWaitingForDeletion.RemoveElement(aDirectory);
|
||||
NS_DispatchToMainThread(new NotifyObserversTask("gmp-directory-deleted",
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <media/IOMX.h>
|
||||
#include <utils/List.h>
|
||||
#include <media/stagefright/OMXCodec.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
extern mozilla::LogModule* GetPDMLog();
|
||||
|
||||
@ -43,6 +44,13 @@ bool IsSoftwareCodec(const char* aComponentName) {
|
||||
return (str.Find(NS_LITERAL_CSTRING("OMX.google.")) == -1 ? false : true);
|
||||
}
|
||||
|
||||
bool IsInEmulator()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
return !strncmp(propQemu, "1", 1);
|
||||
}
|
||||
|
||||
class GonkOmxObserver : public BnOMXObserver {
|
||||
public:
|
||||
void onMessage(const omx_message& aMsg)
|
||||
@ -289,7 +297,10 @@ GonkBufferData::GetPlatformMediaData()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(mTextureClientRecycleHandler);
|
||||
if (!mTextureClientRecycleHandler) {
|
||||
// There is no GraphicBuffer, it should fallback to normal YUV420 VideoData.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VideoInfo info;
|
||||
info.mDisplay = mGonkPlatformLayer->GetTrackInfo()->GetAsVideoInfo()->mDisplay;
|
||||
@ -520,35 +531,39 @@ GonkOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo)
|
||||
return OMX_ErrorUndefined;
|
||||
}
|
||||
|
||||
bool useHardwareCodecOnly = false;
|
||||
|
||||
// H264 and H263 has different profiles, software codec doesn't support high profile.
|
||||
// So we use hardware codec only.
|
||||
if (!IsInEmulator() &&
|
||||
(mInfo->mMimeType.EqualsLiteral("video/avc") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/mp4") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/mp4v-es") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/3gp"))) {
|
||||
useHardwareCodecOnly = true;
|
||||
}
|
||||
|
||||
LOG("find componenet for mime type %s", mInfo->mMimeType.Data());
|
||||
// In Gonk, the software component name has prefix "OMX.google". It needs to
|
||||
// have a way to use hardware codec first.
|
||||
android::Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
|
||||
const char* swcomponent = nullptr;
|
||||
nsTArray<const char*> components;
|
||||
OMXCodec::findMatchingCodecs(mInfo->mMimeType.Data(),
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
&matchingCodecs);
|
||||
for (uint32_t i = 0; i < matchingCodecs.size(); i++) {
|
||||
const char* componentName = matchingCodecs.itemAt(i).mName.string();
|
||||
if (IsSoftwareCodec(componentName)) {
|
||||
swcomponent = componentName;
|
||||
} else {
|
||||
// Try to use hardware codec first.
|
||||
if (LoadComponent(componentName)) {
|
||||
mUsingHardwareCodec = true;
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
LOG("failed to load component %s", componentName);
|
||||
}
|
||||
components.AppendElement(matchingCodecs.itemAt(i).mName.string());
|
||||
}
|
||||
|
||||
// TODO: in android ICS, the software codec is allocated in mediaserver by
|
||||
// default, it may be necessary to allocate it in local process.
|
||||
//
|
||||
// fallback to sw codec
|
||||
if (swcomponent && LoadComponent(swcomponent)) {
|
||||
return OMX_ErrorNone;
|
||||
for (auto name : components) {
|
||||
if (IsSoftwareCodec(name) && useHardwareCodecOnly) {
|
||||
continue;
|
||||
}
|
||||
if (LoadComponent(name)) {
|
||||
return OMX_ErrorNone;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("no component is loaded");
|
||||
|
@ -23,6 +23,8 @@ extern mozilla::LogModule* GetPDMLog();
|
||||
return; \
|
||||
} \
|
||||
|
||||
// There should be a better way to calculate it.
|
||||
#define MIN_VIDEO_INPUT_BUFFER_SIZE 64 * 1024
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -60,11 +62,52 @@ void GetPortIndex(nsTArray<uint32_t>& aPortIndex) {
|
||||
aPortIndex.AppendElement(1);
|
||||
}
|
||||
|
||||
template<class T> void
|
||||
InitOmxParameter(T* aParam)
|
||||
{
|
||||
PodZero(aParam);
|
||||
aParam->nSize = sizeof(T);
|
||||
aParam->nVersion.s.nVersionMajor = 1;
|
||||
}
|
||||
|
||||
// A helper class to retrieve AudioData or VideoData.
|
||||
class MediaDataHelper {
|
||||
protected:
|
||||
virtual ~MediaDataHelper() {}
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataHelper)
|
||||
|
||||
MediaDataHelper(const TrackInfo* aTrackInfo,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
OmxPromiseLayer* aOmxLayer);
|
||||
|
||||
already_AddRefed<MediaData> GetMediaData(BufferData* aBufferData, bool& aPlatformDepenentData);
|
||||
|
||||
protected:
|
||||
already_AddRefed<AudioData> CreateAudioData(BufferData* aBufferData);
|
||||
|
||||
already_AddRefed<VideoData> CreateYUV420VideoData(BufferData* aBufferData);
|
||||
|
||||
const TrackInfo* mTrackInfo;
|
||||
|
||||
OMX_PARAM_PORTDEFINITIONTYPE mOutputPortDef;
|
||||
|
||||
// audio output
|
||||
MediaQueue<AudioData> mAudioQueue;
|
||||
|
||||
AudioCompactor mAudioCompactor;
|
||||
|
||||
// video output
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
};
|
||||
|
||||
OmxDataDecoder::OmxDataDecoder(const TrackInfo& aTrackInfo,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
: mMonitor("OmxDataDecoder")
|
||||
, mOmxTaskQueue(CreateMediaDecodeTaskQueue())
|
||||
, mImageContainer(aImageContainer)
|
||||
, mWatchManager(this, mOmxTaskQueue)
|
||||
, mOmxState(OMX_STATETYPE::OMX_StateInvalid, "OmxDataDecoder::mOmxState")
|
||||
, mTrackInfo(aTrackInfo.Clone())
|
||||
@ -72,7 +115,6 @@ OmxDataDecoder::OmxDataDecoder(const TrackInfo& aTrackInfo,
|
||||
, mShuttingDown(false)
|
||||
, mCheckingInputExhausted(false)
|
||||
, mPortSettingsChanged(-1, "OmxDataDecoder::mPortSettingsChanged")
|
||||
, mAudioCompactor(mAudioQueue)
|
||||
, mCallback(aCallback)
|
||||
{
|
||||
LOG("(%p)", this);
|
||||
@ -272,6 +314,7 @@ OmxDataDecoder::DoAsyncShutdown()
|
||||
self->mOmxLayer->Shutdown();
|
||||
self->mWatchManager.Shutdown();
|
||||
self->mOmxLayer = nullptr;
|
||||
self->mMediaDataHelper = nullptr;
|
||||
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
self->mShuttingDown = false;
|
||||
@ -281,6 +324,7 @@ OmxDataDecoder::DoAsyncShutdown()
|
||||
self->mOmxLayer->Shutdown();
|
||||
self->mWatchManager.Shutdown();
|
||||
self->mOmxLayer = nullptr;
|
||||
self->mMediaDataHelper = nullptr;
|
||||
|
||||
MonitorAutoLock lock(self->mMonitor);
|
||||
self->mShuttingDown = false;
|
||||
@ -288,80 +332,6 @@ OmxDataDecoder::DoAsyncShutdown()
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
OmxDataDecoder::OutputAudio(BufferData* aBufferData)
|
||||
{
|
||||
// TODO: it'd be better to move these code to BufferData::GetPlatformMediaData() or
|
||||
// some kind of abstract layer.
|
||||
MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
|
||||
OMX_BUFFERHEADERTYPE* buf = aBufferData->mBuffer;
|
||||
AudioInfo* info = mTrackInfo->GetAsAudioInfo();
|
||||
if (buf->nFilledLen) {
|
||||
uint64_t offset = 0;
|
||||
uint32_t frames = buf->nFilledLen / (2 * info->mChannels);
|
||||
if (aBufferData->mRawData) {
|
||||
offset = aBufferData->mRawData->mOffset;
|
||||
}
|
||||
typedef AudioCompactor::NativeCopy OmxCopy;
|
||||
mAudioCompactor.Push(offset,
|
||||
buf->nTimeStamp,
|
||||
info->mRate,
|
||||
frames,
|
||||
info->mChannels,
|
||||
OmxCopy(buf->pBuffer + buf->nOffset,
|
||||
buf->nFilledLen,
|
||||
info->mChannels));
|
||||
RefPtr<AudioData> audio = mAudioQueue.PopFront();
|
||||
mCallback->Output(audio);
|
||||
}
|
||||
aBufferData->mStatus = BufferData::BufferStatus::FREE;
|
||||
}
|
||||
|
||||
void
|
||||
OmxDataDecoder::OutputVideo(BufferData* aBufferData)
|
||||
{
|
||||
MOZ_ASSERT(mOmxTaskQueue->IsCurrentThreadIn());
|
||||
|
||||
RefPtr<MediaData> data = aBufferData->GetPlatformMediaData();
|
||||
MOZ_RELEASE_ASSERT(data);
|
||||
|
||||
VideoData* video(data->As<VideoData>());
|
||||
if (aBufferData->mRawData) {
|
||||
video->mTime = aBufferData->mRawData->mTime;
|
||||
video->mTimecode = aBufferData->mRawData->mTimecode;
|
||||
video->mOffset = aBufferData->mRawData->mOffset;
|
||||
video->mDuration = aBufferData->mRawData->mDuration;
|
||||
video->mKeyframe = aBufferData->mRawData->mKeyframe;
|
||||
}
|
||||
|
||||
aBufferData->mStatus = BufferData::BufferStatus::OMX_CLIENT_OUTPUT;
|
||||
|
||||
// TextureClient's recycle callback is called when reference count of
|
||||
// TextureClient becomes 1. In most cases, the last reference count is held
|
||||
// by ITextureClientRecycleAllocator.
|
||||
// And then promise will be resolved in the callback.
|
||||
// TODO:
|
||||
// Because it is gonk specific behaviour, it needs to find a way to
|
||||
// proper abstracting it.
|
||||
MOZ_RELEASE_ASSERT(aBufferData->mPromise.IsEmpty());
|
||||
RefPtr<OmxBufferPromise> p = aBufferData->mPromise.Ensure(__func__);
|
||||
|
||||
RefPtr<OmxDataDecoder> self = this;
|
||||
RefPtr<BufferData> buffer = aBufferData;
|
||||
p->Then(mOmxTaskQueue, __func__,
|
||||
[self, buffer] () {
|
||||
MOZ_RELEASE_ASSERT(buffer->mStatus == BufferData::BufferStatus::OMX_CLIENT_OUTPUT);
|
||||
buffer->mStatus = BufferData::BufferStatus::FREE;
|
||||
self->FillAndEmptyBuffers();
|
||||
},
|
||||
[buffer] () {
|
||||
MOZ_RELEASE_ASSERT(buffer->mStatus == BufferData::BufferStatus::OMX_CLIENT_OUTPUT);
|
||||
buffer->mStatus = BufferData::BufferStatus::FREE;
|
||||
});
|
||||
|
||||
mCallback->Output(video);
|
||||
}
|
||||
|
||||
void
|
||||
OmxDataDecoder::FillBufferDone(BufferData* aData)
|
||||
{
|
||||
@ -383,17 +353,53 @@ OmxDataDecoder::FillBufferDone(BufferData* aData)
|
||||
EndOfStream();
|
||||
aData->mStatus = BufferData::BufferStatus::FREE;
|
||||
} else {
|
||||
if (mTrackInfo->IsAudio()) {
|
||||
OutputAudio(aData);
|
||||
} else if (mTrackInfo->IsVideo()) {
|
||||
OutputVideo(aData);
|
||||
} else {
|
||||
MOZ_ASSERT(0);
|
||||
}
|
||||
Output(aData);
|
||||
FillAndEmptyBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OmxDataDecoder::Output(BufferData* aData)
|
||||
{
|
||||
if (!mMediaDataHelper) {
|
||||
mMediaDataHelper = new MediaDataHelper(mTrackInfo.get(), mImageContainer, mOmxLayer);
|
||||
}
|
||||
|
||||
bool isPlatformData = false;
|
||||
RefPtr<MediaData> data = mMediaDataHelper->GetMediaData(aData, isPlatformData);
|
||||
if (!data) {
|
||||
aData->mStatus = BufferData::BufferStatus::FREE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlatformData) {
|
||||
// If the MediaData is platform dependnet data, it's mostly a kind of
|
||||
// limited resource, for example, GraphicBuffer on Gonk. So we use promise
|
||||
// to notify when the resource is free.
|
||||
aData->mStatus = BufferData::BufferStatus::OMX_CLIENT_OUTPUT;
|
||||
|
||||
MOZ_RELEASE_ASSERT(aData->mPromise.IsEmpty());
|
||||
RefPtr<OmxBufferPromise> p = aData->mPromise.Ensure(__func__);
|
||||
|
||||
RefPtr<OmxDataDecoder> self = this;
|
||||
RefPtr<BufferData> buffer = aData;
|
||||
p->Then(mOmxTaskQueue, __func__,
|
||||
[self, buffer] () {
|
||||
MOZ_RELEASE_ASSERT(buffer->mStatus == BufferData::BufferStatus::OMX_CLIENT_OUTPUT);
|
||||
buffer->mStatus = BufferData::BufferStatus::FREE;
|
||||
self->FillAndEmptyBuffers();
|
||||
},
|
||||
[buffer] () {
|
||||
MOZ_RELEASE_ASSERT(buffer->mStatus == BufferData::BufferStatus::OMX_CLIENT_OUTPUT);
|
||||
buffer->mStatus = BufferData::BufferStatus::FREE;
|
||||
});
|
||||
} else {
|
||||
aData->mStatus = BufferData::BufferStatus::FREE;
|
||||
}
|
||||
|
||||
mCallback->Output(data);
|
||||
}
|
||||
|
||||
void
|
||||
OmxDataDecoder::FillBufferFailure(OmxBufferFailureHolder aFailureHolder)
|
||||
{
|
||||
@ -515,6 +521,7 @@ OmxDataDecoder::FindAvailableBuffer(OMX_DIRTYPE aType)
|
||||
if (buf->mStatus == BufferData::BufferStatus::FREE) {
|
||||
return buf;
|
||||
}
|
||||
LOG("buffer is owned by %d, type %d", buf->mStatus, aType);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -689,6 +696,10 @@ OmxDataDecoder::ConfigVideoCodec()
|
||||
if (def.eDir == OMX_DirInput) {
|
||||
def.format.video.eCompressionFormat = codetype;
|
||||
def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
|
||||
if (def.nBufferSize < MIN_VIDEO_INPUT_BUFFER_SIZE) {
|
||||
def.nBufferSize = videoInfo->mImage.width * videoInfo->mImage.height;
|
||||
LOG("Change input buffer size to %d", def.nBufferSize);
|
||||
}
|
||||
} else {
|
||||
def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
|
||||
}
|
||||
@ -749,15 +760,19 @@ OmxDataDecoder::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2)
|
||||
switch (aEvent) {
|
||||
case OMX_EventPortSettingsChanged:
|
||||
{
|
||||
// According to spec: "To prevent the loss of any input data, the
|
||||
// component issuing the OMX_EventPortSettingsChanged event on its input
|
||||
// port should buffer all input port data that arrives between the
|
||||
// emission of the OMX_EventPortSettingsChanged event and the arrival of
|
||||
// the command to disable the input port."
|
||||
//
|
||||
// So client needs to disable port and reallocate buffers.
|
||||
MOZ_ASSERT(mPortSettingsChanged == -1);
|
||||
mPortSettingsChanged = aData1;
|
||||
// Don't always disable port. See bug 1235340.
|
||||
if (aData2 == 0 ||
|
||||
aData2 == OMX_IndexParamPortDefinition) {
|
||||
// According to spec: "To prevent the loss of any input data, the
|
||||
// component issuing the OMX_EventPortSettingsChanged event on its input
|
||||
// port should buffer all input port data that arrives between the
|
||||
// emission of the OMX_EventPortSettingsChanged event and the arrival of
|
||||
// the command to disable the input port."
|
||||
//
|
||||
// So client needs to disable port and reallocate buffers.
|
||||
MOZ_ASSERT(mPortSettingsChanged == -1);
|
||||
mPortSettingsChanged = aData1;
|
||||
}
|
||||
LOG("Got OMX_EventPortSettingsChanged event");
|
||||
break;
|
||||
}
|
||||
@ -772,14 +787,6 @@ OmxDataDecoder::Event(OMX_EVENTTYPE aEvent, OMX_U32 aData1, OMX_U32 aData2)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T> void
|
||||
OmxDataDecoder::InitOmxParameter(T* aParam)
|
||||
{
|
||||
PodZero(aParam);
|
||||
aParam->nSize = sizeof(T);
|
||||
aParam->nVersion.s.nVersionMajor = 1;
|
||||
}
|
||||
|
||||
bool
|
||||
OmxDataDecoder::BuffersCanBeReleased(OMX_DIRTYPE aType)
|
||||
{
|
||||
@ -975,4 +982,150 @@ void OmxDataDecoder::FlushFailure(OmxCommandFailureHolder aFailureHolder)
|
||||
mMonitor.Notify();
|
||||
}
|
||||
|
||||
MediaDataHelper::MediaDataHelper(const TrackInfo* aTrackInfo,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
OmxPromiseLayer* aOmxLayer)
|
||||
: mTrackInfo(aTrackInfo)
|
||||
, mAudioCompactor(mAudioQueue)
|
||||
, mImageContainer(aImageContainer)
|
||||
{
|
||||
// Get latest port definition.
|
||||
nsTArray<uint32_t> ports;
|
||||
GetPortIndex(ports);
|
||||
for (auto idx : ports) {
|
||||
InitOmxParameter(&mOutputPortDef);
|
||||
mOutputPortDef.nPortIndex = idx;
|
||||
aOmxLayer->GetParameter(OMX_IndexParamPortDefinition, &mOutputPortDef, sizeof(mOutputPortDef));
|
||||
if (mOutputPortDef.eDir == OMX_DirOutput) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<MediaData>
|
||||
MediaDataHelper::GetMediaData(BufferData* aBufferData, bool& aPlatformDepenentData)
|
||||
{
|
||||
aPlatformDepenentData = false;
|
||||
RefPtr<MediaData> data;
|
||||
|
||||
if (mTrackInfo->IsAudio()) {
|
||||
if (!aBufferData->mBuffer->nFilledLen) {
|
||||
return nullptr;
|
||||
}
|
||||
data = CreateAudioData(aBufferData);
|
||||
} else if (mTrackInfo->IsVideo()) {
|
||||
data = aBufferData->GetPlatformMediaData();
|
||||
if (data) {
|
||||
aPlatformDepenentData = true;
|
||||
} else {
|
||||
if (!aBufferData->mBuffer->nFilledLen) {
|
||||
return nullptr;
|
||||
}
|
||||
// Get YUV VideoData, it uses more CPU, in most cases, on software codec.
|
||||
data = CreateYUV420VideoData(aBufferData);
|
||||
}
|
||||
|
||||
// Update video time code, duration... from the raw data.
|
||||
VideoData* video(data->As<VideoData>());
|
||||
if (aBufferData->mRawData) {
|
||||
video->mTime = aBufferData->mRawData->mTime;
|
||||
video->mTimecode = aBufferData->mRawData->mTimecode;
|
||||
video->mOffset = aBufferData->mRawData->mOffset;
|
||||
video->mDuration = aBufferData->mRawData->mDuration;
|
||||
video->mKeyframe = aBufferData->mRawData->mKeyframe;
|
||||
}
|
||||
}
|
||||
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<AudioData>
|
||||
MediaDataHelper::CreateAudioData(BufferData* aBufferData)
|
||||
{
|
||||
RefPtr<AudioData> audio;
|
||||
OMX_BUFFERHEADERTYPE* buf = aBufferData->mBuffer;
|
||||
const AudioInfo* info = mTrackInfo->GetAsAudioInfo();
|
||||
if (buf->nFilledLen) {
|
||||
uint64_t offset = 0;
|
||||
uint32_t frames = buf->nFilledLen / (2 * info->mChannels);
|
||||
if (aBufferData->mRawData) {
|
||||
offset = aBufferData->mRawData->mOffset;
|
||||
}
|
||||
typedef AudioCompactor::NativeCopy OmxCopy;
|
||||
mAudioCompactor.Push(offset,
|
||||
buf->nTimeStamp,
|
||||
info->mRate,
|
||||
frames,
|
||||
info->mChannels,
|
||||
OmxCopy(buf->pBuffer + buf->nOffset,
|
||||
buf->nFilledLen,
|
||||
info->mChannels));
|
||||
audio = mAudioQueue.PopFront();
|
||||
}
|
||||
|
||||
return audio.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<VideoData>
|
||||
MediaDataHelper::CreateYUV420VideoData(BufferData* aBufferData)
|
||||
{
|
||||
uint8_t *yuv420p_buffer = (uint8_t *)aBufferData->mBuffer->pBuffer;
|
||||
int32_t stride = mOutputPortDef.format.video.nStride;
|
||||
int32_t slice_height = mOutputPortDef.format.video.nSliceHeight;
|
||||
int32_t width = mTrackInfo->GetAsVideoInfo()->mImage.width;
|
||||
int32_t height = mTrackInfo->GetAsVideoInfo()->mImage.height;
|
||||
|
||||
// TODO: convert other formats to YUV420.
|
||||
if (mOutputPortDef.format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t yuv420p_y_size = stride * slice_height;
|
||||
size_t yuv420p_u_size = ((stride + 1) / 2) * ((slice_height + 1) / 2);
|
||||
uint8_t *yuv420p_y = yuv420p_buffer;
|
||||
uint8_t *yuv420p_u = yuv420p_y + yuv420p_y_size;
|
||||
uint8_t *yuv420p_v = yuv420p_u + yuv420p_u_size;
|
||||
|
||||
VideoData::YCbCrBuffer b;
|
||||
b.mPlanes[0].mData = yuv420p_y;
|
||||
b.mPlanes[0].mWidth = width;
|
||||
b.mPlanes[0].mHeight = height;
|
||||
b.mPlanes[0].mStride = stride;
|
||||
b.mPlanes[0].mOffset = 0;
|
||||
b.mPlanes[0].mSkip = 0;
|
||||
|
||||
b.mPlanes[1].mData = yuv420p_u;
|
||||
b.mPlanes[1].mWidth = (width + 1) / 2;
|
||||
b.mPlanes[1].mHeight = (height + 1) / 2;
|
||||
b.mPlanes[1].mStride = (stride + 1) / 2;
|
||||
b.mPlanes[1].mOffset = 0;
|
||||
b.mPlanes[1].mSkip = 0;
|
||||
|
||||
b.mPlanes[2].mData = yuv420p_v;
|
||||
b.mPlanes[2].mWidth =(width + 1) / 2;
|
||||
b.mPlanes[2].mHeight = (height + 1) / 2;
|
||||
b.mPlanes[2].mStride = (stride + 1) / 2;
|
||||
b.mPlanes[2].mOffset = 0;
|
||||
b.mPlanes[2].mSkip = 0;
|
||||
|
||||
VideoInfo info;
|
||||
info.mDisplay = mTrackInfo->GetAsVideoInfo()->mDisplay;
|
||||
info.mImage = mTrackInfo->GetAsVideoInfo()->mImage;
|
||||
RefPtr<VideoData> data = VideoData::Create(info,
|
||||
mImageContainer,
|
||||
0, // Filled later by caller.
|
||||
0, // Filled later by caller.
|
||||
1, // We don't know the duration.
|
||||
b,
|
||||
0, // Filled later by caller.
|
||||
-1,
|
||||
info.mImage);
|
||||
|
||||
LOG("YUV420 VideoData: disp width %d, height %d, pic width %d, height %d, time %ld",
|
||||
info.mDisplay.width, info.mDisplay.height, info.mImage.width,
|
||||
info.mImage.height, aBufferData->mBuffer->nTimeStamp);
|
||||
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,9 +12,13 @@
|
||||
#include "OmxPromiseLayer.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "AudioCompactor.h"
|
||||
#include "OMX_Component.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaDataHelper;
|
||||
|
||||
typedef OmxPromiseLayer::OmxCommandPromise OmxCommandPromise;
|
||||
typedef OmxPromiseLayer::OmxBufferPromise OmxBufferPromise;
|
||||
typedef OmxPromiseLayer::OmxBufferFailureHolder OmxBufferFailureHolder;
|
||||
@ -110,9 +114,7 @@ protected:
|
||||
// the port format is changed due to different codec specific.
|
||||
void PortSettingsChanged();
|
||||
|
||||
void OutputAudio(BufferData* aBufferData);
|
||||
|
||||
void OutputVideo(BufferData* aBufferData);
|
||||
void Output(BufferData* aData);
|
||||
|
||||
// Buffer can be released if its status is not OMX_COMPONENT or
|
||||
// OMX_CLIENT_OUTPUT.
|
||||
@ -136,8 +138,6 @@ protected:
|
||||
|
||||
BufferData* FindAvailableBuffer(OMX_DIRTYPE aType);
|
||||
|
||||
template<class T> void InitOmxParameter(T* aParam);
|
||||
|
||||
// aType could be OMX_DirMax for all types.
|
||||
RefPtr<OmxPromiseLayer::OmxBufferPromise::AllPromiseType>
|
||||
CollectBufferPromises(OMX_DIRTYPE aType);
|
||||
@ -149,6 +149,8 @@ protected:
|
||||
|
||||
RefPtr<TaskQueue> mReaderTaskQueue;
|
||||
|
||||
RefPtr<layers::ImageContainer> mImageContainer;
|
||||
|
||||
WatchManager<OmxDataDecoder> mWatchManager;
|
||||
|
||||
// It is accessed in omx TaskQueue.
|
||||
@ -185,12 +187,7 @@ protected:
|
||||
|
||||
BUFFERLIST mOutPortBuffers;
|
||||
|
||||
// For audio output.
|
||||
// TODO: because this class is for both video and audio decoding, so there
|
||||
// should be some kind of abstract things to these members.
|
||||
MediaQueue<AudioData> mAudioQueue;
|
||||
|
||||
AudioCompactor mAudioCompactor;
|
||||
RefPtr<MediaDataHelper> mMediaDataHelper;
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
};
|
||||
|
@ -44,7 +44,12 @@ OmxDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
|
||||
bool
|
||||
OmxDecoderModule::SupportsMimeType(const nsACString& aMimeType) const
|
||||
{
|
||||
// TODO: it could be better to query the support mine types from OMX instead
|
||||
// of hard coding.
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("video/mp4v-es") ||
|
||||
aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/3gp") ||
|
||||
aMimeType.EqualsLiteral("video/avc");
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ already_AddRefed<MediaRawData>
|
||||
OmxPromiseLayer::FindAndRemoveRawData(OMX_TICKS aTimecode)
|
||||
{
|
||||
for (auto raw : mRawDatas) {
|
||||
if (raw->mTimecode == aTimecode) {
|
||||
if (raw->mTime == aTimecode) {
|
||||
mRawDatas.RemoveElement(raw);
|
||||
return raw.forget();
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
#include "nsIContent.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/GCHashTable.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/plugins/PluginAsyncSurrogate.h"
|
||||
@ -42,21 +43,33 @@ using namespace mozilla;
|
||||
using mozilla::plugins::PluginScriptableObjectParent;
|
||||
using mozilla::plugins::ParentNPObject;
|
||||
|
||||
struct JSObjWrapperHasher : public js::DefaultHasher<nsJSObjWrapperKey>
|
||||
struct JSObjWrapperHasher
|
||||
{
|
||||
typedef nsJSObjWrapperKey Key;
|
||||
typedef Key Lookup;
|
||||
|
||||
static uint32_t hash(const Lookup &l) {
|
||||
return HashGeneric(l.mJSObj, l.mNpp);
|
||||
return js::MovableCellHasher<JS::Heap<JSObject*>>::hash(l.mJSObj) ^
|
||||
HashGeneric(l.mNpp);
|
||||
}
|
||||
|
||||
static void rekey(Key &k, const Key& newKey) {
|
||||
MOZ_ASSERT(k.mNpp == newKey.mNpp);
|
||||
k.mJSObj = newKey.mJSObj;
|
||||
static bool match(const Key& k, const Lookup &l) {
|
||||
return js::MovableCellHasher<JS::Heap<JSObject*>>::match(k.mJSObj, l.mJSObj) &&
|
||||
k.mNpp == l.mNpp;
|
||||
}
|
||||
};
|
||||
|
||||
namespace js {
|
||||
template <>
|
||||
struct DefaultGCPolicy<nsJSObjWrapper*> {
|
||||
static void trace(JSTracer* trc, nsJSObjWrapper** wrapper, const char* name) {
|
||||
MOZ_ASSERT(wrapper);
|
||||
MOZ_ASSERT(*wrapper);
|
||||
(*wrapper)->trace(trc);
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
|
||||
class NPObjWrapperHashEntry : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
@ -72,10 +85,10 @@ public:
|
||||
// when a plugin is torn down in case there's a leak in the plugin (we
|
||||
// don't want to leak the world just because a plugin leaks an
|
||||
// NPObject).
|
||||
typedef js::HashMap<nsJSObjWrapperKey,
|
||||
nsJSObjWrapper*,
|
||||
JSObjWrapperHasher,
|
||||
js::SystemAllocPolicy> JSObjWrapperTable;
|
||||
typedef js::GCHashMap<nsJSObjWrapperKey,
|
||||
nsJSObjWrapper*,
|
||||
JSObjWrapperHasher,
|
||||
js::SystemAllocPolicy> JSObjWrapperTable;
|
||||
static JSObjWrapperTable sJSObjWrappers;
|
||||
|
||||
// Whether it's safe to iterate sJSObjWrappers. Set to true when sJSObjWrappers
|
||||
@ -278,20 +291,8 @@ OnWrapperDestroyed();
|
||||
static void
|
||||
TraceJSObjWrappers(JSTracer *trc, void *data)
|
||||
{
|
||||
if (!sJSObjWrappers.initialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trace all JSObjects in the sJSObjWrappers table and rekey the entries if
|
||||
// any of them moved.
|
||||
for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
|
||||
nsJSObjWrapperKey key = e.front().key();
|
||||
JS::UnsafeTraceRoot(trc, &key.mJSObj, "sJSObjWrappers key object");
|
||||
nsJSObjWrapper *wrapper = e.front().value();
|
||||
JS::TraceEdge(trc, &wrapper->mJSObj, "sJSObjWrappers wrapper object");
|
||||
if (key != e.front().key()) {
|
||||
e.rekeyFront(key);
|
||||
}
|
||||
if (sJSObjWrappers.initialized()) {
|
||||
sJSObjWrappers.trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1079,33 +1080,6 @@ nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args,
|
||||
return doInvoke(npobj, NPIdentifier_VOID, args, argCount, true, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function is called during minor GCs for each key in the sJSObjWrappers
|
||||
* table that has been moved.
|
||||
*
|
||||
* Note that the wrapper may be dead at this point, and even the table may have
|
||||
* been finalized if all wrappers have died.
|
||||
*/
|
||||
static void
|
||||
JSObjWrapperKeyMarkCallback(JSTracer *trc, JSObject *obj, void *data) {
|
||||
NPP npp = static_cast<NPP>(data);
|
||||
MOZ_ASSERT(sJSObjWrappersAccessible);
|
||||
if (!sJSObjWrappers.initialized())
|
||||
return;
|
||||
|
||||
JSObject *prior = obj;
|
||||
nsJSObjWrapperKey oldKey(prior, npp);
|
||||
JSObjWrapperTable::Ptr p = sJSObjWrappers.lookup(oldKey);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
js::UnsafeTraceManuallyBarrieredEdge(trc, &obj, "sJSObjWrappers key object");
|
||||
nsJSObjWrapperKey newKey(obj, npp);
|
||||
sJSObjWrappers.rekeyIfMoved(oldKey, newKey);
|
||||
}
|
||||
|
||||
// Look up or create an NPObject that wraps the JSObject obj.
|
||||
|
||||
// static
|
||||
@ -1191,16 +1165,12 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle<JSObject*> obj)
|
||||
|
||||
// Insert the new wrapper into the hashtable, rooting the JSObject. Its
|
||||
// lifetime is now tied to that of the NPObject.
|
||||
nsJSObjWrapperKey key(obj, npp);
|
||||
if (!sJSObjWrappers.putNew(key, wrapper)) {
|
||||
if (!sJSObjWrappers.putNew(nsJSObjWrapperKey(obj, npp), wrapper)) {
|
||||
// Out of memory, free the wrapper we created.
|
||||
_releaseobject(wrapper);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add postbarrier for the hashtable key
|
||||
JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper->mNpp);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "npapi.h"
|
||||
#include "npruntime.h"
|
||||
#include "PLDHashTable.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
class nsJSNPRuntime
|
||||
{
|
||||
@ -33,7 +34,11 @@ public:
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
JSObject * mJSObj;
|
||||
void trace(JSTracer* trc) {
|
||||
JS::TraceEdge(trc, &mJSObj, "nsJSObjWrapperKey");
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*> mJSObj;
|
||||
const NPP mNpp;
|
||||
};
|
||||
|
||||
@ -48,6 +53,10 @@ public:
|
||||
JS::Handle<JSObject*> obj);
|
||||
static bool HasOwnProperty(NPObject* npobj, NPIdentifier npid);
|
||||
|
||||
void trace(JSTracer* trc) {
|
||||
JS::TraceEdge(trc, &mJSObj, "nsJSObjWrapper");
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit nsJSObjWrapper(NPP npp);
|
||||
~nsJSObjWrapper();
|
||||
|
@ -55,6 +55,7 @@ using mozilla::DefaultXDisplay;
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/HTMLObjectElementBinding.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "nsFrameSelection.h"
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "prsystem.h"
|
||||
@ -679,7 +680,8 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit)
|
||||
{
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
|
||||
mIsStartingAsync = aAllowAsyncInit &&
|
||||
Preferences::GetBool(kAsyncInitPref, false);
|
||||
Preferences::GetBool(kAsyncInitPref, false) &&
|
||||
!BrowserTabsRemoteAutostart();
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
|
||||
mIsStartingAsync ?
|
||||
|
@ -80,6 +80,13 @@ PresentationRequest::WrapObject(JSContext* aCx,
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PresentationRequest::Start(ErrorResult& aRv)
|
||||
{
|
||||
return StartWithDevice(NullString(), aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
@ -124,7 +131,7 @@ PresentationRequest::Start(ErrorResult& aRv)
|
||||
|
||||
nsCOMPtr<nsIPresentationServiceCallback> callback =
|
||||
new PresentationRequesterCallback(this, mUrl, id, promise);
|
||||
rv = service->StartSession(mUrl, id, origin, callback);
|
||||
rv = service->StartSession(mUrl, id, origin, aDeviceId, callback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
@ -33,6 +33,9 @@ public:
|
||||
// WebIDL (public APIs)
|
||||
already_AddRefed<Promise> Start(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> StartWithDevice(const nsAString& aDeviceId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetAvailability(ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(connectionavailable);
|
||||
|
@ -384,6 +384,7 @@ NS_IMETHODIMP
|
||||
PresentationService::StartSession(const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aDeviceId,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@ -396,20 +397,62 @@ PresentationService::StartSession(const nsAString& aUrl,
|
||||
new PresentationControllingInfo(aUrl, aSessionId, aCallback);
|
||||
mSessionInfo.Put(aSessionId, info);
|
||||
|
||||
// Pop up a prompt and ask user to select a device.
|
||||
nsCOMPtr<nsIPresentationDevicePrompt> prompt =
|
||||
do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
|
||||
if (NS_WARN_IF(!prompt)) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
nsCOMPtr<nsIPresentationDeviceRequest> request =
|
||||
new PresentationDeviceRequest(aUrl, aSessionId, aOrigin);
|
||||
nsresult rv = prompt->PromptDeviceSelection(request);
|
||||
|
||||
if (aDeviceId.IsVoid()) {
|
||||
// Pop up a prompt and ask user to select a device.
|
||||
nsCOMPtr<nsIPresentationDevicePrompt> prompt =
|
||||
do_GetService(PRESENTATION_DEVICE_PROMPT_CONTRACTID);
|
||||
if (NS_WARN_IF(!prompt)) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
nsresult rv = prompt->PromptDeviceSelection(request);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Find the designated device from available device list.
|
||||
nsCOMPtr<nsIPresentationDeviceManager> deviceManager =
|
||||
do_GetService(PRESENTATION_DEVICE_MANAGER_CONTRACTID);
|
||||
if (NS_WARN_IF(!deviceManager)) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIArray> devices;
|
||||
nsresult rv = deviceManager->GetAvailableDevices(getter_AddRefs(devices));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsISimpleEnumerator> enumerator;
|
||||
rv = devices->Enumerate(getter_AddRefs(enumerator));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return info->ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 utf8DeviceId(aDeviceId);
|
||||
bool hasMore;
|
||||
while(NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore){
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = enumerator->GetNext(getter_AddRefs(isupports));
|
||||
|
||||
nsCOMPtr<nsIPresentationDevice> device(do_QueryInterface(isupports));
|
||||
MOZ_ASSERT(device);
|
||||
|
||||
nsAutoCString id;
|
||||
if (NS_SUCCEEDED(device->GetId(id)) && id.Equals(utf8DeviceId)) {
|
||||
request->Select(device);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Reject if designated device is not available.
|
||||
return info->ReplyError(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -33,7 +33,7 @@ interface nsIPresentationServiceCallback : nsISupports
|
||||
void notifyError(in nsresult error);
|
||||
};
|
||||
|
||||
[scriptable, uuid(c177a13a-bf1a-48bf-8032-d415c3343c46)]
|
||||
[scriptable, uuid(2e360359-c45c-4949-bf95-410242ce483f)]
|
||||
interface nsIPresentationService : nsISupports
|
||||
{
|
||||
/*
|
||||
@ -43,6 +43,8 @@ interface nsIPresentationService : nsISupports
|
||||
* @param url: The url of presenting page.
|
||||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param origin: The url of requesting page.
|
||||
* @param deviceId: The specified device of handling this request, null string
|
||||
for prompt device selection dialog.
|
||||
* @param callback: Invoke the callback when the operation is completed.
|
||||
* NotifySuccess() is called with |id| if a session is
|
||||
* established successfully with the selected device.
|
||||
@ -51,6 +53,7 @@ interface nsIPresentationService : nsISupports
|
||||
void startSession(in DOMString url,
|
||||
in DOMString sessionId,
|
||||
in DOMString origin,
|
||||
in DOMString deviceId,
|
||||
in nsIPresentationServiceCallback callback);
|
||||
|
||||
/*
|
||||
|
@ -17,6 +17,7 @@ struct StartSessionRequest
|
||||
nsString url;
|
||||
nsString sessionId;
|
||||
nsString origin;
|
||||
nsString deviceId;
|
||||
};
|
||||
|
||||
struct SendSessionMessageRequest
|
||||
|
@ -49,10 +49,13 @@ NS_IMETHODIMP
|
||||
PresentationIPCService::StartSession(const nsAString& aUrl,
|
||||
const nsAString& aSessionId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aDeviceId,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
return SendRequest(aCallback,
|
||||
StartSessionRequest(nsAutoString(aUrl), nsAutoString(aSessionId), nsAutoString(aOrigin)));
|
||||
return SendRequest(aCallback, StartSessionRequest(nsAutoString(aUrl),
|
||||
nsAutoString(aSessionId),
|
||||
nsAutoString(aOrigin),
|
||||
nsAutoString(aDeviceId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -252,7 +252,7 @@ PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
return mService->StartSession(aRequest.url(), aRequest.sessionId(),
|
||||
aRequest.origin(), this);
|
||||
aRequest.origin(), aRequest.deviceId(), this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -17,6 +17,8 @@ skip-if = toolkit == 'android' # Bug 1129785
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender_default_request.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender_startWithDevice.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_receiver_establish_connection_error.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android' || os == 'mac' || os == 'win' || buildapp == 'mulet') # Bug 1129785, Bug 1204709
|
||||
[test_presentation_receiver_establish_connection_timeout.html]
|
||||
|
@ -0,0 +1,173 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test startWithDevice for B2G Presentation API at sender side</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239242">Test startWithDevice for B2G Presentation API at sender side</a>
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
'use strict';
|
||||
|
||||
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
|
||||
var request;
|
||||
var connection;
|
||||
|
||||
function testSetup() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
request = new PresentationRequest("http://example.com");
|
||||
|
||||
request.getAvailability().then(
|
||||
function(aAvailability) {
|
||||
aAvailability.onchange = function() {
|
||||
aAvailability.onchange = null;
|
||||
ok(aAvailability.value, "Device should be available.");
|
||||
aResolve();
|
||||
}
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when getting availability: " + aError);
|
||||
teardown();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
|
||||
gScript.sendAsyncMessage('trigger-device-add');
|
||||
});
|
||||
}
|
||||
|
||||
function testStartConnectionWithDevice() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
|
||||
gScript.removeMessageListener('device-prompt', devicePromptHandler);
|
||||
ok(false, "Device prompt should not be triggered.");
|
||||
teardown();
|
||||
aReject();
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
|
||||
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
|
||||
info("A control channel is established.");
|
||||
gScript.sendAsyncMessage('trigger-control-channel-open');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
|
||||
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
|
||||
info("The control channel is opened.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
|
||||
info("The control channel is closed. " + aReason);
|
||||
});
|
||||
|
||||
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
|
||||
gScript.removeMessageListener('offer-sent', offerSentHandler);
|
||||
ok(aIsValid, "A valid offer is sent out.");
|
||||
gScript.sendAsyncMessage('trigger-incoming-transport');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
|
||||
gScript.removeMessageListener('answer-received', answerReceivedHandler);
|
||||
info("An answer is received.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
|
||||
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
|
||||
info("Data transport channel is initialized.");
|
||||
gScript.sendAsyncMessage('trigger-incoming-answer');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
|
||||
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
|
||||
info("Data notification is enabled for data transport channel.");
|
||||
});
|
||||
|
||||
var connectionFromEvent;
|
||||
request.onconnectionavailable = function(aEvent) {
|
||||
request.onconnectionavailable = null;
|
||||
connectionFromEvent = aEvent.connection;
|
||||
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
|
||||
|
||||
if (connection) {
|
||||
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
|
||||
aResolve();
|
||||
}
|
||||
};
|
||||
|
||||
request.startWithDevice('id').then(
|
||||
function(aConnection) {
|
||||
connection = aConnection;
|
||||
ok(connection, "Connection should be available.");
|
||||
ok(connection.id, "Connection ID should be set.");
|
||||
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
|
||||
|
||||
if (connectionFromEvent) {
|
||||
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
|
||||
aResolve();
|
||||
}
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when establishing a connection: " + aError);
|
||||
teardown();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function testStartConnectionWithDeviceNotFoundError() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
request.startWithDevice('').then(
|
||||
function(aConnection) {
|
||||
ok(false, "Should not establish connection to an unknown device");
|
||||
teardown();
|
||||
aReject();
|
||||
},
|
||||
function(aError) {
|
||||
is(aError.name, 'NotFoundError', "Expect NotFoundError occurred when establishing a connection");
|
||||
aResolve();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
|
||||
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
|
||||
gScript.destroy();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
gScript.sendAsyncMessage('teardown');
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
ok(window.PresentationRequest, "PresentationRequest should be available.");
|
||||
|
||||
testSetup().
|
||||
then(testStartConnectionWithDevice).
|
||||
then(testStartConnectionWithDeviceNotFoundError).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
//SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: true, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
runTests);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -410,7 +410,9 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
|
||||
|
||||
// use selfURI as the sourceFile
|
||||
nsAutoCString sourceFile;
|
||||
mSelfURI->GetSpec(sourceFile);
|
||||
if (mSelfURI) {
|
||||
mSelfURI->GetSpec(sourceFile);
|
||||
}
|
||||
|
||||
nsAutoString codeSample(aContent);
|
||||
// cap the length of the script sample at 40 chars
|
||||
@ -591,6 +593,7 @@ nsCSPContext::SetRequestContext(nsIDOMDocument* aDOMDocument,
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDOMDocument);
|
||||
mLoadingContext = do_GetWeakReference(doc);
|
||||
mSelfURI = doc->GetDocumentURI();
|
||||
mLoadingPrincipal = doc->NodePrincipal();
|
||||
doc->GetReferrer(mReferrer);
|
||||
mInnerWindowID = doc->InnerWindowID();
|
||||
// the innerWindowID is not available for CSPs delivered through the
|
||||
@ -668,6 +671,51 @@ nsCSPContext::logToConsole(const char16_t* aName,
|
||||
aSeverityFlag, "CSP", mInnerWindowID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip URI for reporting according to:
|
||||
* http://www.w3.org/TR/CSP/#violation-reports
|
||||
*
|
||||
* @param aURI
|
||||
* The uri to be stripped for reporting
|
||||
* @param aProtectedResourcePrincipal
|
||||
* The loadingPrincipal of the protected resource
|
||||
* which is needed to enforce the SOP.
|
||||
* @return ASCII serialization of the uri to be reported.
|
||||
*/
|
||||
void
|
||||
StripURIForReporting(nsIURI* aURI,
|
||||
nsIPrincipal* aProtectedResourcePrincipal,
|
||||
nsACString& outStrippedURI)
|
||||
{
|
||||
// 1) If the origin of uri is a globally unique identifier (for example,
|
||||
// aURI has a scheme of data, blob, or filesystem), then return the
|
||||
// ASCII serialization of uri’s scheme.
|
||||
bool isHttp =
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("http", &isHttp)) && isHttp) ||
|
||||
(NS_SUCCEEDED(aURI->SchemeIs("https", &isHttp)) && isHttp);
|
||||
if (!isHttp) {
|
||||
// not strictly spec compliant, but what we really care about is
|
||||
// http/https. If it's not http/https, then treat aURI as if
|
||||
// it's a globally unique identifier and just return the scheme.
|
||||
aURI->GetScheme(outStrippedURI);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) If the origin of uri is not the same as the origin of the protected
|
||||
// resource, then return the ASCII serialization of uri’s origin.
|
||||
bool sameOrigin =
|
||||
NS_SUCCEEDED(aProtectedResourcePrincipal->CheckMayLoad(aURI, false, false));
|
||||
if (!sameOrigin) {
|
||||
// cross origin redirects also fall into this category, see:
|
||||
// http://www.w3.org/TR/CSP/#violation-reports
|
||||
aURI->GetPrePath(outStrippedURI);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) Return uri, with any fragment component removed.
|
||||
aURI->GetSpecIgnoringRef(outStrippedURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends CSP violation reports to all sources listed under report-uri.
|
||||
*
|
||||
@ -714,15 +762,7 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
nsCOMPtr<nsIURI> uri = do_QueryInterface(aBlockedContentSource);
|
||||
// could be a string or URI
|
||||
if (uri) {
|
||||
// aOriginalURI will only be *not* null in case of a redirect in which
|
||||
// case aOriginalURI is the uri before the redirect.
|
||||
if (aOriginalURI) {
|
||||
// do not report anything else than the origin in case of a redirect, see:
|
||||
// http://www.w3.org/TR/CSP/#violation-reports
|
||||
uri->GetPrePath(reportBlockedURI);
|
||||
} else {
|
||||
uri->GetSpecIgnoringRef(reportBlockedURI);
|
||||
}
|
||||
StripURIForReporting(uri, mLoadingPrincipal, reportBlockedURI);
|
||||
} else {
|
||||
nsCOMPtr<nsISupportsCString> cstr = do_QueryInterface(aBlockedContentSource);
|
||||
if (cstr) {
|
||||
@ -739,7 +779,7 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
|
||||
|
||||
// document-uri
|
||||
nsAutoCString reportDocumentURI;
|
||||
mSelfURI->GetSpecIgnoringRef(reportDocumentURI);
|
||||
StripURIForReporting(mSelfURI, mLoadingPrincipal, reportDocumentURI);
|
||||
report.mCsp_report.mDocument_uri = NS_ConvertUTF8toUTF16(reportDocumentURI);
|
||||
|
||||
// original-policy
|
||||
|
@ -310,7 +310,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
}
|
||||
|
||||
int16_t decision = REJECT_REQUEST;
|
||||
rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrScript(contentPolicyType),
|
||||
rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentPolicyType),
|
||||
newUri,
|
||||
requestingLocation,
|
||||
loadInfo->LoadingNode(),
|
||||
@ -378,9 +378,11 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// to them.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrScript(aContentType),
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
bool isPreload = nsContentUtils::IsPreloadType(aContentType);
|
||||
|
||||
// The content policy type that we receive may be an internal type for
|
||||
// scripts. Let's remember if we have seen a worker type, and reset it to the
|
||||
// external type in all cases right now.
|
||||
@ -668,7 +670,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
bool isHttpScheme = false;
|
||||
rv = aContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests()) {
|
||||
if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests(isPreload)) {
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2,13 +2,10 @@
|
||||
<head>
|
||||
<link rel='stylesheet' type='text/css'
|
||||
href='/tests/dom/security/test/csp/file_CSP.sjs?testid=css_self&type=text/css' />
|
||||
<link rel='stylesheet' type='text/css'
|
||||
href='http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=css_examplecom&type=text/css' />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img_self&type=img/png"> </img>
|
||||
<img src="http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=img_examplecom&type=img/png"> </img>
|
||||
<script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script_self&type=text/javascript'></script>
|
||||
|
||||
</body>
|
||||
|
@ -20,21 +20,15 @@ var path = "/tests/dom/security/test/csp/";
|
||||
// true/false is the pass/fail result.
|
||||
window.loads = {
|
||||
css_self: {expected: true, verified: false},
|
||||
css_examplecom: {expected: false, verified: false},
|
||||
img_self: {expected: false, verified: false},
|
||||
img_examplecom: {expected: false, verified: false},
|
||||
script_self: {expected: true, verified: false},
|
||||
};
|
||||
|
||||
window.violation_reports = {
|
||||
css_self:
|
||||
{expected: 0, expected_ro: 0}, /* totally fine */
|
||||
css_examplecom:
|
||||
{expected: 1, expected_ro: 0}, /* violates enforced CSP */
|
||||
img_self:
|
||||
{expected: 1, expected_ro: 0}, /* violates enforced CSP */
|
||||
img_examplecom:
|
||||
{expected: 1, expected_ro: 1}, /* violates both CSPs */
|
||||
script_self:
|
||||
{expected: 0, expected_ro: 1}, /* violates report-only */
|
||||
};
|
||||
|
@ -57,7 +57,7 @@ function checkResults(reportStr) {
|
||||
"http://mochi.test:8888/tests/dom/security/test/csp/file_report_for_import_server.sjs?report",
|
||||
"Incorrect original-policy");
|
||||
is(cspReport["blocked-uri"],
|
||||
"http://example.com/tests/dom/security/test/csp/file_report_for_import_server.sjs?stylesheet",
|
||||
"http://example.com",
|
||||
"Incorrect blocked-uri");
|
||||
|
||||
// we do not always set the following fields
|
||||
|
@ -39,9 +39,9 @@ function makeReportHandler(testpath, message, expectedJSON) {
|
||||
request.bodyInputStream,
|
||||
request.bodyInputStream.available()));
|
||||
|
||||
dump("GOT REPORT:\n" + JSON.stringify(reportObj) + "\n");
|
||||
dump("TESTPATH: " + testpath + "\n");
|
||||
dump("EXPECTED: \n" + JSON.stringify(expectedJSON) + "\n\n");
|
||||
// dump("GOT REPORT:\n" + JSON.stringify(reportObj) + "\n");
|
||||
// dump("TESTPATH: " + testpath + "\n");
|
||||
// dump("EXPECTED: \n" + JSON.stringify(expectedJSON) + "\n\n");
|
||||
|
||||
for (var i in expectedJSON)
|
||||
do_check_eq(expectedJSON[i], reportObj['csp-report'][i]);
|
||||
@ -132,7 +132,7 @@ function run_test() {
|
||||
}
|
||||
});
|
||||
|
||||
makeTest(2, {"blocked-uri": "http://blocked.test/foo.js"}, false,
|
||||
makeTest(2, {"blocked-uri": "http://blocked.test"}, false,
|
||||
function(csp) {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
@ -172,4 +172,36 @@ function run_test() {
|
||||
4);
|
||||
}
|
||||
});
|
||||
|
||||
// test that only the uri's scheme is reported for globally unique identifiers
|
||||
makeTest(5, {"blocked-uri": "data"}, false,
|
||||
function(csp) {
|
||||
var base64data =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
|
||||
"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||
NetUtil.newURI("data:image/png;base64," + base64data),
|
||||
null, null, null, null);
|
||||
});
|
||||
|
||||
// test that only the uri's scheme is reported for globally unique identifiers
|
||||
makeTest(6, {"blocked-uri": "intent"}, false,
|
||||
function(csp) {
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SUBDOCUMENT,
|
||||
NetUtil.newURI("intent://mymaps.com/maps?um=1&ie=UTF-8&fb=1&sll"),
|
||||
null, null, null, null);
|
||||
});
|
||||
|
||||
// test fragment removal
|
||||
var selfSpec = REPORT_SERVER_URI + ":" + REPORT_SERVER_PORT + "/foo/self/foo.js";
|
||||
makeTest(7, {"blocked-uri": selfSpec}, false,
|
||||
function(csp) {
|
||||
var uri = NetUtil
|
||||
// shouldLoad creates and sends out the report here.
|
||||
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
NetUtil.newURI(selfSpec + "#bar"),
|
||||
null, null, null, null);
|
||||
});
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ skip-if = android_version == '18' # bug 1147994
|
||||
[test_pointer-events-7.xhtml]
|
||||
[test_scientific.html]
|
||||
[test_selectSubString.xhtml]
|
||||
[test_style_sheet.html]
|
||||
[test_stroke-hit-testing.xhtml]
|
||||
[test_stroke-linecap-hit-testing.xhtml]
|
||||
[test_SVGLengthList-2.xhtml]
|
||||
|
27
dom/svg/test/test_style_sheet.html
Normal file
27
dom/svg/test/test_style_sheet.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test for Bug 1239128</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1239128">Mozilla Bug 1239128</a>
|
||||
<p id="display"</p>
|
||||
|
||||
<svg>
|
||||
<style>svg { fill: blue; }</style>
|
||||
</svg>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript">
|
||||
var style = document.querySelector("style");
|
||||
|
||||
var exceptionThrown = false;
|
||||
try {
|
||||
is(style.sheet.cssRules[0].cssText, "svg { fill: blue; }",
|
||||
"Should get the fill: blue rule back");
|
||||
} catch (e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
ok(!exceptionThrown, "Should be able to access data: <style> stylesheet");
|
||||
</script>
|
||||
</pre>
|
@ -128,6 +128,8 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "Animation", release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectReadOnly", release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "AnimationEffectTimingReadOnly", release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"AnimationEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -46,9 +46,8 @@ dictionary ComputedTimingProperties : AnimationEffectTimingProperties {
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
interface AnimationEffectReadOnly {
|
||||
// Not yet implemented:
|
||||
// readonly attribute AnimationEffectTimingReadOnly timing;
|
||||
|
||||
[Cached, Constant]
|
||||
readonly attribute AnimationEffectTimingReadOnly timing;
|
||||
[BinaryName="getComputedTimingAsDict"]
|
||||
ComputedTimingProperties getComputedTiming();
|
||||
};
|
||||
|
23
dom/webidl/AnimationEffectTimingReadOnly.webidl
Normal file
23
dom/webidl/AnimationEffectTimingReadOnly.webidl
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://w3c.github.io/web-animations/#animationeffecttimingreadonly
|
||||
*
|
||||
* Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Func="nsDocument::IsWebAnimationsEnabled"]
|
||||
interface AnimationEffectTimingReadOnly {
|
||||
readonly attribute double delay;
|
||||
readonly attribute double endDelay;
|
||||
readonly attribute FillMode fill;
|
||||
readonly attribute double iterationStart;
|
||||
readonly attribute unrestricted double iterations;
|
||||
readonly attribute (unrestricted double or DOMString) duration;
|
||||
readonly attribute PlaybackDirection direction;
|
||||
readonly attribute DOMString easing;
|
||||
};
|
@ -43,4 +43,24 @@ interface PresentationRequest : EventTarget {
|
||||
* The event is fired for all connections that are created for the controller.
|
||||
*/
|
||||
attribute EventHandler onconnectionavailable;
|
||||
|
||||
/*
|
||||
* A chrome page, or page which has presentation-device-manage permissiongs,
|
||||
* uses startWithDevice() to start a new connection with specified device,
|
||||
* and it will be returned with the promise. UA may show a prompt box with a
|
||||
* list of available devices and ask the user to grant permission, choose a
|
||||
* device, or cancel the operation.
|
||||
*
|
||||
* The promise is resolved when the presenting page is successfully loaded and
|
||||
* the communication channel is established, i.e., the connection state is
|
||||
* "connected".
|
||||
*
|
||||
* The promise may be rejected duo to one of the following reasons:
|
||||
* - "OperationError": Unexpected error occurs.
|
||||
* - "NotFoundError": No available device.
|
||||
* - "NetworkError": Failed to establish the control channel or data channel.
|
||||
* - "TimeoutError": Presenting page takes too long to load.
|
||||
*/
|
||||
[CheckAnyPermissions="presentation-device-manage", Throws]
|
||||
Promise<PresentationConnection> startWithDevice(DOMString deviceId);
|
||||
};
|
||||
|
@ -22,4 +22,5 @@ interface SVGStyleElement : SVGElement {
|
||||
[SetterThrows]
|
||||
attribute boolean scoped;
|
||||
};
|
||||
SVGStyleElement implements LinkStyle;
|
||||
|
||||
|
@ -24,6 +24,7 @@ WEBIDL_FILES = [
|
||||
'Animatable.webidl',
|
||||
'Animation.webidl',
|
||||
'AnimationEffectReadOnly.webidl',
|
||||
'AnimationEffectTimingReadOnly.webidl',
|
||||
'AnimationEvent.webidl',
|
||||
'AnimationTimeline.webidl',
|
||||
'AnonymousContent.webidl',
|
||||
|
@ -1185,13 +1185,6 @@ private:
|
||||
MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
|
||||
GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
|
||||
|
||||
NS_ConvertUTF8toUTF16 local(mSpec);
|
||||
RequestOrUSVString requestInfo;
|
||||
requestInfo.SetAsUSVString().Rebind(local.Data(), local.Length());
|
||||
|
||||
RootedDictionary<RequestInit> reqInit(aCx);
|
||||
reqInit.mMethod.Construct(mMethod);
|
||||
|
||||
RefPtr<InternalHeaders> internalHeaders = new InternalHeaders(HeadersGuardEnum::Request);
|
||||
MOZ_ASSERT(mHeaderNames.Length() == mHeaderValues.Length());
|
||||
for (uint32_t i = 0; i < mHeaderNames.Length(); i++) {
|
||||
@ -1203,35 +1196,30 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Headers> headers = new Headers(globalObj.GetAsSupports(), internalHeaders);
|
||||
reqInit.mHeaders.Construct();
|
||||
reqInit.mHeaders.Value().SetAsHeaders() = headers;
|
||||
|
||||
reqInit.mMode.Construct(mRequestMode);
|
||||
reqInit.mRedirect.Construct(mRequestRedirect);
|
||||
reqInit.mCredentials.Construct(mRequestCredentials);
|
||||
|
||||
ErrorResult result;
|
||||
RefPtr<Request> request = Request::Constructor(globalObj, requestInfo, reqInit, result);
|
||||
internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
result.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> internalReq = new InternalRequest(mSpec,
|
||||
mMethod,
|
||||
internalHeaders.forget(),
|
||||
mRequestMode,
|
||||
mRequestRedirect,
|
||||
mRequestCredentials,
|
||||
NS_ConvertUTF8toUTF16(mReferrer),
|
||||
mContentPolicyType);
|
||||
internalReq->SetBody(mUploadStream);
|
||||
// For Telemetry, note that this Request object was created by a Fetch event.
|
||||
RefPtr<InternalRequest> internalReq = request->GetInternalRequest();
|
||||
MOZ_ASSERT(internalReq);
|
||||
internalReq->SetCreatedByFetchEvent();
|
||||
|
||||
internalReq->SetBody(mUploadStream);
|
||||
internalReq->SetReferrer(NS_ConvertUTF8toUTF16(mReferrer));
|
||||
|
||||
request->SetContentPolicyType(mContentPolicyType);
|
||||
|
||||
request->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
result.SuppressException();
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(globalObj.GetAsSupports());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<Request> request = new Request(global, internalReq);
|
||||
|
||||
// TODO: remove conditional on http here once app protocol support is
|
||||
// removed from service worker interception
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user