Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-03-27 12:20:00 -04:00
commit 6558bd81c3
414 changed files with 13340 additions and 6629 deletions

View File

@ -8,7 +8,7 @@
#include "AccessibleWrap.h"
#include "nsMai.h"
#include "ProxyAccessible.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Likely.h"
@ -20,12 +20,17 @@ extern "C" {
static void
getCurrentValueCB(AtkValue *obj, GValue *value)
{
ProxyAccessible* proxy = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
if (!accWrap)
if (!accWrap) {
proxy = GetProxy(ATK_OBJECT(obj));
if (!proxy) {
return;
}
}
memset (value, 0, sizeof (GValue));
double accValue = accWrap->CurValue();
double accValue = accWrap ? accWrap->CurValue() : proxy->CurValue();
if (IsNaN(accValue))
return;
@ -36,12 +41,17 @@ getCurrentValueCB(AtkValue *obj, GValue *value)
static void
getMaximumValueCB(AtkValue *obj, GValue *value)
{
ProxyAccessible* proxy = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
if (!accWrap)
if (!accWrap) {
proxy = GetProxy(ATK_OBJECT(obj));
if (!proxy) {
return;
}
}
memset(value, 0, sizeof (GValue));
double accValue = accWrap->MaxValue();
double accValue = accWrap ? accWrap->MaxValue() : proxy->MaxValue();
if (IsNaN(accValue))
return;
@ -52,12 +62,17 @@ getMaximumValueCB(AtkValue *obj, GValue *value)
static void
getMinimumValueCB(AtkValue *obj, GValue *value)
{
ProxyAccessible* proxy = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
if (!accWrap)
if (!accWrap) {
proxy = GetProxy(ATK_OBJECT(obj));
if (!proxy) {
return;
}
}
memset(value, 0, sizeof (GValue));
double accValue = accWrap->MinValue();
double accValue = accWrap ? accWrap->MinValue() : proxy->MinValue();
if (IsNaN(accValue))
return;
@ -68,12 +83,17 @@ getMinimumValueCB(AtkValue *obj, GValue *value)
static void
getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
{
ProxyAccessible* proxy = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
if (!accWrap)
if (!accWrap) {
proxy = GetProxy(ATK_OBJECT(obj));
if (!proxy) {
return;
}
}
memset(minimumIncrement, 0, sizeof (GValue));
double accValue = accWrap->Step();
double accValue = accWrap ? accWrap->Step() : proxy->Step();
if (IsNaN(accValue))
accValue = 0; // zero if the minimum increment is undefined
@ -84,12 +104,17 @@ getMinimumIncrementCB(AtkValue *obj, GValue *minimumIncrement)
static gboolean
setCurrentValueCB(AtkValue *obj, const GValue *value)
{
ProxyAccessible* proxy = nullptr;
AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(obj));
if (!accWrap)
if (!accWrap) {
proxy = GetProxy(ATK_OBJECT(obj));
if (!proxy) {
return FALSE;
}
}
double accValue =g_value_get_double(value);
return accWrap->SetCurValue(accValue);
return accWrap ? accWrap->SetCurValue(accValue) : proxy->SetCurValue(accValue);
}
}

View File

@ -533,8 +533,9 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
// accessibles in subtree then we don't care about the change.
Accessible* child = document->GetAccessible(aChildNode);
if (!child) {
a11y::TreeWalker walker(document->GetContainerAccessible(aChildNode),
aChildNode, a11y::TreeWalker::eWalkCache);
Accessible* container = document->GetContainerAccessible(aChildNode);
a11y::TreeWalker walker(container ? container : document, aChildNode,
a11y::TreeWalker::eWalkCache);
child = walker.NextChild();
}

View File

@ -15,6 +15,7 @@
#include "TableCellAccessible.h"
#include "nsIPersistentProperties2.h"
#include "nsISimpleEnumerator.h"
#include "nsAccUtils.h"
namespace mozilla {
namespace a11y {
@ -1430,5 +1431,205 @@ DocAccessibleChild::RecvUnselectAll(const uint64_t& aID,
return true;
}
bool
DocAccessibleChild::RecvDoAction(const uint64_t& aID,
const uint8_t& aIndex,
bool* aSuccess)
{
*aSuccess = false;
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aSuccess = acc->DoAction(aIndex);
}
return true;
}
bool
DocAccessibleChild::RecvActionCount(const uint64_t& aID,
uint8_t* aCount)
{
*aCount = 0;
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aCount = acc->ActionCount();
}
return true;
}
bool
DocAccessibleChild::RecvActionDescriptionAt(const uint64_t& aID,
const uint8_t& aIndex,
nsString* aDescription)
{
Accessible* acc = IdToAccessible(aID);
if (acc) {
acc->ActionDescriptionAt(aIndex, *aDescription);
}
return true;
}
bool
DocAccessibleChild::RecvActionNameAt(const uint64_t& aID,
const uint8_t& aIndex,
nsString* aName)
{
Accessible* acc = IdToAccessible(aID);
if (acc) {
acc->ActionNameAt(aIndex, *aName);
}
return true;
}
bool
DocAccessibleChild::RecvAccessKey(const uint64_t& aID,
uint32_t* aKey,
uint32_t* aModifierMask)
{
*aKey = 0;
*aModifierMask = 0;
Accessible* acc = IdToAccessible(aID);
if (acc) {
KeyBinding kb = acc->AccessKey();
*aKey = kb.Key();
*aModifierMask = kb.ModifierMask();
}
return true;
}
bool
DocAccessibleChild::RecvKeyboardShortcut(const uint64_t& aID,
uint32_t* aKey,
uint32_t* aModifierMask)
{
*aKey = 0;
*aModifierMask = 0;
Accessible* acc = IdToAccessible(aID);
if (acc) {
KeyBinding kb = acc->KeyboardShortcut();
*aKey = kb.Key();
*aModifierMask = kb.ModifierMask();
}
return true;
}
bool
DocAccessibleChild::RecvCurValue(const uint64_t& aID,
double* aValue)
{
*aValue = UnspecifiedNaN<double>();
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aValue = acc->CurValue();
}
return true;
}
bool
DocAccessibleChild::RecvSetCurValue(const uint64_t& aID,
const double& aValue,
bool* aRetVal)
{
*aRetVal = false;
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aRetVal = acc->SetCurValue(aValue);
}
return true;
}
bool
DocAccessibleChild::RecvMinValue(const uint64_t& aID,
double* aValue)
{
*aValue = UnspecifiedNaN<double>();
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aValue = acc->MinValue();
}
return true;
}
bool
DocAccessibleChild::RecvMaxValue(const uint64_t& aID,
double* aValue)
{
*aValue = UnspecifiedNaN<double>();
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aValue = acc->MaxValue();
}
return true;
}
bool
DocAccessibleChild::RecvStep(const uint64_t& aID,
double* aStep)
{
*aStep = UnspecifiedNaN<double>();
Accessible* acc = IdToAccessible(aID);
if (acc) {
*aStep = acc->Step();
}
return true;
}
bool
DocAccessibleChild::RecvTakeFocus(const uint64_t& aID)
{
Accessible* acc = IdToAccessible(aID);
if (acc) {
acc->TakeFocus();
}
return true;
}
bool
DocAccessibleChild::RecvChildAtPoint(const uint64_t& aID,
const int32_t& aX,
const int32_t& aY,
const uint32_t& aWhich,
uint64_t* aChild,
bool* aOk)
{
*aChild = 0;
*aOk = false;
Accessible* acc = IdToAccessible(aID);
if (acc && !acc->IsDefunct() && !nsAccUtils::MustPrune(acc)) {
Accessible* child =
acc->ChildAtPoint(aX, aY,
static_cast<Accessible::EWhichChildAtPoint>(aWhich));
if (child) {
*aChild = reinterpret_cast<uint64_t>(child->UniqueID());
*aOk = true;
}
}
return true;
}
bool
DocAccessibleChild::RecvBounds(const uint64_t& aID,
nsIntRect* aRect)
{
Accessible* acc = IdToAccessible(aID);
if (acc && !acc->IsDefunct()) {
*aRect = acc->Bounds();
}
return false;
}
}
}

View File

@ -351,6 +351,56 @@ public:
virtual bool RecvUnselectAll(const uint64_t& aID,
bool* aSuccess) override;
virtual bool RecvDoAction(const uint64_t& aID,
const uint8_t& aIndex,
bool* aSuccess) override;
virtual bool RecvActionCount(const uint64_t& aID,
uint8_t* aCount) override;
virtual bool RecvActionDescriptionAt(const uint64_t& aID,
const uint8_t& aIndex,
nsString* aDescription) override;
virtual bool RecvActionNameAt(const uint64_t& aID,
const uint8_t& aIndex,
nsString* aName) override;
virtual bool RecvAccessKey(const uint64_t& aID,
uint32_t* aKey,
uint32_t* aModifierMask) override;
virtual bool RecvKeyboardShortcut(const uint64_t& aID,
uint32_t* aKey,
uint32_t* aModifierMask) override;
virtual bool RecvCurValue(const uint64_t& aID,
double* aValue);
virtual bool RecvSetCurValue(const uint64_t& aID,
const double& aValue,
bool* aRetVal);
virtual bool RecvMinValue(const uint64_t& aID,
double* aValue);
virtual bool RecvMaxValue(const uint64_t& aID,
double* aValue);
virtual bool RecvStep(const uint64_t& aID,
double* aStep);
virtual bool RecvTakeFocus(const uint64_t& aID) override;
virtual bool RecvChildAtPoint(const uint64_t& aID,
const int32_t& aX,
const int32_t& aY,
const uint32_t& aWhich,
uint64_t* aChild,
bool* aOk) override;
virtual bool RecvBounds(const uint64_t& aID, nsIntRect* aRect) override;
private:
Accessible* IdToAccessible(const uint64_t& aID) const;

View File

@ -192,6 +192,23 @@ child:
prio(high) sync SelectAll(uint64_t aID) returns(bool aSuccess);
prio(high) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
prio(high) sync DoAction(uint64_t aID, uint8_t aIndex) returns(bool aSuccess);
prio(high) sync ActionCount(uint64_t aID) returns(uint8_t aCount);
prio(high) sync ActionDescriptionAt(uint64_t aID, uint8_t aIndex) returns(nsString aDescription);
prio(high) sync ActionNameAt(uint64_t aID, uint8_t aIndex) returns(nsString aName);
prio(high) sync AccessKey(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
prio(high) sync KeyboardShortcut(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
prio(high) sync CurValue(uint64_t aID) returns(double aValue);
prio(high) sync SetCurValue(uint64_t aID, double aValue) returns(bool aRetVal);
prio(high) sync MinValue(uint64_t aID) returns(double aValue);
prio(high) sync MaxValue(uint64_t aID) returns(double aValue);
prio(high) sync Step(uint64_t aID) returns(double aStep);
prio(high) sync TakeFocus(uint64_t aID);
prio(high) sync ChildAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aWhich)
returns(uint64_t aChild, bool aOk);
prio(high) sync Bounds(uint64_t aID) returns(nsIntRect aRect);
};
}

View File

@ -799,5 +799,117 @@ ProxyAccessible::UnselectAll()
return success;
}
bool
ProxyAccessible::DoAction(uint8_t aIndex)
{
bool success = false;
unused << mDoc->SendDoAction(mID, aIndex, &success);
return success;
}
uint8_t
ProxyAccessible::ActionCount()
{
uint8_t count = 0;
unused << mDoc->SendActionCount(mID, &count);
return count;
}
void
ProxyAccessible::ActionDescriptionAt(uint8_t aIndex, nsString& aDescription)
{
unused << mDoc->SendActionDescriptionAt(mID, aIndex, &aDescription);
}
void
ProxyAccessible::ActionNameAt(uint8_t aIndex, nsString& aName)
{
unused << mDoc->SendActionNameAt(mID, aIndex, &aName);
}
KeyBinding
ProxyAccessible::AccessKey()
{
uint32_t key = 0;
uint32_t modifierMask = 0;
unused << mDoc->SendAccessKey(mID, &key, &modifierMask);
return KeyBinding(key, modifierMask);
}
KeyBinding
ProxyAccessible::KeyboardShortcut()
{
uint32_t key = 0;
uint32_t modifierMask = 0;
unused << mDoc->SendKeyboardShortcut(mID, &key, &modifierMask);
return KeyBinding(key, modifierMask);
}
double
ProxyAccessible::CurValue()
{
double val = UnspecifiedNaN<double>();
unused << mDoc->SendCurValue(mID, &val);
return val;
}
bool
ProxyAccessible::SetCurValue(double aValue)
{
bool success = false;
unused << mDoc->SendSetCurValue(mID, aValue, &success);
return success;
}
double
ProxyAccessible::MinValue()
{
double val = UnspecifiedNaN<double>();
unused << mDoc->SendMinValue(mID, &val);
return val;
}
double
ProxyAccessible::MaxValue()
{
double val = UnspecifiedNaN<double>();
unused << mDoc->SendMaxValue(mID, &val);
return val;
}
double
ProxyAccessible::Step()
{
double step = UnspecifiedNaN<double>();
unused << mDoc->SendStep(mID, &step);
return step;
}
void
ProxyAccessible::TakeFocus()
{
unused << mDoc->SendTakeFocus(mID);
}
ProxyAccessible*
ProxyAccessible::ChildAtPoint(int32_t aX, int32_t aY,
Accessible::EWhichChildAtPoint aWhichChild)
{
uint64_t childID = 0;
bool ok = false;
unused << mDoc->SendChildAtPoint(mID, aX, aY,
static_cast<uint32_t>(aWhichChild),
&childID, &ok);
return ok ? mDoc->GetAccessible(childID) : nullptr;
}
nsIntRect
ProxyAccessible::Bounds()
{
nsIntRect rect;
unused << mDoc->SendBounds(mID, &rect);
return rect;
}
}
}

View File

