Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-11-17 08:04:25 -05:00
commit a3c3539b92
166 changed files with 3192 additions and 1243 deletions

View File

@ -38,7 +38,7 @@ filters::GetRow(Accessible* aAccessible)
return eMatch | eSkipSubtree;
// Look for rows inside rowgroup.
if (role == roles::SECTION)
if (role == roles::GROUPING)
return eSkip;
return eSkipSubtree;

View File

@ -433,6 +433,16 @@ static nsRoleMapEntry sWAIRoleMaps[] =
kNoReqStates,
eARIASelectable
},
{ // rowgroup
&nsGkAtoms::rowgroup,
roles::GROUPING,
kUseMapRole,
eNoValue,
eNoAction,
eNoLiveAttr,
kGenericAccType,
kNoReqStates
},
{ // rowheader
&nsGkAtoms::rowheader,
roles::ROWHEADER,

View File

@ -18,7 +18,7 @@ mozilla::a11y::ARIAGridCellAccessible::TableFor(Accessible* aRow) const
Accessible* table = aRow->Parent();
if (table) {
roles::Role tableRole = table->Role();
if (tableRole == roles::SECTION) { // if there's a rowgroup.
if (tableRole == roles::GROUPING) { // if there's a rowgroup.
table = table->Parent();
if (table)
tableRole = table->Role();

View File

@ -10,6 +10,7 @@
#include "DocAccessible.h"
#include "nsAccessibilityService.h"
#include "NotificationController.h"
#include "States.h"
inline void
DocAccessible::BindChildDocument(DocAccessible* aDocument)
@ -39,6 +40,21 @@ DocAccessible::UpdateText(nsIContent* aTextNode)
mNotificationController->ScheduleTextUpdate(aTextNode);
}
inline void
DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
{
mLoadState |= eDOMLoaded;
mLoadEventType = aLoadEventType;
// If the document is loaded completely then network activity was presumingly
// caused by file loading. Fire busy state change event.
if (HasLoadState(eCompletelyLoaded) && IsLoadEventTarget()) {
nsRefPtr<AccEvent> stateEvent =
new AccStateChangeEvent(this, mozilla::a11y::states::BUSY, false);
FireDelayedAccessibleEvent(stateEvent);
}
}
inline void
DocAccessible::MaybeNotifyOfValueChange(Accessible* aAccessible)
{

View File

@ -7,7 +7,6 @@
#include "AccIterator.h"
#include "DocAccessible-inl.h"
#include "nsAccCache.h"
#include "nsAccessibilityService.h"
#include "nsAccessiblePivot.h"
#include "nsAccTreeWalker.h"
#include "nsAccUtils.h"
@ -15,7 +14,6 @@
#include "nsTextEquivUtils.h"
#include "Role.h"
#include "RootAccessible.h"
#include "States.h"
#include "nsIMutableArray.h"
#include "nsICommandManager.h"

View File

@ -330,12 +330,7 @@ protected:
/**
* Marks this document as loaded or loading.
*/
void NotifyOfLoad(uint32_t aLoadEventType)
{
mLoadState |= eDOMLoaded;
mLoadEventType = aLoadEventType;
}
void NotifyOfLoad(uint32_t aLoadEventType);
void NotifyOfLoading(bool aIsReloading);
friend class nsAccDocManager;

View File

@ -39,6 +39,7 @@ DIRS = \
include $(DEPTH)/config/autoconf.mk
MOCHITEST_A11Y_FILES =\
dumbfile.xpi \
formimage.png \
letters.gif \
moz.png \

Binary file not shown.

View File

@ -1417,7 +1417,8 @@ function caretMoveChecker(aCaretOffset, aTargetOrFunc, aTargetFuncArg)
* State change checker.
*/
function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
aTargetOrFunc, aTargetFuncArg, aIsAsync)
aTargetOrFunc, aTargetFuncArg, aIsAsync,
aSkipCurrentStateCheck)
{
this.__proto__ = new invokerChecker(EVENT_STATE_CHANGE, aTargetOrFunc,
aTargetFuncArg, aIsAsync);
@ -1441,6 +1442,11 @@ function stateChangeChecker(aState, aIsExtraState, aIsEnabled,
is(event.isEnabled(), aIsEnabled,
"Wrong state of statechange event state");
if (aSkipCurrentStateCheck) {
todo(false, "State checking was skipped!");
return;
}
var state = aIsEnabled ? (aIsExtraState ? 0 : aState) : 0;
var extraState = aIsEnabled ? (aIsExtraState ? aState : 0) : 0;
var unxpdState = aIsEnabled ? 0 : (aIsExtraState ? 0 : aState);

View File

@ -19,6 +19,7 @@ MOCHITEST_A11Y_FILES =\
test_controls.html \
test_controls.xul \
test_doc.html \
test_doc_busy.html \
test_docarticle.html \
test_editablebody.html \
test_expandable.xul \

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html>
<head>
<title>states of document</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
//gA11yEventDumpToConsole = true; // debugging stuff
function loadFile()
{
// XXX: state change busy false event might be delievered when document
// has state busy true already (these events should be coalesced actually
// in this case as nothing happened).
this.eventSeq = [
new stateChangeChecker(STATE_BUSY, false, true, document, null, false, true),
new stateChangeChecker(STATE_BUSY, false, false, document)
];
this.invoke = function loadFile_invoke()
{
synthesizeMouse(getNode("link"), 1, 1, {});
}
this.getID = function loadFile_getID()
{
return "load file: state busy change events on document";
}
}
var gQueue = null;
function doTest()
{
// State busy change event on file loading.
//enableLogging("docload"); // debugging
gQueue = new eventQueue();
gQueue.push(new loadFile());
//gQueue.onFinish = function() { disableLogging(); } // debugging
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Missing busy state change event when downloading files"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=446469">Bug 446469</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<a id="link" href="http://example.com/a11y/accessible/dumbfile.xpi">a file</a>
</body>
</html>

View File

@ -15,6 +15,7 @@ MOCHITEST_A11Y_FILES =\
dockids.html \
$(warning test_applicationacc.xul temporarily disabled, see bug 561508) \
test_aria_globals.html \
test_aria_grid.html \
test_aria_imgmap.html \
test_aria_menu.html \
test_aria_presentation.html \

View File

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<title>HTML table tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript">
function doTest()
{
//////////////////////////////////////////////////////////////////////////
// grid having rowgroups
var accTree =
{ TABLE: [
{ GROUPING: [
{ ROW: [
{ GRID_CELL: [
{ TEXT_LEAF: [ ] }
] }
] }
] },
] };
testAccessibleTree("grid", accTree);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Support ARIA role rowgroup"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=525909">
Mozilla Bug 525909
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="grid" role="grid">
<div role="rowgroup">
<div role="row">
<div role="gridcell">cell</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -43,7 +43,7 @@ if (typeof kIdentityJSLoaded === 'undefined') {
}
var showUI = false;
var options = null;
var options = {};
var isLoaded = false;
var func = null;
@ -65,7 +65,6 @@ function identityCall(message) {
* destroys our context.
*/
function closeIdentityDialog() {
log('ready to close');
// tell gecko we're done.
func = null; options = null;
sendAsyncMessage(kIdentityDelegateFinished);
@ -78,17 +77,14 @@ function closeIdentityDialog() {
function doInternalWatch() {
log("doInternalWatch:", options, isLoaded);
if (options && isLoaded) {
log("internal watch options:", options);
let BrowserID = content.wrappedJSObject.BrowserID;
BrowserID.internal.watch(function(aParams) {
log("sending watch method message:", aParams.method);
identityCall(aParams);
if (aParams.method === "ready") {
log("watch finished.");
closeIdentityDialog();
}
},
JSON.stringify({loggedInUser: options.loggedInUser, origin: options.origin}),
JSON.stringify(options),
function(...things) {
log("internal: ", things);
}
@ -103,8 +99,7 @@ function doInternalRequest() {
options.origin,
function(assertion) {
if (assertion) {
log("request -> assertion, so do login");
identityCall({method:'login',assertion:assertion});
identityCall({method: 'login', assertion: assertion});
}
closeIdentityDialog();
},
@ -116,7 +111,6 @@ function doInternalLogout(aOptions) {
log("doInternalLogout:", (options && isLoaded));
if (options && isLoaded) {
let BrowserID = content.wrappedJSObject.BrowserID;
log("logging you out of ", options.origin);
BrowserID.internal.logout(options.origin, function() {
identityCall({method:'logout'});
closeIdentityDialog();
@ -134,7 +128,7 @@ addEventListener("DOMContentLoaded", function(e) {
// listen for request
addMessageListener(kIdentityDelegateRequest, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateRequest, "\n\n\n");
log("injected identity.js received", kIdentityDelegateRequest, "\n\n\n");
options = aMessage.json;
showUI = true;
func = doInternalRequest;
@ -143,7 +137,7 @@ addMessageListener(kIdentityDelegateRequest, function(aMessage) {
// listen for watch
addMessageListener(kIdentityDelegateWatch, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateWatch, "\n\n\n");
log("injected identity.js received", kIdentityDelegateWatch, "\n\n\n");
options = aMessage.json;
showUI = false;
func = doInternalWatch;
@ -152,7 +146,7 @@ addMessageListener(kIdentityDelegateWatch, function(aMessage) {
// listen for logout
addMessageListener(kIdentityDelegateLogout, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateLogout, "\n\n\n");
log("injected identity.js received", kIdentityDelegateLogout, "\n\n\n");
options = aMessage.json;
showUI = false;
func = doInternalLogout;

View File

@ -76,6 +76,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
"resource://gre/modules/identity/MinimalIdentity.jsm");
@ -101,18 +102,10 @@ const kIdentityDelegateReady = "identity-delegate-ready";
const kIdentityControllerDoMethod = "identity-controller-doMethod";
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
function log(...aMessageArgs) {
Logger.log.apply(Logger, ["SignInToWebsiteController"].concat(aMessageArgs));
}
function getRandomId() {
return uuidgen.generateUUID().toString();
}
/*
* GaiaInterface encapsulates the our gaia functions. There are only two:
*
@ -207,8 +200,8 @@ let Pipe = {
let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
let mm = frameLoader.messageManager;
try {
log("about to load frame script");
mm.loadFrameScript(kIdentityShimFile, true);
log("Loaded shim " + kIdentityShimFile + "\n");
} catch (e) {
log("Error loading ", kIdentityShimFile, " as a frame script: ", e);
}
@ -230,7 +223,7 @@ let Pipe = {
showUI: aGaiaOptions.showUI || false,
id: id
};
log('tell gaia to close the dialog');
log('telling gaia to close the dialog');
// tell gaia to close the dialog
GaiaInterface.sendChromeEvent(detail);
});
@ -305,7 +298,7 @@ this.SignInToWebsiteController = {
if (typeof message === 'string') {
message = JSON.parse(message);
}
log("doMethod:", message.method);
switch(message.method) {
case "ready":
IdentityService.doReady(aRpId);
@ -326,39 +319,38 @@ this.SignInToWebsiteController = {
};
},
doWatch: function SignInToWebsiteController_doWatch(aOptions) {
doWatch: function SignInToWebsiteController_doWatch(aRpOptions) {
// dom prevents watch from being called twice
log("doWatch:", aOptions);
var gaiaOptions = {
message: kIdentityDelegateWatch,
showUI: false
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
},
/**
* The website is requesting login so the user must choose an identity to use.
*/
doRequest: function SignInToWebsiteController_doRequest(aOptions) {
log("doRequest", aOptions);
doRequest: function SignInToWebsiteController_doRequest(aRpOptions) {
log("doRequest", aRpOptions);
// tell gaia to open the identity popup
var gaiaOptions = {
message: kIdentityDelegateRequest,
showUI: true
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
},
/*
*
*/
doLogout: function SignInToWebsiteController_doLogout(aOptions) {
log("doLogout", aOptions);
doLogout: function SignInToWebsiteController_doLogout(aRpOptions) {
log("doLogout", aRpOptions);
var gaiaOptions = {
message: kIdentityDelegateLogout,
showUI: false
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
}
};

View File

@ -47,11 +47,20 @@ function uuid() {
// create a mock "doc" object, which the Identity Service
// uses as a pointer back into the doc object
function mockDoc(aIdentity, aOrigin, aDoFunc) {
function mockDoc(aParams, aDoFunc) {
let mockedDoc = {};
mockedDoc.id = uuid();
mockedDoc.loggedInUser = aIdentity;
mockedDoc.origin = aOrigin;
// Properties of aParams may include loggedInUser
Object.keys(aParams).forEach(function(param) {
mockedDoc[param] = aParams[param];
});
// the origin is set inside nsDOMIdentity by looking at the
// document.nodePrincipal.origin. Here we, we must satisfy
// ourselves with pretending.
mockedDoc.origin = "https://jedp.gov";
mockedDoc['do'] = aDoFunc;
mockedDoc.doReady = partial(aDoFunc, 'ready');
mockedDoc.doLogin = partial(aDoFunc, 'login');
@ -67,7 +76,12 @@ function mockDoc(aIdentity, aOrigin, aDoFunc) {
// messages up to gaia (either the trusty ui or the hidden iframe),
// and convey messages back down from gaia to the controller through
// the message callback.
function mockPipe() {
// The mock receiving pipe simulates gaia which, after receiving messages
// through the pipe, will call back with instructions to invoke
// certain methods. It mocks what comes back from the other end of
// the pipe.
function mockReceivingPipe() {
let MockedPipe = {
communicate: function(aRpOptions, aGaiaOptions, aMessageCallback) {
switch (aGaiaOptions.message) {
@ -89,6 +103,17 @@ function mockPipe() {
return MockedPipe;
}
// The mock sending pipe lets us test what's actually getting put in the
// pipe.
function mockSendingPipe(aMessageCallback) {
let MockedPipe = {
communicate: function(aRpOptions, aGaiaOptions, aDummyCallback) {
aMessageCallback(aRpOptions, aGaiaOptions);
}
};
return MockedPipe;
}
// mimicking callback funtionality for ease of testing
// this observer auto-removes itself after the observe function
// is called, so this is meant to observe only ONE event.

View File

@ -24,9 +24,69 @@ function test_overall() {
run_next_test();
}
function objectContains(object, subset) {
let objectKeys = Object.keys(object);
let subsetKeys = Object.keys(subset);
// can't have fewer keys than the subset
if (objectKeys.length < subsetKeys.length) {
return false;
}
let key;
let success = true;
if (subsetKeys.length > 0) {
for (let i=0; i<subsetKeys.length; i++) {
key = subsetKeys[i];
// key exists in the source object
if (typeof object[key] === 'undefined') {
success = false;
break;
}
// recursively check object values
else if (typeof subset[key] === 'object') {
if (typeof object[key] !== 'object') {
success = false;
break;
}
if (! objectContains(object[key], subset[key])) {
success = false;
break;
}
}
else if (object[key] !== subset[key]) {
success = false;
break;
}
}
}
return success;
}
function test_object_contains() {
do_test_pending();
let someObj = {
pies: 42,
green: "spam",
flan: {yes: "please"}
};
let otherObj = {
pies: 42,
flan: {yes: "please"}
};
do_check_true(objectContains(someObj, otherObj));
do_test_finished();
run_next_test();
}
function test_mock_doc() {
do_test_pending();
let mockedDoc = mockDoc(null, TEST_URL, function(action, params) {
let mockedDoc = mockDoc({loggedInUser: null}, function(action, params) {
do_check_eq(action, 'coffee');
do_test_finished();
run_next_test();
@ -43,15 +103,14 @@ function test_watch() {
setup_test_identity("pie@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, function(action, params) {
let mockedDoc = mockDoc({loggedInUser: null}, function(action, params) {
do_check_eq(action, 'ready');
controller.uninit();
do_test_finished();
run_next_test();
});
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
});
}
@ -62,7 +121,7 @@ function test_request_login() {
setup_test_identity("flan@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -76,7 +135,7 @@ function test_request_login() {
}
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.request(mockedDoc.id, {});
});
@ -88,7 +147,7 @@ function test_request_logout() {
setup_test_identity("flan@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -102,7 +161,7 @@ function test_request_logout() {
}
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.logout(mockedDoc.id, {});
});
@ -114,7 +173,7 @@ function test_request_login_logout() {
setup_test_identity("unagi@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -130,29 +189,68 @@ function test_request_login_logout() {
do_test_finished();
run_next_test();
}
/*
,function(action, params) {
do_check_eq(action, 'ready');
do_test_finished();
run_next_test();
}
*/
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.request(mockedDoc.id, {});
MinimalIDService.RP.logout(mockedDoc.id, {});
});
}
function test_options_pass_through() {
do_test_pending();
// An meaningless structure for testing that RP messages preserve
// objects and their parameters as they are passed back and forth.
let randomMixedParams = {
loggedInUser: "juanita@mozilla.com",
pie: 42,
someThing: {
name: "Pertelote",
legs: 4,
nested: {bee: "Eric", remaining: "1/2"}
}
};
let mockedDoc = mockDoc(randomMixedParams, function(action, params) {});
function pipeOtherEnd(rpOptions, gaiaOptions) {
// Ensure that every time we receive a message, our mixed
// random params are contained in that message
do_check_true(objectContains(rpOptions, randomMixedParams));
switch (gaiaOptions.message) {
case "identity-delegate-watch":
MinimalIDService.RP.request(mockedDoc.id, {});
break;
case "identity-delegate-request":
MinimalIDService.RP.logout(mockedDoc.id, {});
break;
case "identity-delegate-logout":
do_test_finished();
run_next_test();
break;
}
}
let controller = SignInToWebsiteController;
controller.init({pipe: mockSendingPipe(pipeOtherEnd)});
MinimalIDService.RP.watch(mockedDoc, {});
}
let TESTS = [
test_overall,
test_mock_doc,
test_object_contains,
test_watch,
test_request_login,
test_request_logout,
test_request_login_logout
test_request_login_logout,
test_options_pass_through
];
TESTS.forEach(add_test);

View File

@ -100,7 +100,7 @@
<command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true" hidden="true"/>
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" hidden="true"/>
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
<command id="Tools:Sanitize"
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
<command id="Tools:PrivateBrowsing"

View File

@ -925,7 +925,11 @@ var SocialSidebar = {
setSidebarVisibilityState: function(aEnabled) {
let sbrowser = document.getElementById("social-sidebar-browser");
sbrowser.docShell.isActive = aEnabled;
// it's possible we'll be called twice with aEnabled=false so let's
// just assume we may often be called with the same state.
if (aEnabled == sbrowser.docShellIsActive)
return;
sbrowser.docShellIsActive = aEnabled;
let evt = sbrowser.contentDocument.createEvent("CustomEvent");
evt.initCustomEvent(aEnabled ? "socialFrameShow" : "socialFrameHide", true, true, {});
sbrowser.contentDocument.documentElement.dispatchEvent(evt);
@ -987,27 +991,8 @@ var SocialSidebar = {
if (!sbrowser.hasAttribute("origin"))
return;
// Bug 803255 - If we don't remove the sidebar browser from the DOM,
// the previous document leaks because it's only released when the
// sidebar is made visible again.
let container = sbrowser.parentNode;
container.removeChild(sbrowser);
sbrowser.removeAttribute("origin");
sbrowser.removeAttribute("src");
function resetDocShell(docshellSupports) {
let docshell = docshellSupports.QueryInterface(Ci.nsIDocShell);
if (docshell.chromeEventHandler != sbrowser)
return;
SocialSidebar.configureSidebarDocShell(docshell);
Services.obs.removeObserver(resetDocShell, "webnavigation-create");
}
Services.obs.addObserver(resetDocShell, "webnavigation-create", false);
container.appendChild(sbrowser);
sbrowser.setAttribute("src", "about:blank");
SocialFlyout.unload();
},

View File

@ -1471,10 +1471,12 @@ var gBrowserInit = {
}
// Enable Error Console?
let consoleEnabled = gPrefService.getBoolPref("devtools.errorconsole.enabled") ||
// Temporarily enabled. See bug 798925.
let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled") ||
gPrefService.getBoolPref("devtools.chrome.enabled");
if (consoleEnabled) {
let cmd = document.getElementById("Tools:ErrorConsole");
cmd.removeAttribute("disabled");
cmd.removeAttribute("hidden");
}

View File

@ -1060,7 +1060,7 @@
contentcontextmenu="contentAreaContextMenu"
autocompletepopup="PopupAutoComplete"
onclick="contentAreaClick(event, false);"/>
<chatbar id="pinnedchats" layer="true" mousethrough="always"/>
<chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
<statuspanel id="statusbar-display" inactive="true"/>
</vbox>
<splitter id="devtools-side-splitter" hidden="true"/>

View File

@ -24,8 +24,16 @@
<xul:image class="downloadTypeIcon blockedIcon"/>
<xul:vbox pack="center"
flex="1">
<!-- We're letting localizers put a min-width in here primarily
because of the downloads summary at the bottom of the list of
download items. An element in the summary has the same min-width
on a description, and we don't want the panel to change size if the
summary isn't being displayed, so we ensure that items share the
same minimum width.
-->
<xul:description class="downloadTarget"
crop="center"
style="min-width: &downloadsSummary.minWidth;"
xbl:inherits="value=target,tooltiptext=target"/>
<xul:progressmeter anonid="progressmeter"
class="downloadProgress"

View File

@ -89,3 +89,8 @@ richlistitem[type="download"]:not([selected]) button {
{
visibility: hidden;
}
#downloadsSummary:not([inprogress="true"]) #downloadsSummaryProgress,
#downloadsSummary:not([inprogress="true"]) #downloadsSummaryDetails {
display: none;
}

View File

@ -540,11 +540,10 @@ const DownloadsView = {
DownloadsPanel.panel.removeAttribute("hasdownloads");
}
let s = DownloadsCommon.strings;
this.downloadsHistory.label = (hiddenCount > 0)
? s.showMoreDownloads(hiddenCount)
: s.showAllDownloads;
this.downloadsHistory.accessKey = s.showDownloadsAccessKey;
// If we've got some hidden downloads, we should show the summary just
// below the list.
this.downloadsHistory.collapsed = hiddenCount > 0;
DownloadsSummary.visible = this.downloadsHistory.collapsed;
},
/**
@ -1409,3 +1408,155 @@ DownloadsViewItemController.prototype = {
protocolSvc.loadUrl(makeFileURI(aFile));
}
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadsSummary
/**
* Manages the summary at the bottom of the downloads panel list if the number
* of items in the list exceeds the panels limit.
*/
const DownloadsSummary = {
/**
* Sets the collapsed state of the summary, and automatically subscribes or
* unsubscribes from the DownloadsCommon DownloadsSummaryData singleton.
*
* @param aVisible
* True if the summary should be shown.
*/
set visible(aVisible)
{
if (aVisible == this._visible || !this._summaryNode) {
return;
}
if (aVisible) {
DownloadsCommon.getSummary(DownloadsView.kItemCountLimit)
.addView(this);
} else {
DownloadsCommon.getSummary(DownloadsView.kItemCountLimit)
.removeView(this);
}
this._summaryNode.collapsed = !aVisible;
return this._visible = aVisible;
},
_visible: false,
/**
* Sets whether or not we show the progress bar.
*
* @param aShowingProgress
* True if we should show the progress bar.
*/
set showingProgress(aShowingProgress)
{
if (aShowingProgress) {
this._summaryNode.setAttribute("inprogress", "true");
} else {
this._summaryNode.removeAttribute("inprogress");
}
},
/**
* Sets the amount of progress that is visible in the progress bar.
*
* @param aValue
* A value between 0 and 100 to represent the progress of the
* summarized downloads.
*/
set percentComplete(aValue)
{
if (this._progressNode) {
this._progressNode.setAttribute("value", aValue);
}
return aValue;
},
/**
* Sets the description for the download summary.
*
* @param aValue
* A string representing the description of the summarized
* downloads.
*/
set description(aValue)
{
if (this._descriptionNode) {
this._descriptionNode.setAttribute("value", aValue);
this._descriptionNode.setAttribute("tooltiptext", aValue);
}
return aValue;
},
/**
* Sets the details for the download summary, such as the time remaining,
* the amount of bytes transferred, etc.
*
* @param aValue
* A string representing the details of the summarized
* downloads.
*/
set details(aValue)
{
if (this._detailsNode) {
this._detailsNode.setAttribute("value", aValue);
this._detailsNode.setAttribute("tooltiptext", aValue);
}
return aValue;
},
/**
* Element corresponding to the root of the downloads summary.
*/
get _summaryNode()
{
let node = document.getElementById("downloadsSummary");
if (!node) {
return null;
}
delete this._summaryNode;
return this._summaryNode = node;
},
/**
* Element corresponding to the progress bar in the downloads summary.
*/
get _progressNode()
{
let node = document.getElementById("downloadsSummaryProgress");
if (!node) {
return null;
}
delete this._progressNode;
return this._progressNode = node;
},
/**
* Element corresponding to the main description of the downloads
* summary.
*/
get _descriptionNode()
{
let node = document.getElementById("downloadsSummaryDescription");
if (!node) {
return null;
}
delete this._descriptionNode;
return this._descriptionNode = node;
},
/**
* Element corresponding to the secondary description of the downloads
* summary.
*/
get _detailsNode()
{
let node = document.getElementById("downloadsSummaryDetails");
if (!node) {
return null;
}
delete this._detailsNode;
return this._detailsNode = node;
}
}

View File

@ -105,8 +105,32 @@
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
<hbox id="downloadsSummary"
collapsed="true"
align="center"
orient="horizontal"
onclick="DownloadsPanel.showDownloadsHistory();">
<image class="downloadTypeIcon" />
<vbox>
<description id="downloadsSummaryDescription"
class="downloadTarget"
style="min-width: &downloadsSummary.minWidth;"/>
<progressmeter id="downloadsSummaryProgress"
class="downloadProgress"
min="0"
max="100"
mode="normal" />
<description id="downloadsSummaryDetails"
class="downloadDetails"
style="width: &downloadDetails.width;"
crop="end"/>
</vbox>
</hbox>
<button id="downloadsHistory"
class="plain"
label="&downloadsHistory.label;"
accesskey="&downloadsHistory.accesskey;"
oncommand="DownloadsPanel.showDownloadsHistory();"/>
</panel>
</popupset>

View File

@ -54,6 +54,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
"resource://gre/modules/DownloadUtils.jsm");
const nsIDM = Ci.nsIDownloadManager;
@ -72,7 +74,7 @@ const kDownloadsStringsRequiringFormatting = {
};
const kDownloadsStringsRequiringPluralForm = {
showMoreDownloads: true
otherDownloads: true
};
XPCOMUtils.defineLazyGetter(this, "DownloadsLocalFileCtor", function () {
@ -184,7 +186,145 @@ this.DownloadsCommon = {
* This does not need to be a lazy getter, since no initialization is required
* at present.
*/
get indicatorData() DownloadsIndicatorData
get indicatorData() DownloadsIndicatorData,
/**
* Returns a reference to the DownloadsSummaryData singleton - creating one
* in the process if one hasn't been instantiated yet.
*
* @param aNumToExclude
* The number of items on the top of the downloads list to exclude
* from the summary.
*/
_summary: null,
getSummary: function DC_getSummary(aNumToExclude)
{
if (this._summary) {
return this._summary;
}
return this._summary = new DownloadsSummaryData(aNumToExclude);
},
/**
* Given an iterable collection of nsIDownload's, generates and returns
* statistics about that collection.
*
* @param aDownloads An iterable collection of nsIDownloads.
*
* @return Object whose properties are the generated statistics. Currently,
* we return the following properties:
*
* numActive : The total number of downloads.
* numPaused : The total number of paused downloads.
* numScanning : The total number of downloads being scanned.
* numDownloading : The total number of downloads being downloaded.
* totalSize : The total size of all downloads once completed.
* totalTransferred: The total amount of transferred data for these
* downloads.
* slowestSpeed : The slowest download rate.
* rawTimeLeft : The estimated time left for the downloads to
* complete.
* percentComplete : The percentage of bytes successfully downloaded.
*/
summarizeDownloads: function DC_summarizeDownloads(aDownloads)
{
let summary = {
numActive: 0,
numPaused: 0,
numScanning: 0,
numDownloading: 0,
totalSize: 0,
totalTransferred: 0,
// slowestSpeed is Infinity so that we can use Math.min to
// find the slowest speed. We'll set this to 0 afterwards if
// it's still at Infinity by the time we're done iterating all
// downloads.
slowestSpeed: Infinity,
rawTimeLeft: -1,
percentComplete: -1
}
// If no download has been loaded, don't use the methods of the Download
// Manager service, so that it is not initialized unnecessarily.
for (let download of aDownloads) {
summary.numActive++;
switch (download.state) {
case nsIDM.DOWNLOAD_PAUSED:
summary.numPaused++;
break;
case nsIDM.DOWNLOAD_SCANNING:
summary.numScanning++;
break;
case nsIDM.DOWNLOAD_DOWNLOADING:
summary.numDownloading++;
if (download.size > 0 && download.speed > 0) {
let sizeLeft = download.size - download.amountTransferred;
summary.rawTimeLeft = Math.max(summary.rawTimeLeft,
sizeLeft / download.speed);
summary.slowestSpeed = Math.min(summary.slowestSpeed,
download.speed);
}
break;
}
// Only add to total values if we actually know the download size.
if (download.size > 0 &&
download.state != nsIDM.DOWNLOAD_CANCELED &&
download.state != nsIDM.DOWNLOAD_FAILED) {
summary.totalSize += download.size;
summary.totalTransferred += download.amountTransferred;
}
}
if (summary.numActive != 0 && summary.totalSize != 0 &&
summary.numActive != summary.numScanning) {
summary.percentComplete = (summary.totalTransferred /
summary.totalSize) * 100;
}
if (summary.slowestSpeed == Infinity) {
summary.slowestSpeed = 0;
}
return summary;
},
/**
* If necessary, smooths the estimated number of seconds remaining for one
* or more downloads to complete.
*
* @param aSeconds
* Current raw estimate on number of seconds left for one or more
* downloads. This is a floating point value to help get sub-second
* accuracy for current and future estimates.
*/
smoothSeconds: function DC_smoothSeconds(aSeconds, aLastSeconds)
{
// We apply an algorithm similar to the DownloadUtils.getTimeLeft function,
// though tailored to a single time estimation for all downloads. We never
// apply sommothing if the new value is less than half the previous value.
let shouldApplySmoothing = aLastSeconds >= 0 &&
aSeconds > aLastSeconds / 2;
if (shouldApplySmoothing) {
// Apply hysteresis to favor downward over upward swings. Trust only 30%
// of the new value if lower, and 10% if higher (exponential smoothing).
let (diff = aSeconds - aLastSeconds) {
aSeconds = aLastSeconds + (diff < 0 ? .3 : .1) * diff;
}
// If the new time is similar, reuse something close to the last time
// left, but subtract a little to provide forward progress.
let diff = aSeconds - aLastSeconds;
let diffPercent = diff / aLastSeconds * 100;
if (Math.abs(diff) < 5 || Math.abs(diffPercent) < 5) {
aSeconds = aLastSeconds - (diff < 0 ? .4 : .2);
}
}
// In the last few seconds of downloading, we are always subtracting and
// never adding to the time left. Ensure that we never fall below one
// second left until all downloads are actually finished.
return aLastSeconds = Math.max(aSeconds, 1);
}
};
/**
@ -613,6 +753,7 @@ const DownloadsData = {
dataItem.startTime = Math.round(aDownload.startTime / 1000);
dataItem.currBytes = aDownload.amountTransferred;
dataItem.maxBytes = aDownload.size;
dataItem.download = aDownload;
this._views.forEach(
function (view) view.getViewItem(dataItem).onStateChange()
@ -919,19 +1060,13 @@ DownloadsDataItem.prototype = {
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadsIndicatorData
//// DownloadsViewPrototype
/**
* This object registers itself with DownloadsData as a view, and transforms the
* notifications it receives into overall status data, that is then broadcast to
* the registered download status indicators.
*
* Note that using this object does not automatically start the Download Manager
* service. Consumers will see an empty list of downloads until the service is
* actually started. This is useful to display a neutral progress indicator in
* the main browser window until the autostart timeout elapses.
* A prototype for an object that registers itself with DownloadsData as soon
* as a view is registered with it.
*/
const DownloadsIndicatorData = {
const DownloadsViewPrototype = {
//////////////////////////////////////////////////////////////////////////////
//// Registration of views
@ -946,10 +1081,10 @@ const DownloadsIndicatorData = {
* The specified object is initialized with the currently available status.
*
* @param aView
* DownloadsIndicatorView object to be added. This reference must be
* View object to be added. This reference must be
* passed to removeView before termination.
*/
addView: function DID_addView(aView)
addView: function DVP_addView(aView)
{
// Start receiving events when the first of our views is registered.
if (this._views.length == 0) {
@ -964,11 +1099,12 @@ const DownloadsIndicatorData = {
* Updates the properties of an object previously added using addView.
*
* @param aView
* DownloadsIndicatorView object to be updated.
* View object to be updated.
*/
refreshView: function DID_refreshView(aView)
refreshView: function DVP_refreshView(aView)
{
// Update immediately even if we are still loading data asynchronously.
// Subclasses must provide these two functions!
this._refreshProperties();
this._updateView(aView);
},
@ -977,9 +1113,9 @@ const DownloadsIndicatorData = {
* Removes an object previously added using addView.
*
* @param aView
* DownloadsIndicatorView object to be removed.
* View object to be removed.
*/
removeView: function DID_removeView(aView)
removeView: function DVP_removeView(aView)
{
let index = this._views.indexOf(aView);
if (index != -1) {
@ -989,7 +1125,6 @@ const DownloadsIndicatorData = {
// Stop receiving events when the last of our views is unregistered.
if (this._views.length == 0) {
DownloadsCommon.data.removeView(this);
this._itemCount = 0;
}
},
@ -1004,7 +1139,7 @@ const DownloadsIndicatorData = {
/**
* Called before multiple downloads are about to be loaded.
*/
onDataLoadStarting: function DID_onDataLoadStarting()
onDataLoadStarting: function DVP_onDataLoadStarting()
{
this._loading = true;
},
@ -1012,9 +1147,134 @@ const DownloadsIndicatorData = {
/**
* Called after data loading finished.
*/
onDataLoadCompleted: function DID_onDataLoadCompleted()
onDataLoadCompleted: function DVP_onDataLoadCompleted()
{
this._loading = false;
},
/**
* Called when the downloads database becomes unavailable (for example, we
* entered Private Browsing Mode and the database backend changed).
* References to existing data should be discarded.
*
* @note Subclasses should override this.
*/
onDataInvalidated: function DVP_onDataInvalidated()
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Called when a new download data item is available, either during the
* asynchronous data load or when a new download is started.
*
* @param aDataItem
* DownloadsDataItem object that was just added.
* @param aNewest
* When true, indicates that this item is the most recent and should be
* added in the topmost position. This happens when a new download is
* started. When false, indicates that the item is the least recent
* with regard to the items that have been already added. The latter
* generally happens during the asynchronous data load.
*
* @note Subclasses should override this.
*/
onDataItemAdded: function DVP_onDataItemAdded(aDataItem, aNewest)
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Called when a data item is removed, ensures that the widget associated with
* the view item is removed from the user interface.
*
* @param aDataItem
* DownloadsDataItem object that is being removed.
*
* @note Subclasses should override this.
*/
onDataItemRemoved: function DVP_onDataItemRemoved(aDataItem)
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Returns the view item associated with the provided data item for this view.
*
* @param aDataItem
* DownloadsDataItem object for which the view item is requested.
*
* @return Object that can be used to notify item status events.
*
* @note Subclasses should override this.
*/
getViewItem: function DID_getViewItem(aDataItem)
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Private function used to refresh the internal properties being sent to
* each registered view.
*
* @note Subclasses should override this.
*/
_refreshProperties: function DID_refreshProperties()
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Private function used to refresh an individual view.
*
* @note Subclasses should override this.
*/
_updateView: function DID_updateView()
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
};
////////////////////////////////////////////////////////////////////////////////
//// DownloadsIndicatorData
/**
* This object registers itself with DownloadsData as a view, and transforms the
* notifications it receives into overall status data, that is then broadcast to
* the registered download status indicators.
*
* Note that using this object does not automatically start the Download Manager
* service. Consumers will see an empty list of downloads until the service is
* actually started. This is useful to display a neutral progress indicator in
* the main browser window until the autostart timeout elapses.
*/
const DownloadsIndicatorData = {
__proto__: DownloadsViewPrototype,
/**
* Removes an object previously added using addView.
*
* @param aView
* DownloadsIndicatorView object to be removed.
*/
removeView: function DID_removeView(aView)
{
DownloadsViewPrototype.removeView.call(this, aView);
if (this._views.length == 0) {
this._itemCount = 0;
}
},
//////////////////////////////////////////////////////////////////////////////
//// Callback functions from DownloadsData
/**
* Called after data loading finished.
*/
onDataLoadCompleted: function DID_onDataLoadCompleted()
{
DownloadsViewPrototype.onDataLoadCompleted.call(this);
this._updateViews();
},
@ -1179,40 +1439,21 @@ const DownloadsIndicatorData = {
_lastTimeLeft: -1,
/**
* Update the estimated time until all in-progress downloads will finish.
*
* @param aSeconds
* Current raw estimate on number of seconds left for all downloads.
* This is a floating point value to help get sub-second accuracy for
* current and future estimates.
* A generator function for the downloads that this summary is currently
* interested in. This generator is passed off to summarizeDownloads in order
* to generate statistics about the downloads we care about - in this case,
* it's all active downloads.
*/
_updateTimeLeft: function DID_updateTimeLeft(aSeconds)
_activeDownloads: function DID_activeDownloads()
{
// We apply an algorithm similar to the DownloadUtils.getTimeLeft function,
// though tailored to a single time estimation for all downloads. We never
// apply sommothing if the new value is less than half the previous value.
let shouldApplySmoothing = this._lastTimeLeft >= 0 &&
aSeconds > this._lastTimeLeft / 2;
if (shouldApplySmoothing) {
// Apply hysteresis to favor downward over upward swings. Trust only 30%
// of the new value if lower, and 10% if higher (exponential smoothing).
let (diff = aSeconds - this._lastTimeLeft) {
aSeconds = this._lastTimeLeft + (diff < 0 ? .3 : .1) * diff;
}
// If the new time is similar, reuse something close to the last time
// left, but subtract a little to provide forward progress.
let diff = aSeconds - this._lastTimeLeft;
let diffPercent = diff / this._lastTimeLeft * 100;
if (Math.abs(diff) < 5 || Math.abs(diffPercent) < 5) {
aSeconds = this._lastTimeLeft - (diff < 0 ? .4 : .2);
// If no download has been loaded, don't use the methods of the Download
// Manager service, so that it is not initialized unnecessarily.
if (this._itemCount > 0) {
let downloads = Services.downloads.activeDownloads;
while (downloads.hasMoreElements()) {
yield downloads.getNext().QueryInterface(Ci.nsIDownload);
}
}
// In the last few seconds of downloading, we are always subtracting and
// never adding to the time left. Ensure that we never fall below one
// second left until all downloads are actually finished.
this._lastTimeLeft = Math.max(aSeconds, 1);
},
/**
@ -1220,69 +1461,236 @@ const DownloadsIndicatorData = {
*/
_refreshProperties: function DID_refreshProperties()
{
let numActive = 0;
let numPaused = 0;
let numScanning = 0;
let totalSize = 0;
let totalTransferred = 0;
let rawTimeLeft = -1;
// If no download has been loaded, don't use the methods of the Download
// Manager service, so that it is not initialized unnecessarily.
if (this._itemCount > 0) {
let downloads = Services.downloads.activeDownloads;
while (downloads.hasMoreElements()) {
let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
numActive++;
switch (download.state) {
case nsIDM.DOWNLOAD_PAUSED:
numPaused++;
break;
case nsIDM.DOWNLOAD_SCANNING:
numScanning++;
break;
case nsIDM.DOWNLOAD_DOWNLOADING:
if (download.size > 0 && download.speed > 0) {
let sizeLeft = download.size - download.amountTransferred;
rawTimeLeft = Math.max(rawTimeLeft, sizeLeft / download.speed);
}
break;
}
// Only add to total values if we actually know the download size.
if (download.size > 0) {
totalSize += download.size;
totalTransferred += download.amountTransferred;
}
}
}
let summary =
DownloadsCommon.summarizeDownloads(this._activeDownloads());
// Determine if the indicator should be shown or get attention.
this._hasDownloads = (this._itemCount > 0);
if (numActive == 0 || totalSize == 0 || numActive == numScanning) {
// Don't display the current progress.
this._percentComplete = -1;
} else {
// Display the current progress.
this._percentComplete = (totalTransferred / totalSize) * 100;
}
// If all downloads are paused, show the progress indicator as paused.
this._paused = numActive > 0 && numActive == numPaused;
this._paused = summary.numActive > 0 &&
summary.numActive == summary.numPaused;
this._percentComplete = summary.percentComplete;
// Display the estimated time left, if present.
if (rawTimeLeft == -1) {
if (summary.rawTimeLeft == -1) {
// There are no downloads with a known time left.
this._lastRawTimeLeft = -1;
this._lastTimeLeft = -1;
this._counter = "";
} else {
// Compute the new time left only if state actually changed.
if (this._lastRawTimeLeft != rawTimeLeft) {
this._lastRawTimeLeft = rawTimeLeft;
this._updateTimeLeft(rawTimeLeft);
if (this._lastRawTimeLeft != summary.rawTimeLeft) {
this._lastRawTimeLeft = summary.rawTimeLeft;
this._lastTimeLeft = DownloadsCommon.smoothSeconds(summary.rawTimeLeft,
this._lastTimeLeft);
}
this._counter = DownloadsCommon.formatTimeLeft(this._lastTimeLeft);
}
}
}
////////////////////////////////////////////////////////////////////////////////
//// DownloadsSummaryData
/**
* DownloadsSummaryData is a view for DownloadsData that produces a summary
* of all downloads after a certain exclusion point aNumToExclude. For example,
* if there were 5 downloads in progress, and a DownloadsSummaryData was
* constructed with aNumToExclude equal to 3, then that DownloadsSummaryData
* would produce a summary of the last 2 downloads.
*
* @param aNumToExclude
* The number of items to exclude from the summary, starting from the
* top of the list.
*/
function DownloadsSummaryData(aNumToExclude) {
this._numToExclude = aNumToExclude;
// Since we can have multiple instances of DownloadsSummaryData, we
// override these values from the prototype so that each instance can be
// completely separated from one another.
this._views = [];
this._loading = false;
this._dataItems = [];
// Floating point value indicating the last number of seconds estimated until
// the longest download will finish. We need to store this value so that we
// don't continuously apply smoothing if the actual download state has not
// changed. This is set to -1 if the previous value is unknown.
this._lastRawTimeLeft = -1;
// Last number of seconds estimated until all in-progress downloads with a
// known size and speed will finish. This value is stored to allow smoothing
// in case of small variations. This is set to -1 if the previous value is
// unknown.
this._lastTimeLeft = -1;
// The following properties are updated by _refreshProperties and are then
// propagated to the views.
this._showingProgress = false;
this._details = "";
this._description = "";
this._numActive = 0;
this._percentComplete = -1;
}
DownloadsSummaryData.prototype = {
__proto__: DownloadsViewPrototype,
/**
* Removes an object previously added using addView.
*
* @param aView
* DownloadsSummary view to be removed.
*/
removeView: function DSD_removeView(aView)
{
DownloadsViewPrototype.removeView.call(this, aView);
if (this._views.length == 0) {
// Clear out our collection of DownloadsDataItems. If we ever have
// another view registered with us, this will get re-populated.
this._dataItems = [];
}
},
//////////////////////////////////////////////////////////////////////////////
//// Callback functions from DownloadsData - see the documentation in
//// DownloadsViewPrototype for more information on what these functions
//// are used for.
onDataLoadCompleted: function DSD_onDataLoadCompleted()
{
DownloadsViewPrototype.onDataLoadCompleted.call(this);
this._updateViews();
},
onDataInvalidated: function DSD_onDataInvalidated()
{
this._dataItems = [];
},
onDataItemAdded: function DSD_onDataItemAdded(aDataItem, aNewest)
{
if (aNewest) {
this._dataItems.unshift(aDataItem);
} else {
this._dataItems.push(aDataItem);
}
this._updateViews();
},
onDataItemRemoved: function DSD_onDataItemRemoved(aDataItem)
{
let itemIndex = this._dataItems.indexOf(aDataItem);
this._dataItems.splice(itemIndex, 1);
this._updateViews();
},
getViewItem: function DSD_getViewItem(aDataItem)
{
let self = this;
return Object.freeze({
onStateChange: function DIVI_onStateChange()
{
// Since the state of a download changed, reset the estimated time left.
self._lastRawTimeLeft = -1;
self._lastTimeLeft = -1;
self._updateViews();
},
onProgressChange: function DIVI_onProgressChange()
{
self._updateViews();
}
});
},
//////////////////////////////////////////////////////////////////////////////
//// Propagation of properties to our views
/**
* Computes aggregate values and propagates the changes to our views.
*/
_updateViews: function DSD_updateViews()
{
// Do not update the status indicators during batch loads of download items.
if (this._loading) {
return;
}
this._refreshProperties();
this._views.forEach(this._updateView, this);
},
/**
* Updates the specified view with the current aggregate values.
*
* @param aView
* DownloadsIndicatorView object to be updated.
*/
_updateView: function DSD_updateView(aView)
{
aView.showingProgress = this._showingProgress;
aView.percentComplete = this._percentComplete;
aView.description = this._description;
aView.details = this._details;
},
//////////////////////////////////////////////////////////////////////////////
//// Property updating based on current download status
/**
* A generator function for the downloads that this summary is currently
* interested in. This generator is passed off to summarizeDownloads in order
* to generate statistics about the downloads we care about - in this case,
* it's the downloads in this._dataItems after the first few to exclude,
* which was set when constructing this DownloadsSummaryData instance.
*/
_downloadsForSummary: function DSD_downloadsForSummary()
{
if (this._dataItems.length > 0) {
for (let i = this._numToExclude; i < this._dataItems.length; ++i) {
yield this._dataItems[i].download;
}
}
},
/**
* Computes aggregate values based on the current state of downloads.
*/
_refreshProperties: function DSD_refreshProperties()
{
// Pre-load summary with default values.
let summary =
DownloadsCommon.summarizeDownloads(this._downloadsForSummary());
this._description = DownloadsCommon.strings
.otherDownloads(summary.numActive);
this._percentComplete = summary.percentComplete;
// If all downloads are paused, show the progress indicator as paused.
this._showingProgress = summary.numDownloading > 0 ||
summary.numPaused > 0;
// Display the estimated time left, if present.
if (summary.rawTimeLeft == -1) {
// There are no downloads with a known time left.
this._lastRawTimeLeft = -1;
this._lastTimeLeft = -1;
this._details = "";
} else {
// Compute the new time left only if state actually changed.
if (this._lastRawTimeLeft != summary.rawTimeLeft) {
this._lastRawTimeLeft = summary.rawTimeLeft;
this._lastTimeLeft = DownloadsCommon.smoothSeconds(summary.rawTimeLeft,
this._lastTimeLeft);
}
[this._details] = DownloadUtils.getDownloadStatusNoRate(
summary.totalTransferred, summary.totalSize, summary.slowestSpeed,
this._lastTimeLeft);
}
}
}

View File

@ -35,7 +35,7 @@
!define BETA_UPDATE_CHANNEL
!endif
!define BaseURLStubPing "http://download-stats.mozilla.org/stub/v2/"
!define BaseURLStubPing "http://download-stats.mozilla.org/stub/v3/"
# NO_INSTDIR_FROM_REG is defined for pre-releases which have a PreReleaseSuffix
# (e.g. Alpha X, Beta X, etc.) to prevent finding a non-default installation

View File

@ -929,7 +929,8 @@ FunctionEnd
Function StartDownload
${NSD_KillTimer} StartDownload
InetBgDL::Get "${URLStubDownload}" "$PLUGINSDIR\download.exe" /END
InetBgDL::Get "${URLStubDownload}" "$PLUGINSDIR\download.exe" \
/RANGEREQUEST /CONNECTTIMEOUT 120 /RECEIVETIMEOUT 120 /END
StrCpy $4 ""
${NSD_CreateTimer} OnDownload ${DownloadIntervalMS}
${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"

View File

@ -25,6 +25,21 @@
-->
<!ENTITY downloadDetails.width "50ch">
<!-- LOCALIZATION NOTE (downloadsSummary.minWidth):
Minimum width for the main description of the downloads summary,
which is displayed at the bottom of the Downloads Panel if the
number of downloads exceeds the limit that the panel can display.
A good rule of thumb here is to look at the otherDownloads string
in downloads.properties, and make a reasonable estimate of its
maximum length. For English, this seems like a reasonable limit:
+999 other current downloads
that's 28 characters, so we set the minimum width to 28ch.
-->
<!ENTITY downloadsSummary.minWidth "28ch">
<!ENTITY cmd.pause.label "Pause">
<!ENTITY cmd.pause.accesskey "P">
<!ENTITY cmd.resume.label "Resume">
@ -50,3 +65,10 @@
<!ENTITY cmd.clearList.label "Clear List">
<!ENTITY cmd.clearList.accesskey "a">
<!-- LOCALIZATION NOTE (downloadsHistory.label, downloadsHistory.accesskey):
This string is shown at the bottom of the Downloads Panel when all the
downloads fit in the available space, or when there are no downloads in
the panel at all.
-->
<!ENTITY downloadsHistory.label "Show All Downloads">
<!ENTITY downloadsHistory.accesskey "S">

View File

@ -67,20 +67,13 @@ shortTimeLeftDays=%1$Sd
statusSeparator=%1$S \u2014 %2$S
statusSeparatorBeforeNumber=%1$S \u2014 %2$S
# LOCALIZATION NOTE (showMoreDownloads):
# This string is shown in the Downloads Panel when there are more active
# downloads than can fit in the available space. The phrase should be read as
# "Show N more of my recent downloads". Use a semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/Localization_and_Plurals
showMoreDownloads=Show 1 More Recent Download;Show %1$S More Recent Downloads
# LOCALIZATION NOTE (showAllDownloads):
# This string is shown in place of showMoreDownloads when all the downloads fit
# in the available space, or when there are no downloads in the panel at all.
showAllDownloads=Show All Downloads
# LOCALIZATION NOTE (showDownloadsAccessKey):
# This access key applies to both showMoreDownloads and showAllDownloads.
showDownloadsAccessKey=S
fileExecutableSecurityWarning="%S" is an executable file. Executable files may contain viruses or other malicious code that could harm your computer. Use caution when opening this file. Are you sure you want to launch "%S"?
fileExecutableSecurityWarningTitle=Open Executable File?
fileExecutableSecurityWarningDontAsk=Don't ask me this again
# LOCALIZATION NOTE (otherDownloads):
# This is displayed in an item at the bottom of the Downloads Panel when
# there are more downloads than can fit in the list in the panel. Use a
# semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/Localization_and_Plurals
otherDownloads=+%1$S other current download; +%1$S other current downloads

View File

@ -1,4 +1,4 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -24,6 +24,7 @@
cursor: pointer;
}
#downloadsSummary,
#downloadsPanel[hasdownloads] > #downloadsHistory {
border-top: 1px solid ThreeDShadow;
background-image: -moz-linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
@ -37,17 +38,36 @@
outline: 1px -moz-dialogtext dotted;
}
/*** List items ***/
/*** Downloads Summary and List items ***/
#downloadsSummary,
richlistitem[type="download"] {
height: 6em;
-moz-padding-end: 0;
color: inherit;
}
#downloadsSummary {
padding: 8px 38px 8px 12px;
cursor: pointer;
}
#downloadsSummary > .downloadTypeIcon {
height: 32px;
width: 32px;
list-style-image: url("chrome://mozapps/skin/downloads/downloadIcon.png");
}
#downloadsSummaryDescription {
color: -moz-nativehyperlinktext;
}
richlistitem[type="download"] {
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.15);
background: transparent;
padding: 8px;
-moz-padding-end: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {
@ -264,7 +284,7 @@ toolbar[iconsize="large"] #downloads-indicator[attention] > #downloads-indicator
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-color: rgb(90, 185, 255);
background-color: rgb(255, 135, 94);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
border: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);

View File

@ -31,6 +31,7 @@
border-top-right-radius: 6px;
}
#downloadsSummary,
#downloadsPanel[hasdownloads] > #downloadsHistory {
background: #e5e5e5;
border-top: 1px solid hsla(0,0%,0%,.1);
@ -53,17 +54,34 @@
border-bottom-right-radius: 6px;
}
/*** List items ***/
/*** Downloads Summary and List items ***/
#downloadsSummary,
richlistitem[type="download"] {
height: 7em;
-moz-padding-end: 0;
color: inherit;
}
#downloadsSummary {
padding: 8px 38px 8px 12px;
cursor: pointer;
}
#downloadsSummary > .downloadTypeIcon {
list-style-image: url("chrome://mozapps/skin/downloads/downloadIcon.png");
}
#downloadsSummaryDescription {
color: -moz-nativehyperlinktext;
}
richlistitem[type="download"] {
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.07);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background: transparent;
padding: 8px;
-moz-padding-end: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {

View File

@ -42,3 +42,7 @@
0 1px 1.5px rgba(0,0,0,.5);
}
}
#downloads-indicator-counter {
margin-bottom: -1px;
}

View File

@ -14,6 +14,10 @@
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
#downloadsHistory {
background: transparent;
color: -moz-nativehyperlinktext;
@ -25,23 +29,43 @@
}
@media (-moz-windows-default-theme) {
#downloadsSummary,
#downloadsPanel[hasdownloads] > #downloadsHistory {
background-color: hsla(216,45%,88%,.98);
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
}
}
/*** List items ***/
/*** Downloads Summary and List items ***/
#downloadsSummary,
richlistitem[type="download"] {
height: 7em;
-moz-padding-end: 0;
color: inherit;
}
#downloadsSummary {
padding: 8px 38px 8px 12px;
cursor: pointer;
}
#downloadsSummary > .downloadTypeIcon {
height: 24px;
width: 24px;
list-style-image: url("chrome://mozapps/skin/downloads/downloadIcon.png");
}
#downloadsSummaryDescription {
color: -moz-nativehyperlinktext;
}
richlistitem[type="download"] {
margin: 0;
border-top: 1px solid hsla(0,0%,100%,.3);
border-bottom: 1px solid hsla(220,18%,51%,.25);
background: transparent;
padding: 8px;
-moz-padding-end: 0;
color: inherit;
}
richlistitem[type="download"]:first-child {
@ -227,12 +251,12 @@ richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:ac
/*** Progress bar and text ***/
#downloads-indicator-counter {
height: 10px;
margin: 0;
height: 9px;
margin: -3px 0px 0px 0px;
color: hsl(0,0%,30%);
text-shadow: hsla(0,0%,100%,.5) 0 1px;
font-size: 10px;
line-height: 10px;
font-size: 9px;
line-height: 9px;
text-align: center;
}
@ -244,7 +268,7 @@ richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:ac
#downloads-indicator-progress {
width: 16px;
height: 6px;
height: 5px;
min-width: 0;
min-height: 0;
margin-top: 1px;
@ -257,7 +281,7 @@ richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:ac
-moz-appearance: none;
min-width: 0;
min-height: 0;
background-color: rgb(90, 185, 255);
background-color: rgb(90, 201, 66);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
border: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);

View File

@ -28,3 +28,4 @@ DEPRECATED_OPERATION(NoExposedProps)
DEPRECATED_OPERATION(MutationEvent)
DEPRECATED_OPERATION(MozSlice)
DEPRECATED_OPERATION(Components)
DEPRECATED_OPERATION(PrefixedVisibilityAPI)

View File

@ -9487,6 +9487,10 @@ nsDocument::UpdateVisibilityState()
VisibilityState oldState = mVisibilityState;
mVisibilityState = GetVisibilityState();
if (oldState != mVisibilityState) {
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
NS_LITERAL_STRING("visibilitychange"),
/* bubbles = */ true,
/* cancelable = */ false);
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
NS_LITERAL_STRING("mozvisibilitychange"),
/* bubbles = */ true,
@ -9522,6 +9526,13 @@ nsDocument::PostVisibilityUpdateEvent()
NS_IMETHODIMP
nsDocument::GetMozHidden(bool* aHidden)
{
WarnOnceAbout(ePrefixedVisibilityAPI);
return GetHidden(aHidden);
}
NS_IMETHODIMP
nsDocument::GetHidden(bool* aHidden)
{
*aHidden = mVisibilityState != eVisible;
return NS_OK;
@ -9529,6 +9540,13 @@ nsDocument::GetMozHidden(bool* aHidden)
NS_IMETHODIMP
nsDocument::GetMozVisibilityState(nsAString& aState)
{
WarnOnceAbout(ePrefixedVisibilityAPI);
return GetVisibilityState(aState);
}
NS_IMETHODIMP
nsDocument::GetVisibilityState(nsAString& aState)
{
// This needs to stay in sync with the VisibilityState enum.
static const char states[][8] = {

View File

@ -1258,7 +1258,7 @@ protected:
nsRefPtr<nsDOMNavigationTiming> mTiming;
private:
friend class nsUnblockOnloadEvent;
// This needs to stay in sync with the list in GetMozVisibilityState.
// This needs to stay in sync with the list in GetVisibilityState.
enum VisibilityState {
eHidden = 0,
eVisible,

View File

@ -2091,6 +2091,7 @@ GK_ATOM(posinset, "posinset")
GK_ATOM(presentation, "presentation")
GK_ATOM(progressbar, "progressbar")
GK_ATOM(region, "region")
GK_ATOM(rowgroup, "rowgroup")
GK_ATOM(rowheader, "rowheader")
GK_ATOM(select1, "select1")
GK_ATOM(setsize, "setsize")

View File

@ -2,4 +2,3 @@
<meta charset=utf-8>
<title>Non-UTF form target</title>
<body onload="parent.finish();">

View File

@ -1,8 +1,7 @@
<!DOCTYPE html>
<!doctype html>
<meta charset=windows-1252>
<title>Non-UTF form</title>
<body onload="document.forms[0].submit();">
<form action="file_bug708620-2.html">
<input name=foo value=bar>
</form>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=513194
@ -6,67 +6,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=513194
<head>
<meta charset="utf-8">
<title>Test for Bug 513194</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
var consoleListener = {
seenError: false,
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (this.seenError) {
ok(false, "Seen too many errors!");
}
this.seenError = true;
ok(message.message.indexOf("Unknown property") > -1,
"Wrong message");
},
finish: function() {
ok(this.seenError , "Didn't get message.");
SimpleTest.finish();
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
consoleService.reset();
consoleService.registerListener(consoleListener);
SimpleTest.waitForExplicitFinish();
document.write("<style>qux { foo: bar; }<\/style>");
function done() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleListener.finish();
consoleService.unregisterListener(consoleListener);
}
setTimeout(done, 0);
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
>Mozilla Bug 513194</a>
<script>
// The use of document.write is deliberate. We are testing for the
// HTML parser to call the CSS parser once and only once when it
// encounters a new <style> element.
SimpleTest.runTestExpectingConsoleMessages(
function () { document.write("<style>qux { foo : bar; }<\/style>") },
[{ errorMessage: /Unknown property/ }]
);
</script>
</pre>
</body>
</html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=631615
@ -6,76 +6,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=631615
<head>
<meta charset="utf-8">
<title>Test for Bug 631615</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615">Mozilla Bug 631615</a>
<pre id="monitor">
</pre>
<script type="application/javascript">
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
var messageCount = 0;
var monitor = document.getElementById("monitor");
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (message.message === "sentinel") {
is(messageCount, 0, "should have been no console messages");
removeListener();
SimpleTest.finish();
} else {
messageCount++;
var err = "" + messageCount + ": " + message.message + "\n";
monitor.appendChild(document.createTextNode(err));
}
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.unregisterListener(listener);
}
function postSentinel() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
consoleService.logStringMessage("sentinel");
}
SimpleTest.waitForExplicitFinish();
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=631615"
>Mozilla Bug 631615</a>
<pre id="monitor"></pre>
<script>
function doTest() {
var monitor = document.getElementById("monitor");
var html = document.documentElement;
var results;
var matches = html.matchesSelector || html.mozMatchesSelector;
addListener();
try {
results = "return: " +
matches.call(html, "[test!='']:sizzle") + "\n";
@ -85,11 +30,9 @@ function doTest() {
monitor.appendChild(document.createTextNode(results));
is(results.slice(0, 6), "throws", "looking for an exception");
postSentinel();
}
doTest();
SimpleTest.runTestExpectingConsoleMessages(doTest, []);
</script>
</body>
</html>

View File

@ -22,26 +22,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=690056
/** Test for Bug 690056 **/
SimpleTest.waitForExplicitFinish();
is(document.mozHidden, false, "Document should not be hidden during load");
is(document.mozVisibilityState, "visible",
is(document.hidden, false, "Document should not be hidden during load");
is(document.visibilityState, "visible",
"Document should be visible during load");
addLoadEvent(function() {
var doc = document.implementation.createDocument("", "", null);
is(doc.mozHidden, true, "Data documents should be hidden");
is(doc.mozVisibilityState, "hidden", "Data documents really should be hidden");
is(doc.hidden, true, "Data documents should be hidden");
is(doc.visibilityState, "hidden", "Data documents really should be hidden");
is(document.mozHidden, false, "Document should not be hidden onload");
is(document.mozVisibilityState, "visible",
is(document.hidden, false, "Document should not be hidden onload");
is(document.visibilityState, "visible",
"Document should be visible onload");
is($("x").contentDocument.mozHidden, false,
is($("x").contentDocument.hidden, false,
"Subframe document should not be hidden onload");
is($("x").contentDocument.mozVisibilityState, "visible",
is($("x").contentDocument.visibilityState, "visible",
"Subframe document should be visible onload");
is($("y").contentDocument.mozHidden, false,
is($("y").contentDocument.hidden, false,
"display:none subframe document should not be hidden onload");
is($("y").contentDocument.mozVisibilityState, "visible",
is($("y").contentDocument.visibilityState, "visible",
"display:none subframe document should be visible onload");
SimpleTest.finish();

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=708620
@ -6,61 +6,36 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=708620
<head>
<meta charset="utf-8">
<title>Test for Bug 708620</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body onload="start();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620">Mozilla Bug 708620</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test">
<script type="application/javascript">
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=708620"
>Mozilla Bug 708620</a>
<iframe></iframe>
<script>
/** Test for Bug 708620 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "A form was submitted in the windows-1252 encoding "+
"which cannot encode all Unicode characters, so user "+
"input may get corrupted. To avoid this problem, the "+
"page should be changed so that the form is submitted "+
"in the UTF-8 encoding either by changing the encoding "+
"of the page itself to UTF-8 or by specifying "+
"accept-charset=utf-8 on the form element.",
isWarning: true }
]);
var tests = [
"file_bug708620.html"
];
function resolveURL(relative) {
var a = document.createElement('a');
a.href = relative;
return a.href;
}
var resolvedURL = resolveURL(tests[0]);
var expectedErrors = [
'[JavaScript Warning: "A form was submitted in the windows-1252 encoding which cannot encode all Unicode characters, so user input may get corrupted. To avoid this problem, the page should be changed so that the form is submitted in the UTF-8 encoding either by changing the encoding of the page itself to UTF-8 or by specifying accept-charset=utf-8 on the form element." {file: "' + resolvedURL + '" line: 1}]'
];
function consoleError(msg, fileName) {
// Ignore messages not generated by the test
if (fileName !== resolvedURL) {
return;
}
var expected = expectedErrors.shift();
is(msg, expected, "Not the right error message");
}
SpecialPowers.addErrorConsoleListener(consoleError);
function start() {
var url = tests.shift();
document.getElementsByTagName("iframe")[0].src = url;
window.onload = function () {
document.getElementsByTagName("iframe")[0].src = "file_bug708620.html";
}
function finish() {
is(expectedErrors.length, 0, "The error supply was not exhausted");
SpecialPowers.removeErrorConsoleListener(consoleError);
SimpleTest.finish();
SimpleTest.endMonitorConsole();
}
</script>
</pre>
</body>
</html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=489671
@ -6,68 +6,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=489671
<head>
<meta charset="utf-8">
<title>Test for Bug 489671</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671">Mozilla Bug 489671</a>
<p id="display" onclick="throw 'Got click'"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 489671 **/
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
var listener = {
observe: function(message) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
is(message.QueryInterface(Ci.nsIScriptError).errorMessage,
"uncaught exception: Got click");
SimpleTest.executeSoon(nextTest);
},
QueryInterface: function(iid) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
if (iid.equals(Ci.nsIConsoleListener) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_NOINTERFACE;
}
};
function addListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.reset();
consoleService.registerListener(listener);
}
function removeListener() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var consoleService =
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.unregisterListener(listener);
}
SimpleTest.waitForExplicitFinish();
addListener();
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=489671"
>Mozilla Bug 489671</a>
<p id="display" onclick="queueNextTest(); throw 'Got click 1';"></p>
<script>
// override window.onerror so it won't see our exceptions
window.onerror = function() {}
var testNum = 0;
function nextTest() {
function doTest() {
switch(testNum++) {
case 0:
var event = document.createEvent("MouseEvents");
@ -77,22 +29,27 @@ function nextTest() {
break;
case 1:
var script = document.createElement("script");
script.textContent = "throw 'Got click'";
script.textContent = "queueNextTest(); throw 'Got click 2'";
document.body.appendChild(script);
break;
case 2:
window.setTimeout("throw 'Got click'", 0);
window.setTimeout("queueNextTest(); throw 'Got click 3'", 0);
break;
case 3:
removeListener();
SimpleTest.finish();
break;
SimpleTest.endMonitorConsole();
return;
}
}
function queueNextTest() { SimpleTest.executeSoon(doTest); }
nextTest();
SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [
{ errorMessage: "uncaught exception: Got click 1" },
{ errorMessage: "uncaught exception: Got click 2" },
{ errorMessage: "uncaught exception: Got click 3" }
]);
doTest();
</script>
</pre>
</body>
</html>

View File

@ -23,6 +23,7 @@
#include "mozilla/Mutex.h"
#include "nsTimeRanges.h"
#include "nsIDOMWakeLock.h"
#include "AudioChannelCommon.h"
// Define to output information on decoding and painting framerate
/* #define DEBUG_FRAME_RATE 1 */
@ -578,7 +579,7 @@ protected:
* Called asynchronously to release a self-reference to this element.
*/
void DoRemoveSelfReference();
/**
* Possible values of the 'preload' attribute.
*/
@ -590,7 +591,7 @@ protected:
};
/**
* The preloading action to perform. These dictate how we react to the
* The preloading action to perform. These dictate how we react to the
* preload attribute. See mPreloadAction.
*/
enum PreloadAction {
@ -617,7 +618,7 @@ protected:
/**
* Handle a change to the preload attribute. Should be called whenever the
* value (or presence) of the preload attribute changes. The change in
* value (or presence) of the preload attribute changes. The change in
* attribute value may cause a change in the mPreloadAction of this
* element. If there is a change then this method will initiate any
* behaviour that is necessary to implement the action.
@ -723,7 +724,7 @@ protected:
// No load algorithm instance is waiting for a source to be added to the
// media in order to continue loading.
NOT_WAITING,
// We've run the load algorithm, and we tried all source children of the
// We've run the load algorithm, and we tried all source children of the
// media element, and failed to load any successfully. We're waiting for
// another source element to be added to the media element, and will try
// to load any such element when its added.
@ -917,6 +918,9 @@ protected:
// sniffing phase, that would fail because sniffing only works when applied to
// the first bytes of the stream.
nsCString mMimeType;
// Audio Channel Type.
mozilla::dom::AudioChannelType mAudioChannelType;
};
#endif

View File

@ -13,6 +13,7 @@
#include "nsContentUtils.h"
#include "nsJSUtils.h"
#include "AudioSampleFormat.h"
#include "AudioChannelCommon.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -114,7 +115,7 @@ nsHTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate)
}
mAudioStream = AudioStream::AllocateStream();
nsresult rv = mAudioStream->Init(aChannels, aRate);
nsresult rv = mAudioStream->Init(aChannels, aRate, mAudioChannelType);
if (NS_FAILED(rv)) {
mAudioStream->Shutdown();
mAudioStream = nullptr;

View File

@ -542,18 +542,18 @@ nsHTMLMediaElement::OnChannelRedirect(nsIChannel *aChannel,
NS_ENSURE_STATE(http);
NS_NAMED_LITERAL_CSTRING(rangeHdr, "Range");
nsAutoCString rangeVal;
if (NS_SUCCEEDED(http->GetRequestHeader(rangeHdr, rangeVal))) {
NS_ENSURE_STATE(!rangeVal.IsEmpty());
http = do_QueryInterface(aNewChannel);
NS_ENSURE_STATE(http);
nsresult rv = http->SetRequestHeader(rangeHdr, rangeVal, false);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -674,7 +674,7 @@ public:
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
// Asynchronously awaits a stable state, whereupon aClosure runs on the main
// thread. This adds an event which run aClosure to the appshell's list of
// thread. This adds an event which run aClosure to the appshell's list of
// sections synchronous the next time control returns to the event loop.
void AsyncAwaitStableState(nsHTMLMediaElement* aElement,
SyncSectionFn aClosure)
@ -814,7 +814,7 @@ void nsHTMLMediaElement::NotifyAudioAvailable(float* aFrameBuffer,
{
// Auto manage the memory for the frame buffer, so that if we add an early
// return-on-error here in future, we won't forget to release the memory.
// Otherwise we hand ownership of the memory over to the event created by
// Otherwise we hand ownership of the memory over to the event created by
// DispatchAudioAvailableEvent().
nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
// Do same-origin check on element and media before allowing MozAudioAvailable events.
@ -972,7 +972,7 @@ void nsHTMLMediaElement::UpdatePreloadAction()
Preferences::GetInt("media.preload.auto",
nsHTMLMediaElement::PRELOAD_ENOUGH);
if (!val) {
// Attribute is not set. Use the preload action specified by the
// Attribute is not set. Use the preload action specified by the
// media.preload.default pref, or just preload metadata if not present.
nextAction = static_cast<PreloadAction>(preloadDefault);
} else if (val->Type() == nsAttrValue::eEnum) {
@ -1739,7 +1739,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mMediaSecurityVerified(false),
mCORSMode(CORS_NONE),
mHasAudio(false),
mDownloadSuspendedByCache(false)
mDownloadSuspendedByCache(false),
mAudioChannelType(AUDIO_CHANNEL_NORMAL)
{
#ifdef PR_LOGGING
if (!gMediaElementLog) {
@ -1939,7 +1940,7 @@ bool nsHTMLMediaElement::ParseAttribute(int32_t aNamespaceID,
void nsHTMLMediaElement::DoneCreatingElement()
{
if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted))
mMuted = true;
mMuted = true;
}
nsresult nsHTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
@ -2598,6 +2599,7 @@ nsresult nsHTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
// The new stream has not been suspended by us.
mPausedForInactiveDocument = false;
aDecoder->SetAudioChannelType(mAudioChannelType);
aDecoder->SetAudioCaptured(mAudioCaptured);
aDecoder->SetVolume(mMuted ? 0.0 : mVolume);
for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
@ -2902,7 +2904,7 @@ void nsHTMLMediaElement::FirstFrameLoaded(bool aResourceFullyLoaded)
mSuspendedAfterFirstFrame = true;
mDecoder->Suspend();
} else if (mLoadedFirstFrame &&
mDownloadSuspendedByCache &&
mDownloadSuspendedByCache &&
mDecoder &&
!mDecoder->IsEnded()) {
// We've already loaded the first frame, and the decoder has signalled
@ -3442,7 +3444,7 @@ nsresult nsHTMLMediaElement::Observe(nsISupports* aSubject,
const char* aTopic, const PRUnichar* aData)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
mShuttingDown = true;
AddRemoveSelfReference();
@ -3713,6 +3715,59 @@ void nsHTMLMediaElement::NotifyAudioAvailableListener()
}
}
NS_IMETHODIMP
nsHTMLMediaElement::GetMozAudioChannelType(nsAString& aString)
{
switch (mAudioChannelType) {
case AUDIO_CHANNEL_NORMAL:
aString.AssignLiteral("normal");
break;
case AUDIO_CHANNEL_CONTENT:
aString.AssignLiteral("content");
break;
case AUDIO_CHANNEL_NOTIFICATION:
aString.AssignLiteral("notification");
break;
case AUDIO_CHANNEL_ALARM:
aString.AssignLiteral("alarm");
break;
case AUDIO_CHANNEL_TELEPHONY:
aString.AssignLiteral("telephony");
break;
case AUDIO_CHANNEL_PUBLICNOTIFICATION:
aString.AssignLiteral("publicnotification");
break;
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLMediaElement::SetMozAudioChannelType(const nsAString& aString)
{
if (mDecoder) {
return NS_ERROR_FAILURE;
}
if (aString.EqualsASCII("normal")) {
mAudioChannelType = AUDIO_CHANNEL_NORMAL;
} else if (aString.EqualsASCII("content")) {
mAudioChannelType = AUDIO_CHANNEL_CONTENT;
} else if (aString.EqualsASCII("notification")) {
mAudioChannelType = AUDIO_CHANNEL_NOTIFICATION;
} else if (aString.EqualsASCII("alarm")) {
mAudioChannelType = AUDIO_CHANNEL_ALARM;
} else if (aString.EqualsASCII("telephony")) {
mAudioChannelType = AUDIO_CHANNEL_TELEPHONY;
} else if (aString.EqualsASCII("publicnotification")) {
mAudioChannelType = AUDIO_CHANNEL_PUBLICNOTIFICATION;
} else {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
ImageContainer* nsHTMLMediaElement::GetImageContainer()
{
VideoFrameContainer* container = GetVideoFrameContainer();

View File

@ -68,7 +68,8 @@ class nsNativeAudioStream : public AudioStream
~nsNativeAudioStream();
nsNativeAudioStream();
nsresult Init(int32_t aNumChannels, int32_t aRate);
nsresult Init(int32_t aNumChannels, int32_t aRate,
const AudioChannelType aAudioChannelType);
void Shutdown();
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames);
uint32_t Available();
@ -103,7 +104,8 @@ class nsRemotedAudioStream : public AudioStream
nsRemotedAudioStream();
~nsRemotedAudioStream();
nsresult Init(int32_t aNumChannels, int32_t aRate);
nsresult Init(int32_t aNumChannels, int32_t aRate,
const AudioChannelType aAudioChannelType);
void Shutdown();
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames);
uint32_t Available();
@ -357,6 +359,27 @@ static uint32_t GetCubebLatency()
}
#endif
static sa_stream_type_t ConvertChannelToSAType(AudioChannelType aType)
{
switch(aType) {
case AUDIO_CHANNEL_NORMAL:
return SA_STREAM_TYPE_SYSTEM;
case AUDIO_CHANNEL_CONTENT:
return SA_STREAM_TYPE_MUSIC;
case AUDIO_CHANNEL_NOTIFICATION:
return SA_STREAM_TYPE_NOTIFICATION;
case AUDIO_CHANNEL_ALARM:
return SA_STREAM_TYPE_ALARM;
case AUDIO_CHANNEL_TELEPHONY:
return SA_STREAM_TYPE_VOICE_CALL;
case AUDIO_CHANNEL_PUBLICNOTIFICATION:
return SA_STREAM_TYPE_ENFORCED_AUDIBLE;
default:
NS_ERROR("The value of AudioChannelType is invalid");
return SA_STREAM_TYPE_MAX;
}
}
void AudioStream::InitLibrary()
{
#ifdef PR_LOGGING
@ -434,7 +457,8 @@ nsNativeAudioStream::~nsNativeAudioStream()
NS_IMPL_THREADSAFE_ISUPPORTS0(nsNativeAudioStream)
nsresult nsNativeAudioStream::Init(int32_t aNumChannels, int32_t aRate)
nsresult nsNativeAudioStream::Init(int32_t aNumChannels, int32_t aRate,
const AudioChannelType aAudioChannelType)
{
mRate = aRate;
mChannels = aNumChannels;
@ -451,6 +475,15 @@ nsresult nsNativeAudioStream::Init(int32_t aNumChannels, int32_t aRate)
return NS_ERROR_FAILURE;
}
int saError = sa_stream_set_stream_type(static_cast<sa_stream_t*>(mAudioHandle),
ConvertChannelToSAType(aAudioChannelType));
if (saError != SA_SUCCESS && saError != SA_ERROR_NOT_SUPPORTED) {
mAudioHandle = nullptr;
mInError = true;
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsNativeAudioStream: sa_stream_set_stream_type error"));
return NS_ERROR_FAILURE;
}
if (sa_stream_open(static_cast<sa_stream_t*>(mAudioHandle)) != SA_SUCCESS) {
sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
mAudioHandle = nullptr;
@ -616,7 +649,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsRemotedAudioStream)
nsresult
nsRemotedAudioStream::Init(int32_t aNumChannels,
int32_t aRate)
int32_t aRate, AudioChannelType aAudioChannelType)
{
mRate = aRate;
mChannels = aNumChannels;
@ -811,7 +844,8 @@ class nsBufferedAudioStream : public AudioStream
nsBufferedAudioStream();
~nsBufferedAudioStream();
nsresult Init(int32_t aNumChannels, int32_t aRate);
nsresult Init(int32_t aNumChannels, int32_t aRate,
const AudioChannelType aAudioChannelType);
void Shutdown();
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames);
uint32_t Available();
@ -913,7 +947,8 @@ nsBufferedAudioStream::~nsBufferedAudioStream()
NS_IMPL_THREADSAFE_ISUPPORTS0(nsBufferedAudioStream)
nsresult
nsBufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate)
nsBufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
const AudioChannelType aAudioChannelType)
{
cubeb* cubebContext = GetCubebContext();

View File

@ -11,6 +11,7 @@
#include "nsIThread.h"
#include "nsAutoPtr.h"
#include "AudioSampleFormat.h"
#include "AudioChannelCommon.h"
namespace mozilla {
@ -50,7 +51,8 @@ public:
// (22050Hz, 44100Hz, etc).
// Unsafe to call with a monitor held due to synchronous event execution
// on the main thread, which may attempt to acquire any held monitor.
virtual nsresult Init(int32_t aNumChannels, int32_t aRate) = 0;
virtual nsresult Init(int32_t aNumChannels, int32_t aRate,
const mozilla::dom::AudioChannelType aAudioStreamType) = 0;
// Closes the stream. All future use of the stream is an error.
// Unsafe to call with a monitor held due to synchronous event execution

View File

@ -22,6 +22,7 @@
#include "mozilla/Preferences.h"
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace mozilla {
@ -308,7 +309,8 @@ MediaDecoder::MediaDecoder() :
mOwner(nullptr),
mFrameBufferLength(0),
mPinnedForSeek(false),
mShuttingDown(false)
mShuttingDown(false),
mAudioChannelType(AUDIO_CHANNEL_NORMAL)
{
MOZ_COUNT_CTOR(MediaDecoder);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");

View File

@ -192,6 +192,7 @@ destroying the MediaDecoder object.
#include "mozilla/ReentrantMonitor.h"
#include "MediaStreamGraph.h"
#include "MediaDecoderOwner.h"
#include "AudioChannelCommon.h"
class nsIStreamListener;
class nsTimeRanges;
@ -199,6 +200,8 @@ class nsIMemoryReporter;
class nsIPrincipal;
class nsITimer;
using namespace mozilla::dom;
namespace mozilla {
namespace layers {
class Image;
@ -601,6 +604,10 @@ public:
// mDecoderStateMachine). This must be called with the decode monitor
// held.
void UpdatePlaybackPosition(int64_t aTime);
void SetAudioChannelType(AudioChannelType aType) { mAudioChannelType = aType; }
AudioChannelType GetAudioChannelType() { return mAudioChannelType; }
/******
* The following methods must only be called on the main
* thread.
@ -1027,6 +1034,10 @@ protected:
// being run that operates on the element and decoder during shutdown.
// Read/Write from the main thread only.
bool mShuttingDown;
// Be assigned from media element during the initialization and pass to
// AudioStream Class.
AudioChannelType mAudioChannelType;
};
} // namespace mozilla

View File

@ -24,6 +24,7 @@
namespace mozilla {
using namespace layers;
using namespace mozilla::dom;
#ifdef PR_LOGGING
extern PRLogModuleInfo* gMediaDecoderLog;
@ -985,7 +986,14 @@ void MediaDecoderStateMachine::AudioLoop()
// are unsafe to call with the decoder monitor held are documented as such
// in AudioStream.h.
nsRefPtr<AudioStream> audioStream = AudioStream::AllocateStream();
audioStream->Init(channels, rate);
// In order to access decoder with the monitor held but avoid the dead lock
// issue explaned above, to hold monitor here only for getting audio channel type.
AudioChannelType audioChannelType;
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
audioChannelType = mDecoder->GetAudioChannelType();
}
audioStream->Init(channels, rate, audioChannelType);
{
// We must hold the monitor while setting mAudioStream or whenever we query

View File

@ -20,8 +20,10 @@
#include "mozilla/Attributes.h"
#include "TrackUnionStream.h"
#include "ImageContainer.h"
#include "AudioChannelCommon.h"
using namespace mozilla::layers;
using namespace mozilla::dom;
namespace mozilla {
@ -1160,7 +1162,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
audioOutputStream->mBlockedAudioTime = 0;
audioOutputStream->mStream = AudioStream::AllocateStream();
audioOutputStream->mStream->Init(audio->GetChannels(),
tracks->GetRate());
tracks->GetRate(), AUDIO_CHANNEL_NORMAL);
audioOutputStream->mTrackID = tracks->GetID();
}
}

View File

@ -32,11 +32,11 @@
// Now load a new page
doPageNavigation({
uri: 'data:text/html,<title>new load</title>',
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
eventsToListenFor: [ "pageshow", "pagehide", "visibilitychange" ],
expectedEvents: [ { type: "pagehide",
title: "initial load",
persisted: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "initial load",
visibilityState: "hidden",
hidden: true },
@ -52,15 +52,15 @@
// Now go back
doPageNavigation({
back: true,
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
eventsToListenFor: [ "pageshow", "pagehide", "visibilitychange" ],
expectedEvents: [ { type: "pagehide",
title: "new load",
persisted: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "new load",
visibilityState: "hidden",
hidden: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "initial load",
visibilityState: "visible",
hidden: false },
@ -75,15 +75,15 @@
// And forward
doPageNavigation({
forward: true,
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
eventsToListenFor: [ "pageshow", "pagehide", "visibilitychange" ],
expectedEvents: [ { type: "pagehide",
title: "initial load",
persisted: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "initial load",
visibilityState: "hidden",
hidden: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "new load",
visibilityState: "visible",
hidden: false },
@ -97,21 +97,21 @@
function generateDetector(state, hidden, title, name) {
var detector = function (event) {
is(event.target.mozHidden, hidden,
is(event.target.hidden, hidden,
name + " hidden value does not match");
is(event.target.mozVisibilityState, state,
is(event.target.visibilityState, state,
name + " state value does not match");
is(event.target.title, title,
name + " title value does not match");
document.getElementById("content")
.removeEventListener("mozvisibilitychange",
.removeEventListener("visibilitychange",
detector,
true);
nextTest();
}
document.getElementById("content")
.addEventListener("mozvisibilitychange", detector, true);
.addEventListener("visibilitychange", detector, true);
}
generateDetector("hidden", true, "new load", "Going hidden");
@ -123,7 +123,7 @@
// And navigate back; there should be no visibility state transitions
doPageNavigation({
back: true,
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
eventsToListenFor: [ "pageshow", "pagehide", "visibilitychange" ],
expectedEvents: [ { type: "pagehide",
title: "new load",
persisted: true },
@ -131,7 +131,7 @@
title: "initial load",
persisted: true },
],
unexpectedEvents: [ "mozvisibilitychange" ],
unexpectedEvents: [ "visibilitychange" ],
onNavComplete: nextTest
});
yield;
@ -145,15 +145,15 @@
// And forward
doPageNavigation({
forward: true,
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
eventsToListenFor: [ "pageshow", "pagehide", "visibilitychange" ],
expectedEvents: [ { type: "pagehide",
title: "initial load",
persisted: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "initial load",
visibilityState: "hidden",
hidden: true },
{ type: "mozvisibilitychange",
{ type: "visibilitychange",
title: "new load",
visibilityState: "visible",
hidden: false },
@ -173,4 +173,4 @@
]]></script>
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
</window>
</window>

View File

@ -315,13 +315,13 @@ function pageEventListener(event) {
}
if ("visibilityState" in expected) {
is(event.originalTarget.mozVisibilityState, expected.visibilityState,
is(event.originalTarget.visibilityState, expected.visibilityState,
"The visibilityState property of the document on page " +
event.originalTarget.location + " had an unexpected value");
}
if ("hidden" in expected) {
is(event.originalTarget.mozHidden, expected.hidden,
is(event.originalTarget.hidden, expected.hidden,
"The hidden property of the document on page " +
event.originalTarget.location + " had an unexpected value");
}

View File

@ -74,6 +74,7 @@ PARALLEL_DIRS += \
identity \
workers \
camera \
audiochannel \
$(NULL)
ifdef MOZ_B2G_RIL

View File

@ -41,6 +41,7 @@ this.AppsUtils = {
readyToApplyDownload: aApp.readyToApplyDownload,
downloadSize: aApp.downloadSize || 0,
lastUpdateCheck: aApp.lastUpdateCheck,
updateTime: aApp.updateTime,
etag: aApp.etag
};
},

View File

@ -368,6 +368,8 @@ WebappsApplication.prototype = {
this.removable = aApp.removable;
this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
: Date.now();
this.updateTime = aApp.updateTime ? aApp.updateTime
: aApp.installTime;
this.progress = NaN;
this.downloadAvailable = aApp.downloadAvailable;
this.downloading = aApp.downloading;
@ -599,6 +601,7 @@ WebappsApplication.prototype = {
this.downloading = app.downloading;
this.downloadAvailable = app.downloadAvailable;
this.readyToApplyDownload = app.readyToApplyDownload;
this.updateTime = app.updateTime;
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
break;
case "applied":

View File

@ -807,6 +807,7 @@ this.DOMApplicationRegistry = {
app.downloading = false;
app.downloadAvailable = false;
app.readyToApplyDownload = true;
app.updateTime = Date.now();
DOMApplicationRegistry._saveApps(function() {
debug("About to fire Webapps:PackageEvent");
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
@ -967,6 +968,7 @@ this.DOMApplicationRegistry = {
app.name = aManifest.name;
app.csp = aManifest.csp || "";
app.updateTime = Date.now();
// Update the registry.
this.webapps[id] = app;

View File

@ -0,0 +1,28 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_audiochannelcommon_h__
#define mozilla_dom_audiochannelcommon_h__
namespace mozilla {
namespace dom {
// The audio channel. Read the nsIHTMLMediaElement.idl for a description
// about this attribute.
enum AudioChannelType {
AUDIO_CHANNEL_NORMAL = 0,
AUDIO_CHANNEL_CONTENT,
AUDIO_CHANNEL_NOTIFICATION,
AUDIO_CHANNEL_ALARM,
AUDIO_CHANNEL_TELEPHONY,
AUDIO_CHANNEL_PUBLICNOTIFICATION
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -0,0 +1,39 @@
# Copyright 2012 Mozilla Foundation and Mozilla contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = dom
LIBRARY_NAME = domaudiochannel_s
XPIDL_MODULE = dom_audiochannel
LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1
EXPORT_LIBRARY = 1
FAIL_ON_WARNINGS := 1
EXPORTS_NAMESPACES = \
mozilla/dom \
$(NULL)
EXPORTS = AudioChannelCommon.h
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -605,7 +605,7 @@ public:
mDocument = do_GetWeakReference(aDocument);
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aDocument);
NS_NAMED_LITERAL_STRING(visibilitychange, "mozvisibilitychange");
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
target->AddSystemEventListener(visibilitychange,
this, /* listener */
true, /* use capture */
@ -639,7 +639,7 @@ VibrateWindowListener::HandleEvent(nsIDOMEvent* aEvent)
bool hidden = true;
if (doc) {
doc->GetMozHidden(&hidden);
doc->GetHidden(&hidden);
}
if (hidden) {
@ -664,7 +664,7 @@ VibrateWindowListener::RemoveListener()
if (!target) {
return;
}
NS_NAMED_LITERAL_STRING(visibilitychange, "mozvisibilitychange");
NS_NAMED_LITERAL_STRING(visibilitychange, "visibilitychange");
target->RemoveSystemEventListener(visibilitychange, this,
true /* use capture */);
}
@ -737,7 +737,7 @@ Navigator::Vibrate(const jsval& aPattern, JSContext* cx)
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
bool hidden = true;
domDoc->GetMozHidden(&hidden);
domDoc->GetHidden(&hidden);
if (hidden) {
// Hidden documents cannot start or stop a vibration.
return NS_OK;
@ -787,7 +787,7 @@ Navigator::Vibrate(const jsval& aPattern, JSContext* cx)
}
// Add a listener to cancel the vibration if the document becomes hidden,
// and remove the old mozvisibility listener, if there was one.
// and remove the old visibility listener, if there was one.
if (!gVibrateWindowListener) {
// If gVibrateWindowListener is null, this is the first time we've vibrated,

View File

@ -260,9 +260,9 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
// Listen to mozvisibilitychange on the iframe's owner window, and forward it
// Listen to visibilitychange on the iframe's owner window, and forward it
// down to the child.
this._window.addEventListener('mozvisibilitychange',
this._window.addEventListener('visibilitychange',
this._ownerVisibilityChange.bind(this),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
@ -365,7 +365,7 @@ BrowserElementParent.prototype = {
// that we must do so here, rather than in the BrowserElementParent
// constructor, because the BrowserElementChild may not be initialized when
// we run our constructor.
if (this._window.document.mozHidden) {
if (this._window.document.hidden) {
this._ownerVisibilityChange();
}
},
@ -609,7 +609,7 @@ BrowserElementParent.prototype = {
*/
_ownerVisibilityChange: function() {
this._sendAsyncMsg('owner-visibility-change',
{visible: !this._window.document.mozHidden});
{visible: !this._window.document.hidden});
},
_exitFullscreen: function() {

View File

@ -7,9 +7,9 @@
SimpleTest.waitForExplicitFinish();
var iframeScript = function() {
content.document.addEventListener("mozvisibilitychange", function() {
content.document.addEventListener("visibilitychange", function() {
sendAsyncMessage('test:visibilitychange', {
hidden: content.document.mozHidden
hidden: content.document.hidden
});
}, false);
}
@ -32,18 +32,18 @@ function runTest() {
numEvents++;
if (numEvents === 1) {
ok(true, 'iframe recieved visibility changed');
ok(msg.json.hidden === true, 'mozHidden attribute correctly set');
ok(msg.json.hidden === true, 'hidden attribute correctly set');
iframe1.setVisible(false);
iframe1.setVisible(true);
} else if (numEvents === 2) {
ok(msg.json.hidden === false, 'mozHidden attribute correctly set');
ok(msg.json.hidden === false, 'hidden attribute correctly set');
// Allow some time in case we generate too many events
setTimeout(function() {
mm.removeMessageListener('test:visibilitychange', recvVisibilityChanged);
SimpleTest.finish();
}, 100);
} else {
ok(false, 'Too many mozhidden events');
ok(false, 'Too many visibilitychange events');
}
}

View File

@ -9,8 +9,8 @@ addEventListener('load', function() {
}, 0);
});
addEventListener('mozvisibilitychange', function() {
alert(name + ':' + (document.mozHidden ? 'hidden' : 'visible'));
addEventListener('visibilitychange', function() {
alert(name + ':' + (document.hidden ? 'hidden' : 'visible'));
});
</script>

View File

@ -11,6 +11,7 @@ this.EXPORTED_SYMBOLS = ["DOMIdentity"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
#ifdef MOZ_B2G_VERSION
@ -31,8 +32,8 @@ function log(...aMessageArgs) {
Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs));
}
function IDDOMMessage(aID) {
this.id = aID;
function IDDOMMessage(aOptions) {
objectCopy(aOptions, this);
}
function IDPProvisioningContext(aID, aOrigin, aTargetMM) {
@ -46,7 +47,7 @@ IDPProvisioningContext.prototype = {
get origin() this._origin,
doBeginProvisioningCallback: function IDPPC_doBeginProvCB(aID, aCertDuration) {
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.identity = aID;
message.certDuration = aCertDuration;
this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
@ -55,7 +56,7 @@ IDPProvisioningContext.prototype = {
doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) {
log("doGenKeyPairCallback");
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.publicKey = aPublicKey;
this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
},
@ -76,7 +77,7 @@ IDPAuthenticationContext.prototype = {
get origin() this._origin,
doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) {
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.identity = aIdentity;
this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
message);
@ -87,34 +88,37 @@ IDPAuthenticationContext.prototype = {
},
};
function RPWatchContext(aID, aOrigin, aLoggedInUser, aTargetMM) {
this._id = aID;
this._origin = aOrigin;
this._loggedInUser = aLoggedInUser;
function RPWatchContext(aOptions, aTargetMM) {
objectCopy(aOptions, this);
// id and origin are required
if (! (this.id && this.origin)) {
throw new Error("id and origin are required for RP watch context");
}
// default for no loggedInUser is undefined, not null
this.loggedInUser = aOptions.loggedInUser;
this._mm = aTargetMM;
}
RPWatchContext.prototype = {
get id() this._id,
get origin() this._origin,
get loggedInUser() this._loggedInUser,
doLogin: function RPWatchContext_onlogin(aAssertion) {
log("doLogin: " + this.id);
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.assertion = aAssertion;
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
},
doLogout: function RPWatchContext_onlogout() {
log("doLogout :" + this.id);
let message = new IDDOMMessage(this.id);
log("doLogout: " + this.id);
let message = new IDDOMMessage({id: this.id});
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message);
},
doReady: function RPWatchContext_onready() {
log("doReady: " + this.id);
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
},
@ -212,7 +216,7 @@ this.DOMIdentity = {
if (!aContext._mm) {
throw new Error("ERROR: Trying to reset an invalid context");
}
let message = new IDDOMMessage(aContext.id);
let message = new IDDOMMessage({id: aContext.id});
aContext._mm.sendAsyncMessage("Identity:ResetState", message);
},
@ -220,8 +224,7 @@ this.DOMIdentity = {
log("DOMIdentity__watch: " + message.id);
// Pass an object with the watch members to Identity.jsm so it can call the
// callbacks.
let context = new RPWatchContext(message.id, message.origin,
message.loggedInUser, targetMM);
let context = new RPWatchContext(message, targetMM);
IdentityService.RP.watch(context);
},
@ -230,7 +233,7 @@ this.DOMIdentity = {
},
_logout: function DOMIdentity__logout(message) {
IdentityService.RP.logout(message.id, message.origin);
IdentityService.RP.logout(message.id, message.origin, message);
},
_beginProvisioning: function DOMIdentity__beginProvisioning(message, targetMM) {

View File

@ -18,13 +18,11 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
// This is the child process corresponding to nsIDOMIdentity
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
// This is the child process corresponding to nsIDOMIdentity.
function nsDOMIdentity(aIdentityInternal) {
this._identityInternal = aIdentityInternal;
}
@ -77,7 +75,7 @@ nsDOMIdentity.prototype = {
throw new Error("onready must be a function");
}
let message = this.DOMIdentityMessage();
let message = this.DOMIdentityMessage(aOptions);
// loggedInUser vs loggedInEmail
// https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
@ -125,7 +123,7 @@ nsDOMIdentity.prototype = {
throw new Error("navigator.id.request called too many times");
}
let message = this.DOMIdentityMessage();
let message = this.DOMIdentityMessage(aOptions);
if (aOptions) {
// Optional string properties
@ -314,7 +312,6 @@ nsDOMIdentity.prototype = {
_receiveMessage: function nsDOMIdentity_receiveMessage(aMessage) {
let msg = aMessage.json;
this._log("receiveMessage: " + aMessage.name);
switch (aMessage.name) {
case "Identity:ResetState":
@ -419,13 +416,24 @@ nsDOMIdentity.prototype = {
},
/**
* Helper to create messages to send using a message manager
* Helper to create messages to send using a message manager.
* Pass through user options if they are not functions. Always
* overwrite id and origin. Caller does not get to set those.
*/
DOMIdentityMessage: function DOMIdentityMessage() {
return {
id: this._id,
origin: this._origin,
};
DOMIdentityMessage: function DOMIdentityMessage(aOptions) {
aOptions = aOptions || {};
let message = {};
objectCopy(aOptions, message);
// outer window id
message.id = this._id;
// window origin
message.origin = this._origin;
dump("nsDOM message: " + JSON.stringify(message) + "\n");
return message;
},
};

View File

@ -8,7 +8,7 @@
interface nsIDOMDOMRequest;
interface nsIDOMDOMError;
[scriptable, uuid(b00a5908-1228-46bf-a42b-091dce3abde1)]
[scriptable, uuid(84524e5f-c4ab-4dce-8364-4aac71851ff1)]
interface mozIDOMApplication : nsISupports
{
readonly attribute jsval manifest;
@ -41,10 +41,15 @@ interface mozIDOMApplication : nsISupports
attribute nsIDOMEventListener onprogress;
/**
* The date of the last update.
* The date of the last update check.
*/
readonly attribute unsigned long long lastUpdateCheck;
/**
* The date of the last updated manifest.
*/
readonly attribute unsigned long long updateTime;
/**
* Starts the process of looking for an update.
*/

View File

@ -27,7 +27,7 @@ interface nsIDOMLocation;
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
[scriptable, uuid(22af46a3-64ac-430a-bcc7-d0a9aefe474f)]
[scriptable, uuid(31ce7ae7-15d5-4fc8-912b-ae0e23e93146)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;
@ -385,7 +385,9 @@ interface nsIDOMDocument : nsIDOMNode
/**
* Visibility API implementation.
*/
readonly attribute boolean hidden;
readonly attribute boolean mozHidden;
readonly attribute DOMString visibilityState;
readonly attribute DOMString mozVisibilityState;
/**

View File

@ -20,7 +20,7 @@
* @status UNDER_DEVELOPMENT
*/
[scriptable, uuid(9e6cbf3e-4ae5-4a7b-a6ce-5af23572693f)]
[scriptable, uuid(771a0d40-18ed-11e2-89ca-10bf48d64bd4)]
interface nsIDOMHTMLAudioElement : nsIDOMHTMLMediaElement
{
// Setup the audio stream for writing

View File

@ -27,7 +27,7 @@ interface nsIDOMMediaStream;
#endif
%}
[scriptable, uuid(f49b0fea-dc13-47bd-b43e-606044280741)]
[scriptable, uuid(4319d74a-ef91-46e0-b6e1-b35036fc4024)]
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
{
// error state
@ -43,7 +43,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
const unsigned short NETWORK_LOADING = 2;
const unsigned short NETWORK_NO_SOURCE = 3;
readonly attribute unsigned short networkState;
attribute DOMString preload;
attribute DOMString preload;
readonly attribute nsIDOMTimeRanges buffered;
void load();
DOMString canPlayType(in DOMString type);
@ -110,4 +110,34 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
// the media element has a fragment URI for the currentSrc, otherwise
// it is equal to the media duration.
readonly attribute double mozFragmentEnd;
// Mozilla extension: an audio channel type for media elements.
// An exception is thrown if the app tries to change the audio channel type
// without the permission (manifest file for B2G apps).
// The supported values are:
// * normal (default value)
// Automatically paused if "notification" or higher priority channel
// is played
// Use case: normal applications
// * content
// Automatically paused if "notification" or higher priority channel
// is played. Also paused if another app starts using "content"
// channel. Using this channel never affects applications using
// the "normal" channel.
// Use case: video/audio players
// * notification
// Automatically paused if "alarm" or higher priority channel is played.
// Use case: New email, incoming SMS
// * alarm
// Automatically paused if "telephony" or higher priority channel is
// played.
// User case: Alarm clock, calendar alarms
// * telephony
// Automatically paused if "publicnotification" or higher priority
// channel is played.
// Use case: dialer, voip
// * publicnotification
// Always plays in speaker, even when headphones are plugged in.
attribute DOMString mozAudioChannelType;
};

View File

@ -16,7 +16,7 @@
* @status UNDER_DEVELOPMENT
*/
[scriptable, uuid(1fb777fd-952a-4666-bb26-0b32acaf674d)]
[scriptable, uuid(84395418-18ed-11e2-bbda-10bf48d64bd4)]
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
{
attribute long width;

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/AudioParent.h"
#include "mozilla/unused.h"
#include "nsThreadUtils.h"
#include "AudioChannelCommon.h"
// C++ file contents
namespace mozilla {
@ -297,7 +298,8 @@ AudioParent::AudioParent(int32_t aNumChannels, int32_t aRate)
{
mStream = AudioStream::AllocateStream();
NS_ASSERTION(mStream, "AudioStream allocation failed.");
if (NS_FAILED(mStream->Init(aNumChannels, aRate))) {
if (NS_FAILED(mStream->Init(aNumChannels, aRate, AUDIO_CHANNEL_NORMAL))) {
NS_WARNING("AudioStream initialization failed.");
mStream = nullptr;
return;

View File

@ -194,7 +194,7 @@ ProcessPriorityManager::OnContentDocumentGlobalCreated(
return;
}
target->AddSystemEventListener(NS_LITERAL_STRING("mozvisibilitychange"),
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ false,
/* wantsUntrusted = */ false);
@ -235,7 +235,7 @@ ProcessPriorityManager::RecomputeNumVisibleWindows()
}
bool hidden = false;
doc->GetMozHidden(&hidden);
doc->GetHidden(&hidden);
#ifdef DEBUG
nsAutoString spec;
doc->GetDocumentURI(spec);

View File

@ -114,3 +114,5 @@ MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver
MozSliceWarning=Use of mozSlice on the Blob object is deprecated. Use slice instead.
# LOCALIZATION NOTE: Do not translate "Components"
ComponentsWarning=The Components object is deprecated. It will soon be removed.
# LOCALIZATION NOTE: Do not translate "mozHidden", "mozVisibilityState", "hidden", or "visibilityState"
PrefixedVisibilityApiWarning='mozHidden' and 'mozVisibilityState' are deprecated. Please use the unprefixed 'hidden' and 'visibilityState' instead.

View File

@ -58,7 +58,7 @@ WakeLock::Init(const nsAString &aTopic, nsIDOMWindow *aWindow)
if (window) {
nsCOMPtr<nsIDOMDocument> domDoc = window->GetExtantDocument();
NS_ENSURE_STATE(domDoc);
domDoc->GetMozHidden(&mHidden);
domDoc->GetHidden(&mHidden);
}
AttachEventListener();
@ -100,7 +100,7 @@ WakeLock::AttachEventListener()
nsCOMPtr<nsIDOMDocument> domDoc = window->GetExtantDocument();
if (domDoc) {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(domDoc);
target->AddSystemEventListener(NS_LITERAL_STRING("mozvisibilitychange"),
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
@ -127,7 +127,7 @@ WakeLock::DetachEventListener()
nsCOMPtr<nsIDOMDocument> domDoc = window->GetExtantDocument();
if (domDoc) {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(domDoc);
target->RemoveSystemEventListener(NS_LITERAL_STRING("mozvisibilitychange"),
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
this,
/* useCapture = */ true);
target = do_QueryInterface(window);
@ -170,13 +170,13 @@ WakeLock::HandleEvent(nsIDOMEvent *aEvent)
nsAutoString type;
aEvent->GetType(type);
if (type.EqualsLiteral("mozvisibilitychange")) {
if (type.EqualsLiteral("visibilitychange")) {
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(target);
NS_ENSURE_STATE(domDoc);
bool oldHidden = mHidden;
domDoc->GetMozHidden(&mHidden);
domDoc->GetHidden(&mHidden);
if (mLocked && oldHidden != mHidden) {
hal::ModifyWakeLock(mTopic,

View File

@ -114,14 +114,14 @@ let gSteps = [
browser.addEventListener("load", function onLoad(e) {
browser.removeEventListener("load", onLoad, true);
gLock2 = gWin2.navigator.requestWakeLock("test");
is(gWin2.document.mozHidden, true,
is(gWin2.document.hidden, true,
"window is background")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-background",
"wake lock is background");
let doc2 = gWin2.document;
doc2.addEventListener("mozvisibilitychange", function onVisibilityChange(e) {
if (!doc2.mozHidden) {
doc2.removeEventListener("mozvisibilitychange", onVisibilityChange);
doc2.addEventListener("visibilitychange", function onVisibilityChange(e) {
if (!doc2.hidden) {
doc2.removeEventListener("visibilitychange", onVisibilityChange);
executeSoon(runNextStep);
}
});
@ -129,7 +129,7 @@ let gSteps = [
}, true);
},
function crossTabWakeLock2() {
is(gWin2.document.mozHidden, false,
is(gWin2.document.hidden, false,
"window is foreground")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"wake lock is foreground");
@ -157,7 +157,7 @@ let gSteps = [
},
function crossTabWakeLock5() {
// Test again in background tab
is(gWin2.document.mozHidden, true,
is(gWin2.document.hidden, true,
"window is background")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-background",
"wake lock is background");
@ -185,9 +185,9 @@ let gSteps = [
executeSoon(runNextStep);
},
function crossTabWakeLock8() {
is(gWin1.document.mozHidden, true,
is(gWin1.document.hidden, true,
"gWin1 is background");
is(gWin2.document.mozHidden, false,
is(gWin2.document.hidden, false,
"gWin2 is foreground");
gLock1 = gWin1.navigator.requestWakeLock("test");

View File

@ -54,16 +54,15 @@ static int sHeadsetState;
static int kBtSampleRate = 8000;
static bool
IsFmRadioAudioOn()
IsDeviceOn(audio_devices_t device)
{
if (static_cast<
audio_policy_dev_state_t (*) (audio_devices_t, const char *)
>(AudioSystem::getDeviceConnectionState)) {
return AudioSystem::getDeviceConnectionState(AUDIO_DEVICE_OUT_FM, "") ==
AUDIO_POLICY_DEVICE_STATE_AVAILABLE ? true : false;
} else {
return false;
}
>(AudioSystem::getDeviceConnectionState))
return AudioSystem::getDeviceConnectionState(device, "") ==
AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
return false;
}
NS_IMPL_ISUPPORTS2(AudioManager, nsIAudioManager, nsIObserver)
@ -102,7 +101,7 @@ InternalSetAudioRoutesICS(SwitchState aState)
// The audio volume is not consistent when we plug and unplug the headset.
// Set the fm volume again here.
if (IsFmRadioAudioOn()) {
if (IsDeviceOn(AUDIO_DEVICE_OUT_FM)) {
float masterVolume;
AudioSystem::getMasterVolume(&masterVolume);
AudioSystem::setFmVolume(masterVolume);
@ -256,7 +255,8 @@ AudioManager::SetMasterVolume(float aMasterVolume)
return NS_ERROR_FAILURE;
}
if (IsFmRadioAudioOn() && AudioSystem::setFmVolume(aMasterVolume)) {
if (IsDeviceOn(AUDIO_DEVICE_OUT_FM) &&
AudioSystem::setFmVolume(aMasterVolume)) {
return NS_ERROR_FAILURE;
}
@ -311,6 +311,13 @@ NS_IMETHODIMP
AudioManager::SetForceForUse(int32_t aUsage, int32_t aForce)
{
status_t status = 0;
if (IsDeviceOn(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) &&
aUsage == nsIAudioManager::USE_COMMUNICATION &&
aForce == nsIAudioManager::FORCE_NONE) {
aForce = nsIAudioManager::FORCE_BT_SCO;
}
if (static_cast<
status_t (*)(AudioSystem::force_use, AudioSystem::forced_config)
>(AudioSystem::setForceUse)) {
@ -347,7 +354,7 @@ AudioManager::GetForceForUse(int32_t aUsage, int32_t* aForce) {
NS_IMETHODIMP
AudioManager::GetFmRadioAudioEnabled(bool *aFmRadioAudioEnabled)
{
*aFmRadioAudioEnabled = IsFmRadioAudioOn();
*aFmRadioAudioEnabled = IsDeviceOn(AUDIO_DEVICE_OUT_FM);
return NS_OK;
}

View File

@ -8,30 +8,43 @@ disabled = Bug 790463
[test_incoming_reject.js]
disabled = Bug 811167
[test_outgoing_answer_hangup.js]
disabled = Bug 811167
[test_incoming_answer_hangup_oncallschanged.js]
disabled = Bug 811167
[test_outgoing_answer_hangup_oncallschanged.js]
disabled = Bug 811167
[test_outgoing_hangup_alerting.js]
disabled = Bug 811167
[test_outgoing_hangup_held.js]
disabled = Bug 811167
[test_outgoing_badNumber.js]
disabled = Bug 761533
[test_outgoing_busy.js]
disabled = Bug 761533
[test_outgoing_reject.js]
disabled = Bug 811167
[test_voicemail_statuschanged.py]
disabled = Bug 806138
[test_voicemail_number.js]
disabled = Bug 811167
[test_incoming_hold_resume.js]
disabled = Bug 811167
[test_outgoing_hold_resume.js]
disabled = Bug 790463
[test_incoming_already_connected.js]
disabled = Bug 790463
[test_incoming_answer_remote_hangup.js]
disabled = Bug 811167
[test_incoming_connecting_hangup.js]
disabled = Bug 811167
[test_incoming_connecting_remote_hangup.js]
disabled = Bug 811167
[test_incoming_hangup_held.js]
disabled = Bug 790463
[test_incoming_remote_cancel.js]
disabled = Bug 811167
[test_incoming_remote_hangup_held.js]
disabled = Bug 811167
[test_outgoing_already_held.js]
disabled = Bug 790463
[test_outgoing_answer_local_hangup.js]
@ -43,6 +56,10 @@ disabled = Bug 790463
[test_swap_held_and_active.js]
disabled = Bug 790463
[test_incoming_onstatechange.js]
disabled = Bug 811167
[test_outgoing_onstatechange.js]
disabled = Bug 811167
[test_redundant_operations.js]
disabled = Bug 811167

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -22,7 +22,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -22,7 +22,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}
@ -127,6 +132,7 @@ function hangUp() {
}
function cleanUp() {
telephony.oncallschanged = null;
SpecialPowers.removePermission("telephony", document);
finish();
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -20,7 +20,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}
@ -153,6 +158,7 @@ function hangUp() {
}
function cleanUp() {
telephony.onincoming = null;
SpecialPowers.removePermission("telephony", document);
finish();
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}
@ -79,6 +84,7 @@ function reject() {
}
function cleanUp() {
telephony.onincoming = null;
SpecialPowers.removePermission("telephony", document);
finish();
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
simulateIncoming();
if (result[0] == "OK") {
simulateIncoming();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}
@ -93,6 +98,7 @@ function hangUp() {
}
function cleanUp() {
telephony.oncallschanged = null;
SpecialPowers.removePermission("telephony", document);
finish();
}

View File

@ -19,7 +19,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

View File

@ -21,7 +21,12 @@ function verifyInitialState() {
runEmulatorCmd("gsm list", function(result) {
log("Initial call list: " + result);
is(result[0], "OK");
dial();
if (result[0] == "OK") {
dial();
} else {
log("Call exists from a previous test, failing out.");
cleanUp();
}
});
}

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