@ -9,9 +9,11 @@
#include "mozilla/a11y/Role.h"
#include "nsIAccessibleText.h"
#include "Accessible.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsRect.h"
#include "Accessible.h"
namespace mozilla {
namespace a11y {
@ -256,6 +258,24 @@ public:
bool SelectAll();
bool UnselectAll();
bool DoAction(uint8_t aIndex);
uint8_t ActionCount();
void ActionDescriptionAt(uint8_t aIndex, nsString& aDescription);
void ActionNameAt(uint8_t aIndex, nsString& aName);
KeyBinding AccessKey();
KeyBinding KeyboardShortcut();
double CurValue();
bool SetCurValue(double aValue);
double MinValue();
double MaxValue();
double Step();
void TakeFocus();
ProxyAccessible* ChildAtPoint(int32_t aX, int32_t aY,
Accessible::EWhichChildAtPoint aWhichChild);
nsIntRect Bounds();
/**
* Allow the platform to store a pointers worth of data on us.
*/

View File

@ -969,12 +969,7 @@ pref("gecko.handlerService.allowRegisterFromDifferentHost", false);
pref("browser.safebrowsing.enabled", true);
pref("browser.safebrowsing.malware.enabled", true);
pref("browser.safebrowsing.downloads.enabled", true);
// Remote lookups are only enabled for Windows in Nightly and Aurora
#if defined(XP_WIN)
pref("browser.safebrowsing.downloads.remote.enabled", true);
#else
pref("browser.safebrowsing.downloads.remote.enabled", false);
#endif
pref("browser.safebrowsing.debug", false);
pref("browser.safebrowsing.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
@ -1015,7 +1010,7 @@ pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
#ifdef XP_WIN
// Only download the whitelist on Windows, since the whitelist is
// only useful for suppressing remote lookups for signed binaries which we can
// only verify on Windows (Bug 974579).
// only verify on Windows (Bug 974579). Other platforms always do remote lookups.
pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
#endif
#endif
@ -1450,6 +1445,9 @@ pref("devtools.performance.ui.enable-framerate", true);
// The default cache UI setting
pref("devtools.cache.disabled", false);
// The default service workers UI setting
pref("devtools.serviceWorkers.testing.enabled", false);
// Enable the Network Monitor
pref("devtools.netmonitor.enabled", true);

View File

@ -3246,8 +3246,7 @@
};
let popup = browser.ownerDocument.getElementById("contentAreaContextMenu");
let event = gContextMenuContentData.event;
let pos = browser.mapScreenCoordinatesFromContent(event.screenX, event.screenY);
popup.openPopupAtScreen(pos.x, pos.y, true);
popup.openPopupAtScreen(event.screenX, event.screenY, true);
break;
}
case "DOMWebNotificationClicked": {

View File

@ -50,6 +50,9 @@ support-files =
file_bug906190_redirected.html
file_bug906190.js
file_bug906190.sjs
file_mixedContentFromOnunload.html
file_mixedContentFromOnunload_test1.html
file_mixedContentFromOnunload_test2.html
file_bug970276_popup1.html
file_bug970276_popup2.html
file_bug970276_favicon1.ico
@ -283,6 +286,7 @@ skip-if = e10s # Bug 1126316 - New e10s windows erroneously fire initial about:b
[browser_bug902156.js]
[browser_bug906190.js]
skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
[browser_mixedContentFromOnunload.js]
[browser_bug970746.js]
skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode
[browser_bug1015721.js]

View File

@ -59,6 +59,7 @@ function checkPage() {
Services.obs.addObserver(function observer(aSubject, aTopic) {
ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
"online.");
Services.obs.removeObserver(observer, "network:offline-status-changed", false);
finish();
}, "network:offline-status-changed", false);
gBrowser.contentDocument.getElementById("errorTryAgain").click();

View File

@ -0,0 +1,107 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Tests for Bug 947079 - Fix bug in nsSecureBrowserUIImpl that sets the wrong
* security state on a page because of a subresource load that is not on the
* same page.
*/
// We use different domains for each test and for navigation within each test
const gHttpTestRoot1 = "http://example.com/browser/browser/base/content/test/general/";
const gHttpsTestRoot1 = "https://test1.example.com/browser/browser/base/content/test/general/";
const gHttpTestRoot2 = "http://example.net/browser/browser/base/content/test/general/";
const gHttpsTestRoot2 = "https://test2.example.com/browser/browser/base/content/test/general/";
let gTestBrowser = null;
function SecStateTestsCompleted() {
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function test() {
waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_active_content", true],
["security.mixed_content.block_display_content", false]]}, SecStateTests);
}
function SecStateTests() {
gBrowser.selectedTab = gBrowser.addTab();
gTestBrowser = gBrowser.selectedBrowser;
whenLoaded(gTestBrowser, SecStateTest1A);
let url = gHttpTestRoot1 + "file_mixedContentFromOnunload.html";
gTestBrowser.contentWindow.location = url;
}
// Navigation from an http page to a https page with no mixed content
// The http page loads an http image on unload
function SecStateTest1A() {
whenLoaded(gTestBrowser, SecStateTest1B);
let url = gHttpsTestRoot1 + "file_mixedContentFromOnunload_test1.html";
gTestBrowser.contentWindow.location = url;
}
function SecStateTest1B() {
// check security state. Since current url is https and doesn't have any
// mixed content resources, we expect it to be secure.
isSecurityState("secure");
whenLoaded(gTestBrowser, SecStateTest2A);
// change locations and proceed with the second test
let url = gHttpTestRoot2 + "file_mixedContentFromOnunload.html";
gTestBrowser.contentWindow.location = url;
}
// Navigation from an http page to a https page that has mixed display content
// The http page loads an http image on unload
function SecStateTest2A() {
whenLoaded(gTestBrowser, SecStateTest2B);
let url = gHttpsTestRoot2 + "file_mixedContentFromOnunload_test2.html";
gTestBrowser.contentWindow.location = url;
}
function SecStateTest2B() {
isSecurityState("broken");
SecStateTestsCompleted();
}
// Compares the security state of the page with what is expected
function isSecurityState(expectedState) {
let ui = gTestBrowser.securityUI;
if (!ui) {
ok(false, "No security UI to get the security state");
return;
}
const wpl = Components.interfaces.nsIWebProgressListener;
// determine the security state
let isSecure = ui.state & wpl.STATE_IS_SECURE;
let isBroken = ui.state & wpl.STATE_IS_BROKEN;
let isInsecure = ui.state & wpl.STATE_IS_INSECURE;
let actualState;
if (isSecure && !(isBroken || isInsecure)) {
actualState = "secure";
} else if (isBroken && !(isSecure || isInsecure)) {
actualState = "broken";
} else if (isInsecure && !(isSecure || isBroken)) {
actualState = "insecure";
} else {
actualState = "unknown";
}
is(expectedState, actualState, "Expected state " + expectedState + " and the actual state is " + actualState + ".");
}
function whenLoaded(aElement, aCallback) {
aElement.addEventListener("load", function onLoad() {
aElement.removeEventListener("load", onLoad, true);
executeSoon(aCallback);
}, true);
}

View File

@ -0,0 +1,18 @@
<!DOCTYPE HTML>
<html>
<!--
Test for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 947079</title>
</head>
<body>
<p>Test for Bug 947079</p>
<script>
window.addEventListener('unload', function() {
new Image().src = 'http://mochi.test:8888/tests/image/test/mochitest/blue.png';
});
</script>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<!--
Test 1 for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
Page with no insecure subresources
-->
<head>
<meta charset="utf-8">
<title>Test 1 for Bug 947079</title>
</head>
<body>
<p>There are no insecure resource loads on this page</p>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html>
<!--
Test 2 for https://bugzilla.mozilla.org/show_bug.cgi?id=947079
Page with an insecure image load
-->
<head>
<meta charset="utf-8">
<title>Test 2 for Bug 947079</title>
</head>
<body>
<p>Page with http image load</p>
<img src="http://test2.example.com/tests/image/test/mochitest/blue.png">
</body>
</html>

View File

@ -13,6 +13,7 @@ var Ci = Components.interfaces;
var Cr = Components.results;
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('resource://gre/modules/AppConstants.jsm');
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
@ -73,17 +74,9 @@ const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
// identifying the "use plugin" action, so we use this constant instead.
const kActionUsePlugin = 5;
/*
#ifdef MOZ_WIDGET_GTK
*/
const ICON_URL_APP = "moz-icon://dummy.exe?size=16";
/*
#else
*/
const ICON_URL_APP = "chrome://browser/skin/preferences/application.png";
/*
#endif
*/
const ICON_URL_APP = AppConstants.platform == "linux" ?
"moz-icon://dummy.exe?size=16" :
"chrome://browser/skin/preferences/application.png";
// For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
// was set by us to a custom handler icon and CSS should not try to override it.

View File

@ -8,6 +8,7 @@
// Constants & Enumeration Values
Components.utils.import('resource://gre/modules/Services.jsm');
Components.utils.import('resource://gre/modules/AppConstants.jsm');
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
@ -67,17 +68,9 @@ const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
// identifying the "use plugin" action, so we use this constant instead.
const kActionUsePlugin = 5;
/*
#if MOZ_WIDGET_GTK == 2
*/
const ICON_URL_APP = "moz-icon://dummy.exe?size=16";
/*
#else
*/
const ICON_URL_APP = "chrome://browser/skin/preferences/application.png";
/*
#endif
*/
const ICON_URL_APP = AppConstants.platform == "linux" ?
"moz-icon://dummy.exe?size=16" :
"chrome://browser/skin/preferences/application.png";
// For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
// was set by us to a custom handler icon and CSS should not try to override it.

View File

@ -95,7 +95,9 @@ let gSyncPane = {
"weave:service:start-over:finish",
"weave:service:setup-complete",
"weave:service:logout:finish",
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
];
let migrateTopic = "fxa-migration:state-changed";
// Add the observers now and remove them on unload
@ -123,6 +125,8 @@ let gSyncPane = {
}),
this.updateWeavePrefs();
this._initProfileImageUI();
},
_setupEventListeners: function() {
@ -224,6 +228,14 @@ let gSyncPane = {
});
},
_initProfileImageUI: function () {
try {
if (Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled")) {
document.getElementById("fxaProfileImage").hidden = false;
}
} catch (e) { }
},
updateWeavePrefs: function () {
// ask the migration module to broadcast its current state (and nothing will
// happen if it's not loaded - which is good, as that means no migration
@ -244,10 +256,11 @@ let gSyncPane = {
}
// determine the fxa status...
this.page = PAGE_PLEASE_WAIT;
fxAccounts.getSignedInUser().then(data => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
return;
return false;
}
this.page = FXA_PAGE_LOGGED_IN;
// We are logged in locally, but maybe we are in a state where the
@ -281,7 +294,36 @@ let gSyncPane = {
for (let checkbox of engines.querySelectorAll("checkbox")) {
checkbox.disabled = enginesListDisabled;
}
// Clear the profile image (if any) of the previously logged in account.
document.getElementById("fxaProfileImage").style.removeProperty("background-image");
// If the account is verified the next promise in the chain will
// fetch profile data.
return data.verified;
}).then(shouldGetProfile => {
if (shouldGetProfile) {
return fxAccounts.getSignedInUserProfile();
}
}).then(data => {
if (data && data.avatar) {
// Make sure the image is available before displaying it,
// as we don't want to overwrite the default profile image
// with a broken/unavailable image
let img = new Image();
img.onload = () => {
let bgImage = "url('" + data.avatar + "')";
document.getElementById("fxaProfileImage").style.backgroundImage = bgImage;
};
img.src = data.avatar;
}
}, err => {
FxAccountsCommon.log.error(err);
}).catch(err => {
// If we get here something's really busted
Cu.reportError(String(err));
});
// If fxAccountEnabled is false and we are in a "not configured" state,
// then fxAccounts is probably fully disabled rather than just unconfigured,
// so handle this case. This block can be removed once we remove support
@ -521,6 +563,15 @@ let gSyncPane = {
});
},
openChangeProfileImage: function() {
fxAccounts.promiseAccountsChangeProfileURI("avatar")
.then(url => {
this.openContentInBrowser(url, {
replaceQueryString: true
});
});
},
manageFirefoxAccount: function() {
let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri");
this.openContentInBrowser(url);

View File

@ -233,7 +233,11 @@
<!-- logged in and verified and all is good -->
<hbox id="fxaLoginVerified"
align="center">
<hbox align="center">
<image id="fxaProfileImage"
onclick="gSyncPane.openChangeProfileImage();" hidden="true"/>
<label id="fxaEmailAddress1"/>
</hbox>
<spacer flex="1"/>
<button id="verifiedManage"
label="&manage.label;"/>

View File

@ -8,6 +8,8 @@ support-files =
head.js
helper_disable_cache.js
doc_theme.css
browser_toolbox_options_enable_serviceworkers_testing.html
serviceworker.js
[browser_devtools_api.js]
[browser_devtools_api_destroy.js]
@ -51,6 +53,8 @@ skip-if = os == "mac" && os_version == "10.8" || os == "win" && os_version == "5
[browser_toolbox_zoom.js]
[browser_toolbox_custom_host.js]
[browser_toolbox_theme_registration.js]
[browser_toolbox_options_enable_serviceworkers_testing.js]
skip-if = e10s # Bug 1030318
# We want this test to run for mochitest-dt as well, so we include it here:
[../../../base/content/test/general/browser_parsable_css.js]

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<title>browser_toolbox_options_enable_serviceworkers_testing.html</title>
<meta charset="UTF-8">
<style>
div {
width: 260px;
height: 24px;
border: 1px solid #000;
margin-top: 10px;
}
h1 {
font-size: 20px
}
</style>
<script type="application/javascript;version=1.8">
function log(msg) {
var output = document.getElementById("output");
output.innerHTML = msg;
}
navigator.serviceWorker.register("serviceworker.js").then(
swr => {
var msg = "";
var button = document.getElementById("button");
if (swr.installing) {
msg += "Installing worker/";
}
if (swr.waiting) {
msg += "Waiting worker/";
}
if (swr.active) {
msg += "Active worker/";
}
log(msg);
button.click();
},
error => {
var button = document.getElementById("button");
if (error.name === "SecurityError") {
log("SecurityError");
}
button.click();
});
</script>
</head>
<body>
<h1>Test in page</h1>
<input id="button"
type="button"
value="Worker clicks here"/>
<br>
<div id="output">No output</div>
</body>
</html>

View File

@ -0,0 +1,124 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that enabling Service Workers testing option enables the
// mServiceWorkersTestingEnabled attribute added to nsPIDOMWindow.
const TEST_URI = URL_ROOT +
"browser_toolbox_options_enable_serviceworkers_testing.html";
const ELEMENT_ID = "devtools-enable-serviceWorkersTesting";
let toolbox;
let doc;
function test() {
// Note: Pref dom.serviceWorkers.testing.enabled is false since we are testing
// the same capabilities are enabled with the devtool pref.
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", false]
]}, start);
}
function start() {
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
gDevTools.showToolbox(target).then(testSelectTool);
}, true);
content.location = TEST_URI;
}
function testSelectTool(aToolbox) {
toolbox = aToolbox;
toolbox.once("options-selected", testRegisterFails);
toolbox.selectTool("options");
}
function testRegisterFails() {
let output = doc.getElementById("output");
let button = doc.getElementById("button");
function doTheCheck() {
info("Testing it doesn't registers correctly until enable testing");
is(output.textContent,
"SecurityError",
"SecurityError expected");
testRegisterInstallingWorker();
}
if (output.textContent !== "No output") {
doTheCheck();
}
button.addEventListener('click', function onClick() {
button.removeEventListener('click', onClick);
doTheCheck();
});
}
function testRegisterInstallingWorker() {
toggleServiceWorkersTestingCheckbox().then(() => {
let output = doc.getElementById("output");
let button = doc.getElementById("button");
function doTheCheck() {
info("Testing it registers correctly and there is an installing worker");
is(output.textContent,
"Installing worker/",
"Installing worker expected");
toggleServiceWorkersTestingCheckbox().then(finishUp);
}
if (output.textContent !== "No output") {
doTheCheck();
}
button.addEventListener('click', function onClick() {
button.removeEventListener('click', onClick);
doTheCheck();
});
});
}
function toggleServiceWorkersTestingCheckbox() {
let deferred = promise.defer();
let panel = toolbox.getCurrentPanel();
let cbx = panel.panelDoc.getElementById(ELEMENT_ID);
cbx.scrollIntoView();
if (cbx.checked) {
info("Clearing checkbox to disable service workers testing");
} else {
info("Checking checkbox to enable service workers testing");
}
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
deferred.resolve();
}, true);
cbx.click();
let mm = getFrameScript();
mm.sendAsyncMessage("devtools:test:reload");
return deferred.promise;
}
function finishUp() {
toolbox.destroy().then(function() {
gBrowser.removeCurrentTab();
toolbox = doc = null;
finish();
});
}

View File

@ -0,0 +1 @@
// empty service worker, always succeed!

View File

@ -317,7 +317,7 @@ OptionsPanel.prototype = {
if (this.target.activeTab) {
this.target.client.attachTab(this.target.activeTab._actor, (response) => {
this._origJavascriptEnabled = response.javascriptEnabled;
this.disableJSNode.checked = !this._origJavascriptEnabled
this.disableJSNode.checked = !this._origJavascriptEnabled;
this.disableJSNode.addEventListener("click", this._disableJSClicked, false);
});
} else {

View File

@ -145,6 +145,10 @@
<checkbox id="devtools-disable-javascript"
label="&options.disableJavaScript.label;"
tooltiptext="&options.disableJavaScript.tooltip;"/>
<checkbox id="devtools-enable-serviceWorkersTesting"
label="&options.enableServiceWorkersTesting.label;"
tooltiptext="&options.enableServiceWorkersTesting.tooltip;"
data-pref="devtools.serviceWorkers.testing.enabled"/>
<hbox class="hidden-labels-box">
<checkbox label="&options.enableChrome.label5;"
tooltiptext="&options.enableChrome.tooltip3;"

View File

@ -332,6 +332,7 @@ Toolbox.prototype = {
this._buildOptions();
this._buildTabs();
this._applyCacheSettings();
this._applyServiceWorkersTestingSettings();
this._addKeysToWindow();
this._addReloadKeys();
this._addHostListeners();
@ -407,8 +408,13 @@ Toolbox.prototype = {
* }
*/
_prefChanged: function(event, data) {
if (data.pref === "devtools.cache.disabled") {
switch(data.pref) {
case "devtools.cache.disabled":
this._applyCacheSettings();
break;
case "devtools.serviceWorkers.testing.enabled":
this._applyServiceWorkersTestingSettings();
break;
}
},
@ -747,6 +753,22 @@ Toolbox.prototype = {
}
},
/**
* Apply the current service workers testing setting from
* devtools.serviceWorkers.testing.enabled to this toolbox's tab.
*/
_applyServiceWorkersTestingSettings: function() {
let pref = "devtools.serviceWorkers.testing.enabled";
let serviceWorkersTestingEnabled =
Services.prefs.getBoolPref(pref) || false;
if (this.target.activeTab) {
this.target.activeTab.reconfigure({
"serviceWorkersTestingEnabled": serviceWorkersTestingEnabled
});
}
},
/**
* Setter for the checked state of the picker button in the toolbar
* @param {Boolean} isChecked
@ -1694,10 +1716,13 @@ Toolbox.prototype = {
}
}
// Now that we are closing the toolbox we can re-enable JavaScript for the
// current tab.
// Now that we are closing the toolbox we can re-enable the cache settings
// and disable the service workers testing settings for the current tab.
if (this.target.activeTab) {
this.target.activeTab.reconfigure({"cacheDisabled": false});
this.target.activeTab.reconfigure({
"cacheDisabled": false,
"serviceWorkersTestingEnabled": false
});
}
// Destroying the walker and inspector fronts

View File

@ -13,7 +13,11 @@ let test = Task.async(function*() {
let firstTarget = TargetFactory.forTab(firstTab);
yield firstTarget.makeRemote();
yield gDevTools.showToolbox(firstTarget, "webconsole");
let toolboxFirstTab;
yield gDevTools.showToolbox(firstTarget, "webconsole").then((aToolbox) => {
toolboxFirstTab = aToolbox;
});
is(gProfilerConnections, 1,
"A shared profiler connection should have been created.");
@ -25,14 +29,21 @@ let test = Task.async(function*() {
let secondTarget = TargetFactory.forTab(secondTab);
yield secondTarget.makeRemote();
yield gDevTools.showToolbox(secondTarget, "jsprofiler");
let toolboxSecondTab;
yield gDevTools.showToolbox(secondTarget, "jsprofiler").then((aToolbox) => {
toolboxSecondTab = aToolbox;
});
is(gProfilerConnections, 2,
"Only one new profiler connection should have been created.");
yield removeTab(firstTab);
yield removeTab(secondTab);
yield toolboxFirstTab.destroy().then(() => {
removeTab(firstTab);
});
yield toolboxSecondTab.destroy().then(() => {
removeTab(secondTab);
finish();
});
});
function profilerConnectionObserver(subject, topic, data) {

View File

@ -97,6 +97,12 @@
<!ENTITY options.disableCache.label2 "Disable Cache (when toolbox is open)">
<!ENTITY options.disableCache.tooltip2 "Turning this option on will disable the cache for all tabs that have the toolbox open.">
<!-- LOCALIZATION NOTE (options.enableServiceWorkersTesting.label,
- options.enableServiceWorkersTesting.tooltip): This is the options panel label and
- tooltip for the checkbox that toggles the service workers testing features on or off. -->
<!ENTITY options.enableServiceWorkersTesting.label "Enable Service Workers testing features (when toolbox is open)">
<!ENTITY options.enableServiceWorkersTesting.tooltip "Turning this option on will enable the service workers testing features for all tabs that have the toolbox open.">
<!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
- the heading of group of checkboxes corresponding to the default developer
- tools. -->

View File

@ -179,6 +179,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)

View File

@ -284,6 +284,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<path fill="#C3CFD8" d="M500-0.3c276.1,0,500,223.9,500,500s-223.9,500-500,500S0,775.8,0,499.7C0,223.5,223.9-0.3,500-0.3z"/>
<circle fill="#FFFFFF" cx="500" cy="317" r="139.1"/>
<path fill="#FFFFFF" d="M751.8,643.6L751.8,643.6c0.1-2.3,0.2-4.6,0.2-6.9c0-68-55.3-127-136.2-156.3L505.9,590.4h0
c-0.4,29.8-1.4,58.8-2.8,86.6c-1,0.1-2,0.3-3.1,0.3s-2-0.2-3.1-0.3c-1.4-27.9-2.4-56.9-2.8-86.7h0L384.3,480.4
C303.3,509.7,248,568.7,248,636.7c0,2.3,0.1,4.6,0.2,6.9l7.4,49.7c57.1,72,145.4,118.2,244.4,118.2c99,0,187.3-46.2,244.4-118.2
L751.8,643.6z"/>
</svg>

After

Width:  |  Height:  |  Size: 993 B

View File

@ -216,6 +216,22 @@ description > html|a {
cursor: pointer;
}
#fxaProfileImage {
width: 60px;
height: 60px;
border-radius: 50%;
border-width: 5px;
border-color: red;
background-image: url(chrome://browser/skin/preferences/in-content/default-profile-image.svg);
background-size: contain;
cursor: pointer;
-moz-margin-end: 15px;
}
#fxaProfileImage:hover {
border-color: blue;
}
#noFxaAccount {
/* Overriding the margins from the base preferences.css theme file.
These overrides can be simplified by fixing bug 1027174 */

View File

@ -207,6 +207,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)

View File

@ -130,6 +130,7 @@ ifdef MOZ_FOLD_LIBS
DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=nss3
else
DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=mozsqlite3
DEFAULT_GMAKE_FLAGS += SQLITE_LIB_DIR=$(ABS_DIST)/../config/external/sqlite
endif # MOZ_FOLD_LIBS
DEFAULT_GMAKE_FLAGS += SQLITE_INCLUDE_DIR=$(ABS_DIST)/include
endif
@ -357,6 +358,11 @@ GARBAGE += \
endif # GCC_USE_GNU_LD
endif # WINNT
IMPORT_LIB_FILES = $(IMPORT_LIBRARY)
IMPORT_LIB_DEST ?= $(DIST)/lib
IMPORT_LIB_TARGET = target
INSTALL_TARGETS += IMPORT_LIB
endif # MOZ_FOLD_LIBS
include $(topsrcdir)/config/rules.mk

View File

@ -31,11 +31,6 @@ ifdef LIBRARY
ifdef DIST_INSTALL
ifdef IS_COMPONENT
$(error Shipping static component libs makes no sense.)
else
DIST_LIBRARY_FILES = $(LIBRARY)
DIST_LIBRARY_DEST ?= $(DIST)/lib
DIST_LIBRARY_TARGET = target
INSTALL_TARGETS += DIST_LIBRARY
endif
endif # DIST_INSTALL
endif # LIBRARY
@ -47,21 +42,6 @@ SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)
SHARED_LIBRARY_TARGET = target
INSTALL_TARGETS += SHARED_LIBRARY
ifneq (,$(filter WINNT,$(OS_ARCH)))
ifndef NO_INSTALL_IMPORT_LIBRARY
IMPORT_LIB_FILES = $(IMPORT_LIBRARY)
endif # NO_INSTALL_IMPORT_LIBRARY
else
IMPORT_LIB_FILES = $(SHARED_LIBRARY)
endif
IMPORT_LIB_DEST ?= $(DIST)/lib
IMPORT_LIB_TARGET = target
ifdef IMPORT_LIB_FILES
INSTALL_TARGETS += IMPORT_LIB
endif
endif # ! IS_COMPONENT
endif # SHARED_LIBRARY
@ -72,13 +52,6 @@ HOST_PROGRAMS_TARGET = host
INSTALL_TARGETS += HOST_PROGRAMS
endif
ifdef HOST_LIBRARY
HOST_LIBRARY_FILES = $(HOST_LIBRARY)
HOST_LIBRARY_DEST ?= $(DIST)/host/lib
HOST_LIBRARY_TARGET = host
INSTALL_TARGETS += HOST_LIBRARY
endif
endif # !NO_DIST_INSTALL
# EOF

View File

@ -2727,6 +2727,7 @@ MOZ_CHECK_HEADERS([linux/quota.h],,,[#include <sys/socket.h>])
dnl SCTP support - needs various network include headers
MOZ_CHECK_HEADERS([linux/if_addr.h linux/rtnetlink.h],,,[#include <sys/socket.h>])
MOZ_CHECK_HEADERS(sys/queue.h)
MOZ_CHECK_HEADERS(sys/types.h netinet/in.h byteswap.h)

View File

@ -45,7 +45,7 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_popup-navigates-children.html]
skip-if = buildapp == 'b2g' # b2g(Needs multiple window.open support, also uses docshelltreenode) b2g-debug(Needs multiple window.open support, also uses docshelltreenode) b2g-desktop(Needs multiple window.open support, also uses docshelltreenode)
[test_reserved.html]
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' #too slow on Android 2.3 aws only; bug 1030403
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || android_version == '10' || android_version == '18' #too slow on Android 2.3 and 4.3 aws only; bug 1030403
[test_sessionhistory.html]
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #RANDOM # b2g-debug(Perma-orange on debug emulator builds) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
[test_sibling-matching-parent.html]

View File

@ -61,7 +61,7 @@ AnimationPlayer::SetStartTime(const Nullable<TimeDuration>& aNewStartTime)
mHoldTime = previousCurrentTime;
}
CancelPendingPlay();
CancelPendingTasks();
if (mReady) {
// We may have already resolved mReady, but in that case calling
// MaybeResolve is a no-op, so that's okay.
@ -123,7 +123,12 @@ AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime)
{
SilentlySetCurrentTime(aSeekTime);
// Once pending pause tasks are supported, cancel that here.
if (mPendingState == PendingState::PausePending) {
CancelPendingTasks();
if (mReady) {
mReady->MaybeResolve(this);
}
}
UpdateSourceContent();
PostUpdate();
@ -160,7 +165,7 @@ AnimationPlayer::SilentlySetPlaybackRate(double aPlaybackRate)
AnimationPlayState
AnimationPlayer::PlayState() const
{
if (mIsPending) {
if (mPendingState != PendingState::NotPending) {
return AnimationPlayState::Pending;
}
@ -267,7 +272,7 @@ AnimationPlayer::Tick()
// it's possible that mPendingReadyTime is set to a time in the future.
// In that case, we should wait until the next refresh driver tick before
// resuming.
if (mIsPending &&
if (mPendingState != PendingState::NotPending &&
!mPendingReadyTime.IsNull() &&
mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) {
ResumeAt(mPendingReadyTime.Value());
@ -284,12 +289,11 @@ AnimationPlayer::Tick()
}
void
AnimationPlayer::StartOnNextTick(const Nullable<TimeDuration>& aReadyTime)
AnimationPlayer::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
{
// Normally we expect the play state to be pending but it's possible that,
// due to the handling of possibly orphaned players in Tick() [coming
// in a later patch in this series], this player got started whilst still
// being in another document's pending player map.
// due to the handling of possibly orphaned players in Tick(), this player got
// started whilst still being in another document's pending player map.
if (PlayState() != AnimationPlayState::Pending) {
return;
}
@ -300,7 +304,7 @@ AnimationPlayer::StartOnNextTick(const Nullable<TimeDuration>& aReadyTime)
}
void
AnimationPlayer::StartNow()
AnimationPlayer::TriggerNow()
{
MOZ_ASSERT(PlayState() == AnimationPlayState::Pending,
"Expected to start a pending player");
@ -334,8 +338,8 @@ AnimationPlayer::GetCurrentOrPendingStartTime() const
void
AnimationPlayer::Cancel()
{
if (mIsPending) {
CancelPendingPlay();
if (mPendingState != PendingState::NotPending) {
CancelPendingTasks();
if (mReady) {
mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
}
@ -350,7 +354,9 @@ AnimationPlayer::Cancel()
bool
AnimationPlayer::IsRunning() const
{
if (IsPaused() || !GetSource() || GetSource()->IsFinishedTransition()) {
if (IsPausedOrPausing() ||
!GetSource() ||
GetSource()->IsFinishedTransition()) {
return false;
}
@ -424,6 +430,12 @@ AnimationPlayer::DoPlay()
// need to pass a flag so that when we start playing due to a change in
// animation-play-state we *don't* trigger finishing behavior.
bool reuseReadyPromise = false;
if (mPendingState != PendingState::NotPending) {
CancelPendingTasks();
reuseReadyPromise = true;
}
Nullable<TimeDuration> currentTime = GetCurrentTime();
if (mPlaybackRate > 0.0 &&
(currentTime.IsNull())) {
@ -439,17 +451,19 @@ AnimationPlayer::DoPlay()
return;
}
// Clear ready promise. We'll create a new one lazily.
mReady = nullptr;
// Clear the start time until we resolve a new one
mStartTime.SetNull();
mIsPending = true;
if (!reuseReadyPromise) {
// Clear ready promise. We'll create a new one lazily.
mReady = nullptr;
}
mPendingState = PendingState::PlayPending;
nsIDocument* doc = GetRenderedDocument();
if (!doc) {
StartOnNextTick(Nullable<TimeDuration>());
TriggerOnNextTick(Nullable<TimeDuration>());
return;
}
@ -464,8 +478,8 @@ AnimationPlayer::DoPlay()
void
AnimationPlayer::DoPause()
{
if (mIsPending) {
CancelPendingPlay();
if (mPendingState == PendingState::PlayPending) {
CancelPendingTasks();
// Resolve the ready promise since we currently only use it for
// players that are waiting to play. Later (in bug 1109390), we will
// use this for players waiting to pause as well and then we won't
@ -491,10 +505,11 @@ AnimationPlayer::ResumeAt(const TimeDuration& aResumeTime)
// This method is only expected to be called for a player that is
// waiting to play. We can easily adapt it to handle other states
// but it's currently not necessary.
MOZ_ASSERT(PlayState() == AnimationPlayState::Pending,
"Expected to resume a pending player");
MOZ_ASSERT(mPendingState == PendingState::PlayPending,
"Expected to resume a play-pending player");
MOZ_ASSERT(!mHoldTime.IsNull(),
"A player in the pending state should have a resolved hold time");
"A player in the play-pending state should have a resolved"
" hold time");
if (mPlaybackRate != 0) {
mStartTime.SetValue(aResumeTime - (mHoldTime.Value() / mPlaybackRate));
@ -502,7 +517,7 @@ AnimationPlayer::ResumeAt(const TimeDuration& aResumeTime)
} else {
mStartTime.SetValue(aResumeTime);
}
mIsPending = false;
mPendingState = PendingState::NotPending;
UpdateSourceContent();
@ -539,9 +554,9 @@ AnimationPlayer::PostUpdate()
}
void
AnimationPlayer::CancelPendingPlay()
AnimationPlayer::CancelPendingTasks()
{
if (!mIsPending) {
if (mPendingState == PendingState::NotPending) {
return;
}
@ -549,11 +564,15 @@ AnimationPlayer::CancelPendingPlay()
if (doc) {
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
if (tracker) {
if (mPendingState == PendingState::PlayPending) {
tracker->RemovePlayPending(*this);
} else {
tracker->RemovePausePending(*this);
}
}
}
mIsPending = false;
mPendingState = PendingState::NotPending;
mPendingReadyTime.SetNull();
}
@ -574,11 +593,11 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
// when we have been painted.
// * When we started playing we couldn't find a PendingPlayerTracker to
// register with (perhaps the source content had no document) so we simply
// set mIsPending in DoPlay and relied on this method to catch us on the
// set mPendingState in DoPlay and relied on this method to catch us on the
// next tick.
// If we're not pending we're ok.
if (!mIsPending) {
if (mPendingState == PendingState::NotPending) {
return false;
}
@ -598,12 +617,17 @@ AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const
// PendingPlayerTracker then there's a good chance no one is tracking us.
//
// If we're wrong and another document is tracking us then, at worst, we'll
// simply start the animation one tick too soon. That's better than never
// starting the animation and is unlikely.
// simply start/pause the animation one tick too soon. That's better than
// never starting/pausing the animation and is unlikely.
nsIDocument* doc = GetRenderedDocument();
return !doc ||
!doc->GetPendingPlayerTracker() ||
!doc->GetPendingPlayerTracker()->IsWaitingToPlay(*this);
if (!doc) {
return false;
}
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
return !tracker ||
(!tracker->IsWaitingToPlay(*this) &&
!tracker->IsWaitingToPause(*this));
}
StickyTimeDuration

View File

@ -54,7 +54,7 @@ public:
explicit AnimationPlayer(AnimationTimeline* aTimeline)
: mTimeline(aTimeline)
, mPlaybackRate(1.0)
, mIsPending(false)
, mPendingState(PendingState::NotPending)
, mIsRunningOnCompositor(false)
, mIsPreviousStateFinished(false)
, mIsRelevant(false)
@ -107,6 +107,8 @@ public:
void Tick();
/**
* Set the time to use for starting or pausing a pending player.
*
* Typically, when a player is played, it does not start immediately but is
* added to a table of pending players on the document of its source content.
* In the meantime it sets its hold time to the time from which playback
@ -119,9 +121,9 @@ public:
* players do start, they can be timed from the point when painting
* completed.
*
* After calling StartOnNextTick, players remain in the pending state until
* After calling TriggerOnNextTick, players remain in the pending state until
* the next refresh driver tick. At that time they transition out of the
* pending state using the time passed to StartOnNextTick as the effective
* pending state using the time passed to TriggerOnNextTick as the effective
* time at which they resumed.
*
* This approach means that any setup time required for performing the
@ -145,20 +147,27 @@ public:
* between triggering an animation and its effective start is unacceptably
* long.
*
* For pausing, we apply the same asynchronous approach. This is so that we
* synchronize with animations that are running on the compositor. Otherwise
* if the main thread lags behind the compositor there will be a noticeable
* jump backwards when the main thread takes over. Even though main thread
* animations could be paused immediately, we do it asynchronously for
* consistency and so that animations paused together end up in step.
*
* Note that the caller of this method is responsible for removing the player
* from any PendingPlayerTracker it may have been added to.
*/
void StartOnNextTick(const Nullable<TimeDuration>& aReadyTime);
void TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime);
// Testing only: Start a pending player using the current timeline time.
// This is used to support existing tests that expect animations to begin
// immediately. Ideally we would rewrite the those tests and get rid of this
// method, but there are a lot of them.
// Testing only: Start or pause a pending player using the current timeline
// time. This is used to support existing tests that expect animations to
// begin immediately. Ideally we would rewrite the those tests and get rid of
// this method, but there are a lot of them.
//
// As with StartOnNextTick, the caller of this method is responsible for
// As with TriggerOnNextTick, the caller of this method is responsible for
// removing the player from any PendingPlayerTracker it may have been added
// to.
void StartNow();
void TriggerNow();
/**
* When StartOnNextTick is called, we store the ready time but we don't apply
@ -182,17 +191,24 @@ public:
void Cancel();
const nsString& Name() const {
const nsString& Name() const
{
return mSource ? mSource->Name() : EmptyString();
}
bool IsPaused() const { return PlayState() == AnimationPlayState::Paused; }
bool IsPausedOrPausing() const
{
return PlayState() == AnimationPlayState::Paused ||
mPendingState == PendingState::PausePending;
}
bool IsRunning() const;
bool HasCurrentSource() const {
bool HasCurrentSource() const
{
return GetSource() && GetSource()->IsCurrent();
}
bool HasInEffectSource() const {
bool HasInEffectSource() const
{
return GetSource() && GetSource()->IsInEffect();
}
@ -226,10 +242,12 @@ protected:
void UpdateSourceContent();
void FlushStyle() const;
void PostUpdate();
// Remove this player from the pending player tracker and resets mIsPending
// as necessary. The caller is responsible for resolving or aborting the
// mReady promise as necessary.
void CancelPendingPlay();
/**
* Remove this player from the pending player tracker and reset
* mPendingState as necessary. The caller is responsible for resolving or
* aborting the mReady promise as necessary.
*/
void CancelPendingTasks();
bool IsPossiblyOrphanedPendingPlayer() const;
StickyTimeDuration SourceContentEnd() const;
@ -252,12 +270,15 @@ protected:
// This object is lazily created by GetReady.
nsRefPtr<Promise> mReady;
// Indicates if the player is in the pending state. We use this rather
// than checking if this player is tracked by a PendingPlayerTracker.
// This is because the PendingPlayerTracker is associated with the source
// content's document but we need to know if we're pending even if the
// source content loses association with its document.
bool mIsPending;
// Indicates if the player is in the pending state (and what state it is
// waiting to enter when it finished pending). We use this rather than
// checking if this player is tracked by a PendingPlayerTracker because the
// player will continue to be pending even after it has been removed from the
// PendingPlayerTracker while it is waiting for the next tick
// (see TriggerOnNextTick for details).
enum class PendingState { NotPending, PlayPending, PausePending };
PendingState mPendingState;
bool mIsRunningOnCompositor;
// Indicates whether we were in the finished state during our
// most recent unthrottled sample (our last ComposeStyle call).

View File

@ -13,15 +13,19 @@ using namespace mozilla;
namespace mozilla {
NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker, mPlayPendingSet, mDocument)
NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker,
mPlayPendingSet,
mPausePendingSet,
mDocument)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingPlayerTracker, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingPlayerTracker, Release)
void
PendingPlayerTracker::AddPlayPending(dom::AnimationPlayer& aPlayer)
PendingPlayerTracker::AddPending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet)
{
mPlayPendingSet.PutEntry(&aPlayer);
aSet.PutEntry(&aPlayer);
// Schedule a paint. Otherwise animations that don't trigger a paint by
// themselves (e.g. CSS animations with an empty keyframes rule) won't
@ -30,19 +34,21 @@ PendingPlayerTracker::AddPlayPending(dom::AnimationPlayer& aPlayer)
}
void
PendingPlayerTracker::RemovePlayPending(dom::AnimationPlayer& aPlayer)
PendingPlayerTracker::RemovePending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet)
{
mPlayPendingSet.RemoveEntry(&aPlayer);
aSet.RemoveEntry(&aPlayer);
}
bool
PendingPlayerTracker::IsWaitingToPlay(dom::AnimationPlayer const& aPlayer) const
PendingPlayerTracker::IsWaiting(const dom::AnimationPlayer& aPlayer,
const AnimationPlayerSet& aSet) const
{
return mPlayPendingSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
return aSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer));
}
PLDHashOperator
StartPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
TriggerPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
void* aReadyTime)
{
dom::AnimationPlayer* player = aKey->GetKey();
@ -51,38 +57,43 @@ StartPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey,
// When the timeline's refresh driver is under test control, its values
// have no correspondance to wallclock times so we shouldn't try to convert
// aReadyTime (which is a wallclock time) to a timeline value. Instead, the
// animation player will be started when the refresh driver is next
// advanced since this will trigger a call to StartPendingPlayersNow.
// animation player will be started/paused when the refresh driver is next
// advanced since this will trigger a call to TriggerPendingPlayersNow.
if (timeline->IsUnderTestControl()) {
return PL_DHASH_NEXT;
}
Nullable<TimeDuration> readyTime =
timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime));
player->StartOnNextTick(readyTime);
player->TriggerOnNextTick(readyTime);
return PL_DHASH_REMOVE;
}
void
PendingPlayerTracker::StartPendingPlayersOnNextTick(const TimeStamp& aReadyTime)
PendingPlayerTracker::TriggerPendingPlayersOnNextTick(const TimeStamp&
aReadyTime)
{
mPlayPendingSet.EnumerateEntries(StartPlayerAtTime,
mPlayPendingSet.EnumerateEntries(TriggerPlayerAtTime,
const_cast<TimeStamp*>(&aReadyTime));
mPausePendingSet.EnumerateEntries(TriggerPlayerAtTime,
const_cast<TimeStamp*>(&aReadyTime));
}
PLDHashOperator
StartPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*)
TriggerPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*)
{
aKey->GetKey()->StartNow();
aKey->GetKey()->TriggerNow();
return PL_DHASH_NEXT;
}
void
PendingPlayerTracker::StartPendingPlayersNow()
PendingPlayerTracker::TriggerPendingPlayersNow()
{
mPlayPendingSet.EnumerateEntries(StartPlayerNow, nullptr);
mPlayPendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
mPlayPendingSet.Clear();
mPausePendingSet.EnumerateEntries(TriggerPlayerNow, nullptr);
mPausePendingSet.Clear();
}
void

View File

@ -25,13 +25,41 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingPlayerTracker)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingPlayerTracker)
void AddPlayPending(dom::AnimationPlayer& aPlayer);
void RemovePlayPending(dom::AnimationPlayer& aPlayer);
bool IsWaitingToPlay(dom::AnimationPlayer const& aPlayer) const;
void AddPlayPending(dom::AnimationPlayer& aPlayer)
{
MOZ_ASSERT(!IsWaitingToPause(aPlayer),
"Player is already waiting to pause");
AddPending(aPlayer, mPlayPendingSet);
}
void RemovePlayPending(dom::AnimationPlayer& aPlayer)
{
RemovePending(aPlayer, mPlayPendingSet);
}
bool IsWaitingToPlay(const dom::AnimationPlayer& aPlayer) const
{
return IsWaiting(aPlayer, mPlayPendingSet);
}
void StartPendingPlayersOnNextTick(const TimeStamp& aReadyTime);
void StartPendingPlayersNow();
bool HasPendingPlayers() const { return mPlayPendingSet.Count() > 0; }
void AddPausePending(dom::AnimationPlayer& aPlayer)
{
MOZ_ASSERT(!IsWaitingToPlay(aPlayer),
"Player is already waiting to play");
AddPending(aPlayer, mPausePendingSet);
}
void RemovePausePending(dom::AnimationPlayer& aPlayer)
{
RemovePending(aPlayer, mPausePendingSet);
}
bool IsWaitingToPause(const dom::AnimationPlayer& aPlayer) const
{
return IsWaiting(aPlayer, mPausePendingSet);
}
void TriggerPendingPlayersOnNextTick(const TimeStamp& aReadyTime);
void TriggerPendingPlayersNow();
bool HasPendingPlayers() const {
return mPlayPendingSet.Count() > 0 || mPausePendingSet.Count() > 0;
}
private:
~PendingPlayerTracker() { }
@ -41,7 +69,15 @@ private:
typedef nsTHashtable<nsRefPtrHashKey<dom::AnimationPlayer>>
AnimationPlayerSet;
void AddPending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet);
void RemovePending(dom::AnimationPlayer& aPlayer,
AnimationPlayerSet& aSet);
bool IsWaiting(const dom::AnimationPlayer& aPlayer,
const AnimationPlayerSet& aSet) const;
AnimationPlayerSet mPlayPendingSet;
AnimationPlayerSet mPausePendingSet;
nsCOMPtr<nsIDocument> mDocument;
};

View File

@ -31,10 +31,11 @@ async_test(function(t) {
player.ready.then(waitForFrame).then(t.step_func(function() {
assert_true(getMarginLeft(cs) > previousAnimVal,
'margin-left is initially increasing');
previousAnimVal = getMarginLeft(cs);
player.pause();
return player.ready.then(waitForFrame);
return player.ready;
})).then(t.step_func(function() {
previousAnimVal = getMarginLeft(cs);
return waitForFrame();
})).then(t.step_func(function() {
assert_equals(getMarginLeft(cs), previousAnimVal,
'margin-left does not increase after calling pause()');
@ -102,13 +103,14 @@ async_test(function(t) {
}).then(t.step_func(function() {
assert_equals(cs.animationPlayState, 'running',
'animation-play-state is running');
previousAnimVal = getMarginLeft(cs);
div.style.animationPlayState = 'paused';
cs.animationPlayState; // Trigger style resolution
return waitForFrame();
return player.ready;
})).then(t.step_func(function() {
assert_equals(cs.animationPlayState, 'paused',
'animation-play-state is paused');
previousAnimVal = getMarginLeft(cs);
return waitForFrame();
})).then(t.step_func(function() {
assert_equals(getMarginLeft(cs), previousAnimVal,
'Animated value of margin-left does not change when'
+ ' paused by style');
@ -164,9 +166,9 @@ async_test(function(t) {
player.pause();
var previousAnimVal = getMarginLeft(cs);
waitForFrame().then(t.step_func(function() {
player.ready.then(waitForFrame).then(t.step_func(function() {
assert_equals(cs.animationPlayState, 'running',
'animation-play-state is paused');
'animation-play-state is running');
assert_equals(getMarginLeft(cs), previousAnimVal,
'Paused value of margin-left does not change');
t.done();

View File

@ -588,28 +588,25 @@ async_test(function(t) {
div.style.animation = 'anim 100s';
var player = div.getAnimationPlayers()[0];
var pauseTime;
player.ready.then(t.step_func(function() {
var savedCurrentTime = player.currentTime;
assert_not_equals(player.currentTime, null,
'AnimationPlayer.currentTime not null on ready Promise resolve');
var prePauseCurrentTime = player.currentTime;
player.pause();
// After bug 1109390 we will need to wait here for the ready promise again
assert_equals(player.currentTime, prePauseCurrentTime,
'AnimationPlayer.currentTime is unchanged after AnimationPlayer.pause()');
assert_equals(player.playState, 'paused',
'AnimationPlayer.playState is "paused" after pause() call');
return player.ready;
})).then(t.step_func(function() {
pauseTime = player.currentTime;
return waitForFrame();
})).then(t.step_func(function() {
assert_equals(player.currentTime, pauseTime,
'AnimationPlayer.currentTime is unchanged after pausing');
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
t.done();
});
}, 'AnimationPlayer.currentTime after paused');
}, 'AnimationPlayer.currentTime after pausing');
</script>
</body>

View File

@ -24,23 +24,37 @@ async_test(function(t) {
}));
}, 'Player returns correct playState when running');
test(function(t) {
async_test(function(t) {
var div = addDiv(t);
var cs = window.getComputedStyle(div);
div.style.animation = 'anim 1000s paused';
var player = div.getAnimationPlayers()[0];
// FIXME: When we turn on async pausing later in this patch series, enable
// this
// assert_equals(player.playState, 'pending');
player.ready.then(t.step_func(function() {
assert_equals(player.playState, 'paused');
t.done();
}));
}, 'Player returns correct playState when paused');
test(function(t) {
async_test(function(t) {
var div = addDiv(t);
var cs = window.getComputedStyle(div);
div.style.animation = 'anim 1000s';
var player = div.getAnimationPlayers()[0];
player.pause();
// FIXME: When we turn on async pausing later in this patch series, enable
// this
// assert_equals(player.playState, 'pending');
player.ready.then(t.step_func(function() {
assert_equals(player.playState, 'paused');
t.done();
}));
}, 'Player.playState updates when paused by script');
test(function(t) {

View File

@ -618,8 +618,8 @@ async_test(function(t) {
'AnimationPlayer.startTime not null on ready Promise resolve');
player.pause();
// After bug 1109390 we will need to wait here for the ready promise again
return player.ready;
})).then(t.step_func(function() {
assert_equals(player.startTime, null,
'AnimationPlayer.startTime is null after paused');
assert_equals(player.playState, 'paused',

View File

@ -384,8 +384,8 @@ async_test(function(t) {
'AnimationPlayer.startTime not null on ready Promise resolve');
player.pause();
// After bug 1109390 we will need to wait here for the ready promise again
return player.ready;
})).then(t.step_func(function() {
assert_equals(player.startTime, null,
'AnimationPlayer.startTime is null after paused');
assert_equals(player.playState, 'paused',

View File

@ -483,7 +483,7 @@ WarningOnlyErrorReporter(JSContext* aCx, const char* aMessage, JSErrorReport* aR
{
MOZ_ASSERT(JSREPORT_IS_WARNING(aRep->flags));
nsRefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
nsPIDOMWindow* win = xpc::WindowGlobalOrNull(JS::CurrentGlobalOrNull(aCx));
nsPIDOMWindow* win = xpc::CurrentWindowOrNull(aCx);
xpcReport->Init(aRep, aMessage, nsContentUtils::IsCallerChrome(),
win ? win->WindowID() : 0);
xpcReport->LogToConsole();

View File

@ -2595,7 +2595,7 @@ nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds)
if (doc) {
PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker();
if (tracker) {
tracker->StartPendingPlayersNow();
tracker->TriggerPendingPlayersNow();
}
}
@ -3985,6 +3985,32 @@ nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetServiceWorkersTestingEnabled(bool aEnabled)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
window->SetServiceWorkersTestingEnabled(aEnabled);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetServiceWorkersTestingEnabled(bool *aEnabled)
{
MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_STATE(window);
*aEnabled = window->GetServiceWorkersTestingEnabled();
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)

View File

@ -884,8 +884,7 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
// Don't show remote iframe if we are waiting for the completion of reflow.
if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
nsIntPoint chromeDisp = aFrame->GetChromeDisplacement();
mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
mRemoteBrowser->UpdateDimensions(dimensions, size);
}
}
@ -1383,6 +1382,12 @@ nsFrameLoader::StartDestroy()
}
}
// If the TabParent has installed any event listeners on the window, this is
// its last chance to remove them while we're still in the document.
if (mRemoteBrowser) {
mRemoteBrowser->RemoveWindowListeners();
}
nsCOMPtr<nsIDocument> doc;
bool dynamicSubframeRemoval = false;
if (mOwnerContent) {
@ -2058,8 +2063,7 @@ nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
ScreenIntSize size = aIFrame->GetSubdocumentSize();
nsIntRect dimensions;
NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
nsIntPoint chromeDisp = aIFrame->GetChromeDisplacement();
mRemoteBrowser->UpdateDimensions(dimensions, size, chromeDisp);
mRemoteBrowser->UpdateDimensions(dimensions, size);
}
return NS_OK;
}

View File

@ -229,6 +229,9 @@ public:
void ActivateUpdateHitRegion();
void DeactivateUpdateHitRegion();
// Properly retrieves documentSize of any subdocument type.
nsresult GetWindowDimensions(nsIntRect& aRect);
private:
void SetOwnerContent(mozilla::dom::Element* aContent);
@ -284,9 +287,6 @@ private:
nsresult MaybeCreateDocShell();
nsresult EnsureMessageManager();
// Properly retrieves documentSize of any subdocument type.
nsresult GetWindowDimensions(nsIntRect& aRect);
// Updates the subdocument position and size. This gets called only
// when we have our own in-process DocShell.
void UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame);

View File

@ -584,7 +584,7 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
mOuterWindow(aOuterWindow),
// Make sure no actual window ends up with mWindowID == 0
mWindowID(NextWindowID()), mHasNotifiedGlobalCreated(false),
mMarkedCCGeneration(0)
mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false)
{}
nsPIDOMWindow::~nsPIDOMWindow() {}

View File

@ -91,6 +91,13 @@
#endif
#endif // XP_WIN
#ifdef XP_MACOSX
// HandlePluginCrashed() and HandlePluginInstantiated() needed from here to
// fix bug 1147521. Should later be replaced by proper interface methods,
// maybe on nsIObjectLoadingContext.
#include "mozilla/dom/HTMLObjectElement.h"
#endif
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
static const char *kPrefJavaMIME = "plugin.java.mime";
@ -867,6 +874,10 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
NS_LITERAL_STRING("PluginInstantiated"));
NS_DispatchToCurrentThread(ev);
#ifdef XP_MACOSX
HTMLObjectElement::HandlePluginInstantiated(thisContent->AsElement());
#endif
return NS_OK;
}
@ -2723,14 +2734,19 @@ nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag,
LOG(("OBJLC [%p]: Plugin Crashed, queuing crash event", this));
NS_ASSERTION(mType == eType_Plugin, "PluginCrashed at non-plugin type");
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
#ifdef XP_MACOSX
HTMLObjectElement::HandlePluginCrashed(thisContent->AsElement());
#endif
PluginDestroyed();
// Switch to fallback/crashed state, notify
LoadFallback(eFallbackCrashed, true);
// send nsPluginCrashedEvent
nsCOMPtr<nsIContent> thisContent =
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
// Note that aPluginTag in invalidated after we're called, so copy
// out any data we need now.

View File

@ -186,6 +186,18 @@ public:
float GetAudioGlobalVolume();
virtual void SetServiceWorkersTestingEnabled(bool aEnabled)
{
MOZ_ASSERT(IsOuterWindow());
mServiceWorkersTestingEnabled = aEnabled;
}
bool GetServiceWorkersTestingEnabled()
{
MOZ_ASSERT(IsOuterWindow());
return mServiceWorkersTestingEnabled;
}
protected:
// Lazily instantiate an about:blank document if necessary, and if
// we have what it takes to do so.
@ -798,6 +810,10 @@ protected:
bool mHasNotifiedGlobalCreated;
uint32_t mMarkedCCGeneration;
// Let the service workers plumbing know that some feature are enabled while
// testing.
bool mServiceWorkersTestingEnabled;
};

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1147026 - CSP should ignore query string when checking a resource load</title>
</head>
<body>
<div id="testdiv">blocked</div>
<script src="http://test1.example.com/tests/dom/base/test/csp/file_csp_path_matching.js?val=foo"></script>
</body>
</html>

View File

@ -86,6 +86,7 @@ support-files =
file_self_none_as_hostname_confusion.html
file_self_none_as_hostname_confusion.html^headers^
file_csp_path_matching.html
file_csp_path_matching_incl_query.html
file_csp_path_matching.js
file_csp_path_matching_redirect.html
file_csp_path_matching_redirect_server.sjs

View File

@ -79,9 +79,14 @@ function loadNextTest() {
}
else {
policy = policies[counter++];
var src = "file_csp_testserver.sjs";
var src = "file_csp_testserver.sjs?file=";
// append the file that should be served
src += "?file=" + escape("tests/dom/base/test/csp/file_csp_path_matching.html");
src += (counter % 2 == 0)
// load url including ref: example.com#foo
? escape("tests/dom/base/test/csp/file_csp_path_matching.html")
// load url including query: example.com?val=foo (bug 1147026)
: escape("tests/dom/base/test/csp/file_csp_path_matching_incl_query.html");
// append the CSP that should be used to serve the file
src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);

View File

@ -1525,7 +1525,7 @@ DOMInterfaces = {
'headerFile': 'mozilla/dom/WorkerScope.h',
'nativeType': 'mozilla::dom::workers::WorkerDebuggerGlobalScope',
'implicitJSContext': [
'dump', 'global',
'dump', 'global', 'reportError',
],
},

View File

@ -243,16 +243,14 @@ protected:
return false;
}
virtual nsresult GetLineno(int32_t* aLineNo)
virtual int32_t GetLineno()
{
*aLineNo = mLineno;
return NS_OK;
return mLineno;
}
virtual nsresult GetColNo(int32_t* aColNo)
virtual int32_t GetColNo()
{
*aColNo = mColNo;
return NS_OK;
return mColNo;
}
nsCOMPtr<nsIStackFrame> mCaller;
@ -318,8 +316,8 @@ protected:
return true;
}
virtual nsresult GetLineno(int32_t* aLineNo) override;
virtual nsresult GetColNo(int32_t* aColNo) override;
virtual int32_t GetLineno() override;
virtual int32_t GetColNo() override;
private:
virtual ~JSStackFrame();
@ -437,7 +435,11 @@ GetValueIfNotCached(JSContext* aCx, JSObject* aStack,
/* readonly attribute AString filename; */
NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
aFilename.Truncate();
return NS_OK;
}
ThreadsafeAutoJSContext cx;
JS::Rooted<JSString*> filename(cx);
bool canCache = false, useCachedValue = false;
@ -449,7 +451,9 @@ NS_IMETHODIMP JSStackFrame::GetFilename(nsAString& aFilename)
nsAutoJSString str;
if (!str.init(cx, filename)) {
return NS_ERROR_OUT_OF_MEMORY;
JS_ClearPendingException(cx);
aFilename.Truncate();
return NS_OK;
}
aFilename = str;
@ -476,7 +480,11 @@ NS_IMETHODIMP StackFrame::GetFilename(nsAString& aFilename)
/* readonly attribute AString name; */
NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
aFunction.Truncate();
return NS_OK;
}
ThreadsafeAutoJSContext cx;
JS::Rooted<JSString*> name(cx);
bool canCache = false, useCachedValue = false;
@ -491,7 +499,9 @@ NS_IMETHODIMP JSStackFrame::GetName(nsAString& aFunction)
if (name) {
nsAutoJSString str;
if (!str.init(cx, name)) {
return NS_ERROR_OUT_OF_MEMORY;
JS_ClearPendingException(cx);
aFunction.Truncate();
return NS_OK;
}
aFunction = str;
} else {
@ -519,10 +529,13 @@ NS_IMETHODIMP StackFrame::GetName(nsAString& aFunction)
}
// virtual
nsresult
JSStackFrame::GetLineno(int32_t* aLineNo)
int32_t
JSStackFrame::GetLineno()
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
return 0;
}
ThreadsafeAutoJSContext cx;
uint32_t line;
bool canCache = false, useCachedValue = false;
@ -530,30 +543,32 @@ JSStackFrame::GetLineno(int32_t* aLineNo)
&canCache, &useCachedValue, &line);
if (useCachedValue) {
return StackFrame::GetLineno(aLineNo);
return StackFrame::GetLineno();
}
*aLineNo = line;
if (canCache) {
mLineno = line;
mLinenoInitialized = true;
}
return NS_OK;
return line;
}
/* readonly attribute int32_t lineNumber; */
NS_IMETHODIMP StackFrame::GetLineNumber(int32_t* aLineNumber)
{
return GetLineno(aLineNumber);
*aLineNumber = GetLineno();
return NS_OK;
}
// virtual
nsresult
JSStackFrame::GetColNo(int32_t* aColNo)
int32_t
JSStackFrame::GetColNo()
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
return 0;
}
ThreadsafeAutoJSContext cx;
uint32_t col;
bool canCache = false, useCachedValue = false;
@ -561,23 +576,22 @@ JSStackFrame::GetColNo(int32_t* aColNo)
&canCache, &useCachedValue, &col);
if (useCachedValue) {
return StackFrame::GetColNo(aColNo);
return StackFrame::GetColNo();
}
*aColNo = col;
if (canCache) {
mColNo = col;
mColNoInitialized = true;
}
return NS_OK;
return col;
}
/* readonly attribute int32_t columnNumber; */
NS_IMETHODIMP StackFrame::GetColumnNumber(int32_t* aColumnNumber)
{
return GetColNo(aColumnNumber);
*aColumnNumber = GetColNo();
return NS_OK;
}
/* readonly attribute AUTF8String sourceLine; */
@ -590,7 +604,11 @@ NS_IMETHODIMP StackFrame::GetSourceLine(nsACString& aSourceLine)
/* readonly attribute AString asyncCause; */
NS_IMETHODIMP JSStackFrame::GetAsyncCause(nsAString& aAsyncCause)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
aAsyncCause.Truncate();
return NS_OK;
}
ThreadsafeAutoJSContext cx;
JS::Rooted<JSString*> asyncCause(cx);
bool canCache = false, useCachedValue = false;
@ -605,7 +623,9 @@ NS_IMETHODIMP JSStackFrame::GetAsyncCause(nsAString& aAsyncCause)
if (asyncCause) {
nsAutoJSString str;
if (!str.init(cx, asyncCause)) {
return NS_ERROR_OUT_OF_MEMORY;
JS_ClearPendingException(cx);
aAsyncCause.Truncate();
return NS_OK;
}
aAsyncCause = str;
} else {
@ -635,7 +655,11 @@ NS_IMETHODIMP StackFrame::GetAsyncCause(nsAString& aAsyncCause)
/* readonly attribute nsIStackFrame asyncCaller; */
NS_IMETHODIMP JSStackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
*aAsyncCaller = nullptr;
return NS_OK;
}
ThreadsafeAutoJSContext cx;
JS::Rooted<JSObject*> asyncCallerObj(cx);
bool canCache = false, useCachedValue = false;
@ -668,7 +692,11 @@ NS_IMETHODIMP StackFrame::GetAsyncCaller(nsIStackFrame** aAsyncCaller)
/* readonly attribute nsIStackFrame caller; */
NS_IMETHODIMP JSStackFrame::GetCaller(nsIStackFrame** aCaller)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
*aCaller = nullptr;
return NS_OK;
}
ThreadsafeAutoJSContext cx;
JS::Rooted<JSObject*> callerObj(cx);
bool canCache = false, useCachedValue = false;
@ -706,7 +734,11 @@ NS_IMETHODIMP StackFrame::GetCaller(nsIStackFrame** aCaller)
NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack)
{
NS_ENSURE_TRUE(mStack, NS_ERROR_NOT_AVAILABLE);
if (!mStack) {
aStack.Truncate();
return NS_OK;
}
// Sadly we can't use GetValueIfNotCached here, because our getter
// returns bool, not JS::SavedFrameResult. Maybe it's possible to
// make the templates more complicated to deal, but in the meantime
@ -727,12 +759,16 @@ NS_IMETHODIMP JSStackFrame::GetFormattedStack(nsAString& aStack)
JS::Rooted<JSString*> formattedStack(cx);
if (!JS::StringifySavedFrameStack(cx, stack, &formattedStack)) {
return NS_ERROR_UNEXPECTED;
JS_ClearPendingException(cx);
aStack.Truncate();
return NS_OK;
}
nsAutoJSString str;
if (!str.init(cx, formattedStack)) {
return NS_ERROR_OUT_OF_MEMORY;
JS_ClearPendingException(cx);
aStack.Truncate();
return NS_OK;
}
aStack = str;
@ -787,9 +823,7 @@ NS_IMETHODIMP StackFrame::ToString(nsACString& _retval)
funname.AssignLiteral("<TOP_LEVEL>");
}
int32_t lineno;
rv = GetLineno(&lineno);
NS_ENSURE_SUCCESS(rv, rv);
int32_t lineno = GetLineno();
static const char format[] = "%s frame :: %s :: %s :: line %d";
_retval.AppendPrintf(format, frametype,

View File

@ -17,7 +17,7 @@ skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in
[webgl-mochitest/test_implicit_color_buffer_float.html]
[webgl-mochitest/test_highp_fs.html]
[webgl-mochitest/test_no_arr_points.html]
skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.3 aws only; bug 1030942
[webgl-mochitest/test_noprog_draw.html]
[webgl-mochitest/test_privileged_exts.html]
[webgl-mochitest/test_texsubimage_float.html]

View File

@ -1176,7 +1176,7 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent)
nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel();
int32_t targetAPD = targetFrame->PresContext()->AppUnitsPerDevPixel();
ptInTarget = ptInTarget.ConvertAppUnits(rootAPD, targetAPD);
ptInTarget = ptInTarget.ScaleToOtherAppUnits(rootAPD, targetAPD);
nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
nsIFrame::ContentOffsets contentOffsets =

View File

@ -23,6 +23,7 @@
#ifdef XP_MACOSX
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/Event.h"
#include "nsFocusManager.h"
#endif
namespace mozilla {
@ -151,6 +152,22 @@ private:
void
HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus)
{
// In general we don't want to call nsIWidget::SetPluginFocused() for any
// Element that doesn't have a plugin running. But if SetPluginFocused(true)
// was just called for aElement while it had a plugin running, we want to
// make sure nsIWidget::SetPluginFocused(false) gets called for it now, even
// if aFocus is true.
if (aFocus) {
nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aElement);
bool hasRunningPlugin = false;
if (olc) {
olc->GetHasRunningPlugin(&hasRunningPlugin);
}
if (!hasRunningPlugin) {
aFocus = false;
}
}
if (aFocus || aElement == sLastFocused) {
if (!aFocus) {
sLastFocused = nullptr;
@ -163,6 +180,29 @@ HTMLObjectElement::OnFocusBlurPlugin(Element* aElement, bool aFocus)
}
}
void
HTMLObjectElement::HandlePluginCrashed(Element* aElement)
{
OnFocusBlurPlugin(aElement, false);
}
void
HTMLObjectElement::HandlePluginInstantiated(Element* aElement)
{
// If aElement is already focused when a plugin is instantiated, we need
// to initiate a call to nsIWidget::SetPluginFocused(true). Otherwise
// keyboard input won't work in a click-to-play plugin until aElement
// loses focus and regains it.
nsIContent* focusedContent = nullptr;
nsFocusManager *fm = nsFocusManager::GetFocusManager();
if (fm) {
focusedContent = fm->GetFocusedContent();
}
if (SameCOMIdentity(focusedContent, aElement)) {
OnFocusBlurPlugin(aElement, true);
}
}
void
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
WidgetEvent* aEvent)

View File

@ -36,6 +36,8 @@ public:
// Helper methods
static void OnFocusBlurPlugin(Element* aElement, bool aFocus);
static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
static void HandlePluginCrashed(Element* aElement);
static void HandlePluginInstantiated(Element* aElement);
// Weak pointer. Null if last action was blur.
static Element* sLastFocused;
#endif

View File

@ -28,13 +28,13 @@ skip-if = buildapp == 'mulet'
[test_input_color_picker_initial.html]
skip-if = buildapp == 'mulet'
[test_input_color_picker_popup.html]
skip-if = buildapp == 'mulet'
skip-if = buildapp == 'mulet' || android_version == '18' # Android, bug 1147974
[test_input_color_picker_update.html]
skip-if = buildapp == 'mulet'
skip-if = buildapp == 'mulet' || android_version == '18' # Android, bug 1147974
[test_input_defaultValue.html]
[test_input_email.html]
[test_input_event.html]
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop and mulet specific, initial triage
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') || android_version == '18' #Bug 931116, b2g desktop and mulet specific, initial triage; on Android, bug 1147974
[test_input_file_picker.html]
skip-if = buildapp == 'b2g' # b2g(5 failures out of 139 and timing out, bug 901581) b2g-debug(5 failures out of 139 and timing out, bug 901581) b2g-desktop(5 failures out of 139 and timing out, bug 901581)
[test_input_list_attribute.html]

View File

@ -50,7 +50,7 @@ interface nsITranslationNodeList;
interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
[scriptable, uuid(400db885-c2b8-4bf1-bc12-1dadcb08ad12)]
[scriptable, uuid(7f2f44ab-2857-4cc2-8c9d-3d9816f5a4d6)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -1757,6 +1757,11 @@ interface nsIDOMWindowUtils : nsISupports {
in int32_t aRight,
in int32_t aBottom,
in int32_t aLeft);
/**
* Enable some service workers testing features.
*/
attribute boolean serviceWorkersTestingEnabled;
};
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]

View File

@ -55,10 +55,10 @@ FilePickerParent::~FilePickerParent()
// the same runnable on the main thread.
// 3. The main thread sends the results over IPC.
FilePickerParent::FileSizeAndDateRunnable::FileSizeAndDateRunnable(FilePickerParent *aFPParent,
nsCOMArray<nsIDOMFile>& aDomfiles)
nsTArray<nsRefPtr<FileImpl>>& aFiles)
: mFilePickerParent(aFPParent)
{
mDomfiles.SwapElements(aDomfiles);
mFiles.SwapElements(aFiles);
}
bool
@ -82,16 +82,16 @@ FilePickerParent::FileSizeAndDateRunnable::Run()
// results.
if (NS_IsMainThread()) {
if (mFilePickerParent) {
mFilePickerParent->SendFiles(mDomfiles);
mFilePickerParent->SendFiles(mFiles);
}
return NS_OK;
}
// We're not on the main thread, so do the stat().
for (unsigned i = 0; i < mDomfiles.Length(); i++) {
uint64_t size, lastModified;
mDomfiles[i]->GetSize(&size);
mDomfiles[i]->GetMozLastModifiedDate(&lastModified);
for (unsigned i = 0; i < mFiles.Length(); i++) {
ErrorResult rv;
mFiles[i]->GetSize(rv);
mFiles[i]->GetLastModified(rv);
}
// Dispatch ourselves back on the main thread.
@ -111,14 +111,14 @@ FilePickerParent::FileSizeAndDateRunnable::Destroy()
}
void
FilePickerParent::SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles)
FilePickerParent::SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aFiles)
{
nsIContentParent* parent = TabParent::GetFrom(Manager())->Manager();
InfallibleTArray<PBlobParent*> files;
for (unsigned i = 0; i < aDomfiles.Length(); i++) {
BlobParent* blob = parent->GetOrCreateActorForBlob(
static_cast<File*>(aDomfiles[i]));
for (unsigned i = 0; i < aFiles.Length(); i++) {
nsRefPtr<File> file = new File(nullptr, aFiles[i]);
BlobParent* blob = parent->GetOrCreateActorForBlob(file);
if (blob) {
files.AppendElement(blob);
}
@ -139,7 +139,7 @@ FilePickerParent::Done(int16_t aResult)
return;
}
nsCOMArray<nsIDOMFile> domfiles;
nsTArray<nsRefPtr<FileImpl>> files;
if (mMode == nsIFilePicker::modeOpenMultiple) {
nsCOMPtr<nsISimpleEnumerator> iter;
NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
@ -151,25 +151,21 @@ FilePickerParent::Done(int16_t aResult)
if (supports) {
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
// A null parent is fine because File are not used in this process
// but only in the child.
nsCOMPtr<nsIDOMFile> domfile = File::CreateFromFile(nullptr, file);
domfiles.AppendElement(domfile);
nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
files.AppendElement(fileimpl);
}
}
} else {
nsCOMPtr<nsIFile> file;
mFilePicker->GetFile(getter_AddRefs(file));
if (file) {
// A null parent is fine because File are not used in this process
// but only in the child.
nsCOMPtr<nsIDOMFile> domfile = File::CreateFromFile(nullptr, file);
domfiles.AppendElement(domfile);
nsRefPtr<FileImpl> fileimpl = new FileImplFile(file);
files.AppendElement(fileimpl);
}
}
MOZ_ASSERT(!mRunnable);
mRunnable = new FileSizeAndDateRunnable(this, domfiles);
mRunnable = new FileSizeAndDateRunnable(this, files);
if (!mRunnable->Dispatch()) {
unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
}

View File

@ -12,6 +12,7 @@
#include "nsIFilePicker.h"
#include "nsCOMArray.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/PFilePickerParent.h"
namespace mozilla {
@ -29,7 +30,7 @@ class FilePickerParent : public PFilePickerParent
virtual ~FilePickerParent();
void Done(int16_t aResult);
void SendFiles(const nsCOMArray<nsIDOMFile>& aDomfiles);
void SendFiles(const nsTArray<nsRefPtr<FileImpl>>& aDomfiles);
virtual bool RecvOpen(const int16_t& aSelectedType,
const bool& aAddToRecentDocs,
@ -64,11 +65,11 @@ class FilePickerParent : public PFilePickerParent
class FileSizeAndDateRunnable : public nsRunnable
{
FilePickerParent* mFilePickerParent;
nsCOMArray<nsIDOMFile> mDomfiles;
nsTArray<nsRefPtr<FileImpl>> mFiles;
nsCOMPtr<nsIEventTarget> mEventTarget;
public:
FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsCOMArray<nsIDOMFile>& aDomfiles);
FileSizeAndDateRunnable(FilePickerParent *aFPParent, nsTArray<nsRefPtr<FileImpl>>& aFiles);
bool Dispatch();
NS_IMETHOD Run();
void Destroy();

View File

@ -55,7 +55,7 @@ using mozilla::CSSToScreenScale from "Units.h";
using mozilla::CommandInt from "mozilla/EventForwards.h";
using mozilla::Modifiers from "mozilla/EventForwards.h";
using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
using mozilla::WritingMode from "WritingModes.h";
using mozilla::WritingMode from "mozilla/WritingModes.h";
using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
namespace mozilla {

View File

@ -2026,7 +2026,7 @@ TabChild::RecvUpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
mOrientation = orientation;
ScreenIntSize oldScreenSize = mInnerSize;
mInnerSize = size;
mWidget->Resize(0, 0, size.width, size.height,
mWidget->Resize(rect.x + chromeDisp.x, rect.y + chromeDisp.y, size.width, size.height,
true);
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(WebNavigation());

View File

@ -80,6 +80,7 @@
#include "nsICancelable.h"
#include "gfxPrefs.h"
#include "nsILoginManagerPrompter.h"
#include "nsPIWindowRoot.h"
#include <algorithm>
using namespace mozilla::dom;
@ -324,10 +325,36 @@ TabParent::CacheFrameLoader(nsFrameLoader* aFrameLoader)
void
TabParent::SetOwnerElement(Element* aElement)
{
// If we held previous content then unregister for its events.
RemoveWindowListeners();
// Update to the new content, and register to listen for events from it.
mFrameElement = aElement;
if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
if (eventTarget) {
eventTarget->AddEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
this, false, false);
}
}
TryCacheDPIAndScale();
}
void
TabParent::RemoveWindowListeners()
{
if (mFrameElement && mFrameElement->OwnerDoc()->GetWindow()) {
nsCOMPtr<nsPIDOMWindow> window = mFrameElement->OwnerDoc()->GetWindow();
nsCOMPtr<EventTarget> eventTarget = window->GetTopWindowRoot();
if (eventTarget) {
eventTarget->RemoveEventListener(NS_LITERAL_STRING("MozUpdateWindowPos"),
this, false);
}
}
}
void
TabParent::GetAppType(nsAString& aOut)
{
@ -879,8 +906,7 @@ TabParent::RecvSetDimensions(const uint32_t& aFlags,
}
void
TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
const nsIntPoint& aChromeDisp)
TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size)
{
if (mIsDestroyed) {
return;
@ -891,12 +917,20 @@ TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
if (!mUpdatedDimensions || mOrientation != orientation ||
mDimensions != size || !mRect.IsEqualEdges(rect)) {
nsCOMPtr<nsIWidget> widget = GetWidget();
nsIntRect contentRect = rect;
if (widget) {
contentRect.x += widget->GetClientOffset().x;
contentRect.y += widget->GetClientOffset().y;
}
mUpdatedDimensions = true;
mRect = rect;
mRect = contentRect;
mDimensions = size;
mOrientation = orientation;
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, aChromeDisp);
nsIntPoint chromeOffset = -LayoutDevicePixel::ToUntyped(GetChildProcessOffset());
unused << SendUpdateDimensions(mRect, mDimensions, mOrientation, chromeOffset);
}
}
@ -2733,6 +2767,27 @@ TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aAc
return true;
}
nsresult
TabParent::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("MozUpdateWindowPos") && !mIsDestroyed) {
// This event is sent when the widget moved. Therefore we only update
// the position.
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
if (!frameLoader) {
return NS_OK;
}
nsIntRect windowDims;
NS_ENSURE_SUCCESS(frameLoader->GetWindowDimensions(windowDims), NS_ERROR_FAILURE);
UpdateDimensions(windowDims, mDimensions);
return NS_OK;
}
return NS_OK;
}
class FakeChannel final : public nsIChannel,
public nsIAuthPromptCallback,
public nsIInterfaceRequestor,

View File

@ -7,21 +7,22 @@
#ifndef mozilla_tabs_TabParent_h
#define mozilla_tabs_TabParent_h
#include "mozilla/EventForwards.h"
#include "js/TypeDecls.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/dom/PFilePickerParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/dom/ipc/IdType.h"
#include "mozilla/EventForwards.h"
#include "mozilla/WritingModes.h"
#include "nsCOMPtr.h"
#include "nsIAuthPromptProvider.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDOMEventListener.h"
#include "nsISecureBrowserUI.h"
#include "nsITabParent.h"
#include "nsIXULBrowserWindow.h"
#include "nsWeakReference.h"
#include "Units.h"
#include "WritingModes.h"
#include "js/TypeDecls.h"
class nsFrameLoader;
class nsIFrameLoader;
@ -59,6 +60,7 @@ class Element;
struct StructuredCloneData;
class TabParent final : public PBrowserParent
, public nsIDOMEventListener
, public nsITabParent
, public nsIAuthPromptProvider
, public nsISecureBrowserUI
@ -72,6 +74,8 @@ class TabParent final : public PBrowserParent
public:
// nsITabParent
NS_DECL_NSITABPARENT
// nsIDOMEventListener interfaces
NS_DECL_NSIDOMEVENTLISTENER
TabParent(nsIContentParent* aManager,
const TabId& aTabId,
@ -106,6 +110,8 @@ public:
void Destroy();
void RemoveWindowListeners();
virtual bool RecvMoveFocus(const bool& aForward) override;
virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
@ -224,8 +230,7 @@ public:
// message-sending functions under a layer of indirection and
// eating the return values
void Show(const ScreenIntSize& size, bool aParentIsActive);
void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size,
const nsIntPoint& chromeDisp);
void UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size);
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
void UIResolutionChanged();
void RequestFlingSnap(const FrameMetrics::ViewID& aScrollId,

View File

@ -161,3 +161,5 @@ XMLDocumentLoadPrincipalMismatch=Use of document.load forbidden on Documents tha
IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet complete has been aborted due to page navigation.
# LOCALIZATION NOTE (WillChangeBudgetWarning): Do not translate Will-change, %1$S,%2$S,%3$S are numbers.
WillChangeBudgetWarning=Will-change memory consumption is too high. Surface area covers %1$S pixels, budget is the document surface area multiplied by %2$S (%3$S pixels). All occurences of will-change in the document are ignored when over budget.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.

View File

@ -1006,6 +1006,8 @@ MediaCodecReader::DecodeVideoFrameSync(int64_t aTimeThreshold)
}
if (v) {
// Notify mDecoder that we have decoded a video frame.
mDecoder->NotifyDecodedFrames(0, 1, 0);
VideoQueue().Push(v);
} else {
NS_WARNING("Unable to create VideoData");
@ -1817,6 +1819,10 @@ MediaCodecReader::GetCodecOutputData(Track& aTrack,
}
if (status == OK) {
// Notify mDecoder that we have parsed a video frame.
if (&aTrack == &mVideoTrack) {
mDecoder->NotifyDecodedFrames(1, 0, 0);
}
if (!IsValidTimestampUs(aThreshold) || info.mTimeUs >= aThreshold) {
// Get a valid output buffer.
break;

View File

@ -101,7 +101,13 @@ MediaOmxCommonDecoder::PauseStateMachine()
if (!mDecoderStateMachine) {
return;
}
mDecoderStateMachine->SetDormant(true);
// enter dormant state
RefPtr<nsRunnable> event =
NS_NewRunnableMethodWithArg<bool>(
mDecoderStateMachine,
&MediaDecoderStateMachine::SetDormant,
true);
mDecoderStateMachine->TaskQueue()->Dispatch(event);
}
void
@ -124,7 +130,13 @@ MediaOmxCommonDecoder::ResumeStateMachine()
mNextState = mPlayState;
ChangeState(PLAY_STATE_LOADING);
mDecoderStateMachine->SetDormant(false);
// exit dormant state
RefPtr<nsRunnable> event =
NS_NewRunnableMethodWithArg<bool>(
mDecoderStateMachine,
&MediaDecoderStateMachine::SetDormant,
false);
mDecoderStateMachine->TaskQueue()->Dispatch(event);
}
void

View File

@ -22,7 +22,7 @@
# do ok(true, "Type not supported") and stop the test.
[DEFAULT]
skip-if = buildapp == 'mulet' || (os == 'win' && strictContentSandbox) # strictContentSandbox (Bug 1042735)
skip-if = buildapp == 'mulet' || (os == 'win' && strictContentSandbox) || android_version == '18' # strictContentSandbox (Bug 1042735)
support-files =
320x240.ogv
320x240.ogv^headers^

View File

@ -2,7 +2,7 @@
# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
# won't run on b2g desktop tests - bug 1119993
# broken HTTPS on b2g emulator - bug 1135339
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk')
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk')
support-files =
/.well-known/idp-proxy/idp.js

View File

@ -1,6 +1,6 @@
[DEFAULT]
# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18'
support-files =
head.js
dataChannel.js

View File

@ -189,7 +189,7 @@ void Reverb::process(const AudioChunk* sourceBus, AudioChunk* destinationBus, si
// simply copy L -> R
float* destinationChannelR = static_cast<float*>(const_cast<void*>(destinationBus->mChannelData[1]));
bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->mDuration) >= framesToProcess && size_t(destinationBus->mDuration) >= framesToProcess;
bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->mDuration) >= framesToProcess;
MOZ_ASSERT(isCopySafe);
if (!isCopySafe)
return;

View File

@ -120,9 +120,9 @@ skip-if = toolkit == 'android' # bug 1145816
[test_mediaStreamAudioSourceNodePassThrough.html]
[test_mediaStreamAudioSourceNodeResampling.html]
[test_mixingRules.html]
skip-if = android_version == '10' # bug 1091965
skip-if = android_version == '10' || android_version == '18' # bug 1091965
[test_mozaudiochannel.html]
skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' # Android: bug 1061675
skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' || android_version == '18' # Android: bug 1061675
[test_nodeToParamConnection.html]
[test_OfflineAudioContext.html]
[test_offlineDestinationChannelCountLess.html]

View File

@ -334,7 +334,8 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPe
if (streamType == nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN) {
SuspendRequest();
} else if (!SetStreamType(streamType, false)) {
}
if (!SetStreamType(streamType, false)) {
return NS_ERROR_FAILURE;
}
@ -364,6 +365,12 @@ nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
// instance is destroyed.
NS_ADDREF_THIS();
break;
case nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN:
MOZ_ASSERT(!aNeedsResume);
mStreamType = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
// In this case we just want to set mStreamType but we do not want to
// execute anything else in this function.
return true;
default:
return false;
}

View File

@ -790,7 +790,6 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
tabContentBounds.ScaleInverseRoundOut(scaleFactor);
int32_t windowH = tabContentBounds.height + int(chromeSize.y);
// This is actually relative to window-chrome.
nsPoint pluginPosition = AsNsPoint(pluginFrame->GetScreenRect().TopLeft());
// Convert (sourceX, sourceY) to 'real' (not PuppetWidget) screen space.
@ -800,8 +799,8 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
nsPoint screenPoint;
switch (sourceSpace) {
case NPCoordinateSpacePlugin:
screenPoint = sourcePoint + pluginFrame->GetContentRectRelativeToSelf().TopLeft() +
chromeSize + pluginPosition + windowPosition;
screenPoint = sourcePoint + pluginPosition +
pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
break;
case NPCoordinateSpaceWindow:
screenPoint = nsPoint(sourcePoint.x, windowH-sourcePoint.y) +
@ -824,8 +823,8 @@ NPBool nsPluginInstanceOwner::ConvertPointPuppet(PuppetWidget *widget,
nsPoint destPoint;
switch (destSpace) {
case NPCoordinateSpacePlugin:
destPoint = screenPoint - pluginFrame->GetContentRectRelativeToSelf().TopLeft() -
chromeSize - pluginPosition - windowPosition;
destPoint = screenPoint - pluginPosition -
pluginFrame->GetContentRectRelativeToSelf().TopLeft() / nsPresContext::AppUnitsPerCSSPixel();
break;
case NPCoordinateSpaceWindow:
destPoint = screenPoint - windowPosition;
@ -1308,7 +1307,7 @@ GetOffsetRootContent(nsIFrame* aFrame)
int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
if (!f || newAPD != currAPD) {
// Convert docOffset to the right APD and add it to offset.
offset += docOffset.ConvertAppUnits(currAPD, apd);
offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
docOffset.x = docOffset.y = 0;
}
currAPD = newAPD;
@ -1316,7 +1315,7 @@ GetOffsetRootContent(nsIFrame* aFrame)
}
}
offset += docOffset.ConvertAppUnits(currAPD, apd);
offset += docOffset.ScaleToOtherAppUnits(currAPD, apd);
return offset;
}

View File

@ -1185,6 +1185,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
void
nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
{
MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
MOZ_ASSERT(mRequest);
mStreamType = aStreamType;
if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
@ -1201,8 +1202,6 @@ nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
}
}
const int32_t nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN = UINT16_MAX;
nsresult
nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
{

View File

@ -131,7 +131,9 @@ public:
// Called by nsNPAPIPluginStreamListener
void OnStreamTypeSet(const int32_t aStreamType);
static const int32_t STREAM_TYPE_UNKNOWN;
enum {
STREAM_TYPE_UNKNOWN = UINT16_MAX
};
private:
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);

View File

@ -1395,7 +1395,7 @@ PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
MOZ_ASSERT(mSurrogate);
mSurrogate->AsyncCallDeparting();
if (SendAsyncNPP_NewStream(bs, NullableString(type), seekable)) {
*stype = UINT16_MAX;
*stype = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
} else {
err = NPERR_GENERIC_ERROR;
}

View File

@ -537,6 +537,13 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
OnInitFailure();
return;
}
CrashReporterParent* crashReporter = CrashReporter();
if (crashReporter) {
crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
mIsStartingAsync ?
NS_LITERAL_CSTRING("1") :
NS_LITERAL_CSTRING("0"));
}
#ifdef XP_WIN
{ // Scope for lock
mozilla::MutexAutoLock lock(mCrashReporterMutex);
@ -607,6 +614,12 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome)
{
#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
mIsStartingAsync ?
NS_LITERAL_CSTRING("1") :
NS_LITERAL_CSTRING("0"));
#endif
#endif
}

View File

@ -408,12 +408,16 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// path-level matching, unless the channel got redirected, see:
// http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
if (!aWasRedirected && !mPath.IsEmpty()) {
// cloning uri so we can ignore the ref
nsCOMPtr<nsIURI> uri;
aUri->CloneIgnoringRef(getter_AddRefs(uri));
// converting aUri into nsIURL so we can strip query and ref
// example.com/test#foo -> example.com/test
// example.com/test?val=foo -> example.com/test
nsCOMPtr<nsIURL> url = do_QueryInterface(aUri);
if (!url) {
NS_ASSERTION(false, "can't QI into nsIURI");
return false;
}
nsAutoCString uriPath;
rv = uri->GetPath(uriPath);
rv = url->GetFilePath(uriPath);
NS_ENSURE_SUCCESS(rv, false);
// check if the last character of mPath is '/'; if so
// we just have to check loading resource is within

View File

@ -61,6 +61,7 @@ skip-if = true
[test_pointer-events-1b.xhtml]
[test_pointer-events-2.xhtml]
[test_pointer-events-3.xhtml]
skip-if = android_version == '18' # bug 1147994
[test_pointer-events-4.xhtml]
[test_pointer-events-5.xhtml]
[test_pointer-events-6.xhtml]

View File

@ -7,9 +7,15 @@
interface WorkerDebuggerGlobalScope : EventTarget {
readonly attribute object global;
void enterEventLoop();
void leaveEventLoop();
void postMessage(DOMString message);
attribute EventHandler onmessage;
void reportError(DOMString message);
};
// So you can debug while you debug

View File

@ -14,6 +14,7 @@
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIScriptError.h"
#include "nsIScriptSecurityManager.h"
#include "nsISupportsPriority.h"
#include "nsITimer.h"
@ -26,6 +27,7 @@
#include "jsfriendapi.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/AtomList.h"
@ -1414,6 +1416,12 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
nsCString sharedWorkerScriptSpec;
const bool isServiceWorker = aWorkerPrivate->IsServiceWorker();
if (isServiceWorker) {
AssertIsOnMainThread();
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_ATTEMPTS, 1);
}
bool isSharedOrServiceWorker = aWorkerPrivate->IsSharedWorker() ||
aWorkerPrivate->IsServiceWorker();
if (isSharedOrServiceWorker) {
@ -1461,6 +1469,19 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
if (queued) {
domainInfo->mQueuedWorkers.AppendElement(aWorkerPrivate);
if (isServiceWorker) {
AssertIsOnMainThread();
// ServiceWorker spawn gets queued due to hitting max workers per domain
// limit so let's log a warning.
// Note: aWorkerPrivate->GetDocument() call might result nullptr due to
// no window so the message warning will show up in the browser console.
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
NS_LITERAL_CSTRING("DOM"),
aWorkerPrivate->GetDocument(),
nsContentUtils::eDOM_PROPERTIES,
"HittingMaxWorkersPerDomain");
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_SPAWN_GETS_QUEUED, 1);
}
}
else if (parent) {
domainInfo->mChildWorkerCount++;
@ -1529,6 +1550,10 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return false;
}
if (isServiceWorker) {
AssertIsOnMainThread();
Telemetry::Accumulate(Telemetry::SERVICE_WORKER_WAS_SPAWNED, 1);
}
return true;
}

View File

@ -885,6 +885,10 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
nsCOMPtr<nsPIDOMWindow> outerWindow = window->GetOuterWindow();
bool serviceWorkersTestingEnabled =
outerWindow->GetServiceWorkersTestingEnabled();
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (!doc) {
return NS_ERROR_FAILURE;
@ -893,8 +897,8 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
nsCOMPtr<nsIURI> documentURI = doc->GetBaseURI();
bool authenticatedOrigin = false;
// FIXME(nsm): Bug 1003991. Disable check when devtools are open.
if (Preferences::GetBool("dom.serviceWorkers.testing.enabled")) {
if (Preferences::GetBool("dom.serviceWorkers.testing.enabled") ||
serviceWorkersTestingEnabled) {
authenticatedOrigin = true;
}

View File

@ -1505,20 +1505,23 @@ public:
nsIScriptGlobalObject* sgo;
if (aWorkerPrivate) {
nsIDOMEventTarget* target = nullptr;
WorkerGlobalScope* globalScope = nullptr;
UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalScope);
if (globalScope) {
MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
target = static_cast<nsIDOMEventTarget*>(globalScope);
} else {
if (!globalScope) {
WorkerDebuggerGlobalScope* globalScope = nullptr;
UNWRAP_OBJECT(WorkerDebuggerGlobalScope, global, globalScope);
MOZ_ASSERT(globalScope);
MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
target = static_cast<nsIDOMEventTarget*>(globalScope);
aWorkerPrivate->ReportErrorToDebugger(aFilename, aLineNumber,
aMessage);
return true;
}
MOZ_ASSERT(global == globalScope->GetWrapperPreserveColor());
nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalScope);
nsRefPtr<ErrorEvent> event =
ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
event->SetTrusted(true);
@ -4214,6 +4217,41 @@ WorkerPrivateParent<Derived>::AssertInnerWindowIsCorrect() const
#endif
class ReportDebuggerErrorRunnable final : public nsIRunnable
{
nsRefPtr<WorkerDebugger> mDebugger;
nsString mFilename;
uint32_t mLineno;
nsString mMessage;
public:
ReportDebuggerErrorRunnable(WorkerDebugger* aDebugger,
const nsAString& aFilename, uint32_t aLineno,
const nsAString& aMessage)
: mDebugger(aDebugger),
mFilename(aFilename),
mLineno(aLineno),
mMessage(aMessage)
{
}
NS_DECL_THREADSAFE_ISUPPORTS
private:
~ReportDebuggerErrorRunnable()
{ }
NS_IMETHOD
Run() override
{
mDebugger->ReportErrorToDebuggerOnMainThread(mFilename, mLineno, mMessage);
return NS_OK;
}
};
NS_IMPL_ISUPPORTS(ReportDebuggerErrorRunnable, nsIRunnable)
WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
: mMutex("WorkerDebugger::mMutex"),
mCondVar(mMutex, "WorkerDebugger::mCondVar"),
@ -4499,6 +4537,41 @@ WorkerDebugger::PostMessageToDebuggerOnMainThread(const nsAString& aMessage)
}
}
void
WorkerDebugger::ReportErrorToDebugger(const nsAString& aFilename,
uint32_t aLineno,
const nsAString& aMessage)
{
mWorkerPrivate->AssertIsOnWorkerThread();
nsCOMPtr<nsIRunnable> runnable =
new ReportDebuggerErrorRunnable(this, aFilename, aLineno, aMessage);
if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to report error to debugger on main thread!");
}
}
void
WorkerDebugger::ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
uint32_t aLineno,
const nsAString& aMessage)
{
AssertIsOnMainThread();
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> listeners;
{
MutexAutoLock lock(mMutex);
listeners.AppendElements(mListeners);
}
for (size_t index = 0; index < listeners.Length(); ++index) {
listeners[index]->OnError(aFilename, aLineno, aMessage);
}
LogErrorToConsole(aMessage, aFilename, nsString(), aLineno, 0, 0, 0);
}
WorkerPrivate::WorkerPrivate(JSContext* aCx,
WorkerPrivate* aParent,
const nsAString& aScriptURL,
@ -4510,6 +4583,7 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
aSharedWorkerName, aLoadInfo)
, mJSContext(nullptr)
, mPRThread(nullptr)
, mDebuggerEventLoopLevel(0)
, mErrorHandlerRecursionCount(0)
, mNextTimeoutId(1)
, mStatus(Pending)
@ -6113,12 +6187,90 @@ WorkerPrivate::PostMessageToParentMessagePort(
aMessagePortSerial, aRv);
}
void
WorkerPrivate::EnterDebuggerEventLoop()
{
AssertIsOnWorkerThread();
JSContext* cx = GetJSContext();
MOZ_ASSERT(cx);
uint32_t currentEventLoopLevel = ++mDebuggerEventLoopLevel;
while (currentEventLoopLevel <= mDebuggerEventLoopLevel) {
bool debuggerRunnablesPending = false;
{
MutexAutoLock lock(mMutex);
debuggerRunnablesPending = !mDebuggerQueue.IsEmpty();
}
// Don't block with the periodic GC timer running.
if (!debuggerRunnablesPending) {
SetGCTimerMode(IdleTimer);
}
// Wait for something to do
{
MutexAutoLock lock(mMutex);
while (mControlQueue.IsEmpty() &&
!(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty())) {
WaitForWorkerEvents();
}
ProcessAllControlRunnablesLocked();
}
if (debuggerRunnablesPending) {
// Start the periodic GC timer if it is not already running.
SetGCTimerMode(PeriodicTimer);
WorkerRunnable* runnable;
{
MutexAutoLock lock(mMutex);
mDebuggerQueue.Pop(runnable);
}
MOZ_ASSERT(runnable);
static_cast<nsIRunnable*>(runnable)->Run();
runnable->Release();
// Now *might* be a good time to GC. Let the JS engine make the decision.
JS_MaybeGC(cx);
}
}
}
void
WorkerPrivate::LeaveDebuggerEventLoop()
{
AssertIsOnWorkerThread();
MutexAutoLock lock(mMutex);
if (mDebuggerEventLoopLevel > 0) {
--mDebuggerEventLoopLevel;
}
}
void
WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage)
{
mDebugger->PostMessageToDebugger(aMessage);
}
void
WorkerPrivate::ReportErrorToDebugger(const nsAString& aFilename,
uint32_t aLineno,
const nsAString& aMessage)
{
mDebugger->ReportErrorToDebugger(aFilename, aLineno, aMessage);
}
bool
WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
{

View File

@ -56,6 +56,8 @@ class PrincipalInfo;
struct PRThread;
class ReportDebuggerErrorRunnable;
BEGIN_WORKERS_NAMESPACE
class AutoSyncLoopHolder;
@ -721,6 +723,8 @@ public:
};
class WorkerDebugger : public nsIWorkerDebugger {
friend class ::ReportDebuggerErrorRunnable;
mozilla::Mutex mMutex;
mozilla::CondVar mCondVar;
@ -753,6 +757,10 @@ public:
void
PostMessageToDebugger(const nsAString& aMessage);
void
ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
const nsAString& aMessage);
private:
virtual
~WorkerDebugger();
@ -762,6 +770,11 @@ private:
void
PostMessageToDebuggerOnMainThread(const nsAString& aMessage);
void
ReportErrorToDebuggerOnMainThread(const nsAString& aFilename,
uint32_t aLineno,
const nsAString& aMessage);
};
class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
@ -802,6 +815,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
nsTArray<ParentType*> mChildWorkers;
nsTArray<WorkerFeature*> mFeatures;
nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
uint32_t mDebuggerEventLoopLevel;
struct SyncLoopInfo
{
@ -962,9 +976,19 @@ public:
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv);
void
EnterDebuggerEventLoop();
void
LeaveDebuggerEventLoop();
void
PostMessageToDebugger(const nsAString& aMessage);
void
ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno,
const nsAString& aMessage);
bool
NotifyInternal(JSContext* aCx, Status aStatus);

View File

@ -513,12 +513,35 @@ WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
}
void
WorkerDebuggerGlobalScope::EnterEventLoop()
{
mWorkerPrivate->EnterDebuggerEventLoop();
}
void
WorkerDebuggerGlobalScope::LeaveEventLoop()
{
mWorkerPrivate->LeaveDebuggerEventLoop();
}
void
WorkerDebuggerGlobalScope::PostMessage(const nsAString& aMessage)
{
mWorkerPrivate->PostMessageToDebugger(aMessage);
}
void
WorkerDebuggerGlobalScope::ReportError(JSContext* aCx,
const nsAString& aMessage)
{
JS::AutoFilename afn;
uint32_t lineno = 0;
JS::DescribeScriptedCaller(aCx, &afn, &lineno);
nsString filename(NS_ConvertUTF8toUTF16(afn.get()));
mWorkerPrivate->ReportErrorToDebugger(filename, lineno, aMessage);
}
void
WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
const Optional<nsAString>& aString) const

View File

@ -264,11 +264,20 @@ public:
void
GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
void
EnterEventLoop();
void
LeaveEventLoop();
void
PostMessage(const nsAString& aMessage);
IMPL_EVENT_HANDLER(message)
void
ReportError(JSContext* aCx, const nsAString& aMessage);
void
Dump(JSContext* aCx, const Optional<nsAString>& aString) const;

View File

@ -2,11 +2,14 @@
interface nsIDOMWindow;
[scriptable, uuid(ead45621-22a7-48ef-b7db-c4252ae3e6cb)]
[scriptable, uuid(55d54034-1573-4889-b1d9-93ba12fc33c7)]
interface nsIWorkerDebuggerListener : nsISupports
{
void onClose();
void onError(in DOMString filename, in unsigned long lineno,
in DOMString message);
void onMessage(in DOMString message);
};

View File

@ -1,6 +1,6 @@
"use strict"
onmessage = function (event) {
this.onmessage = function (event) {
switch (event.data) {
case "ping":
postMessage("pong");

View File

@ -0,0 +1,14 @@
"use strict";
function f() {
debugger;
}
self.onmessage = function (event) {
switch (event.data) {
case "ping":
debugger;
postMessage("pong");
break;
};
};

View File

@ -0,0 +1,29 @@
"use strict";
let frames = [];
var dbg = new Debugger(global);
dbg.onDebuggerStatement = function (frame) {
frames.push(frame);
postMessage("paused");
enterEventLoop();
frames.pop();
postMessage("resumed");
};
this.onmessage = function (event) {
switch (event.data) {
case "eval":
frames[frames.length - 1].eval("f()");
postMessage("evalled");
break;
case "ping":
postMessage("pong");
break;
case "resume":
leaveEventLoop();
break;
};
};

View File

@ -0,0 +1,25 @@
"use strict";
function f() {
debugger;
}
var worker = new Worker("WorkerDebuggerGlobalScope.enterEventLoop_childWorker.js");
worker.onmessage = function (event) {
postMessage("child:" + event.data);
};
self.onmessage = function (event) {
var message = event.data;
if (message.indexOf(":") >= 0) {
worker.postMessage(message.split(":")[1]);
return;
}
switch (message) {
case "ping":
debugger;
postMessage("pong");
break;
};
};

View File

@ -0,0 +1,5 @@
"use strict";
self.onerror = function () {
postMessage("error");
}

View File

@ -0,0 +1,12 @@
"use strict";
this.onmessage = function (event) {
switch (event.data) {
case "report":
reportError("reported");
break;
case "throw":
throw new Error("thrown");
break;
}
};

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