Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2013-08-26 20:20:58 -04:00
commit 8a77e0943c
198 changed files with 3388 additions and 3124 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 908208 - ipdl dependencies are busted, so we must clobber. See Bug 907394 for a solution.
Bug 899210 - xpidl header generation is somehow busted so we need to clobber on windows

View File

@ -779,7 +779,7 @@ XULTreeItemAccessibleBase::GetBounds(int32_t* aX, int32_t* aY,
NS_IMETHODIMP
XULTreeItemAccessibleBase::SetSelected(bool aSelect)
{
if (IsDefunct() || !mTreeView)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsITreeSelection> selection;
@ -797,7 +797,7 @@ XULTreeItemAccessibleBase::SetSelected(bool aSelect)
NS_IMETHODIMP
XULTreeItemAccessibleBase::TakeFocus()
{
if (IsDefunct() || !mTreeView)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsITreeSelection> selection;
@ -812,8 +812,6 @@ XULTreeItemAccessibleBase::TakeFocus()
Relation
XULTreeItemAccessibleBase::RelationByType(uint32_t aType)
{
if (!mTreeView)
return Relation();
switch (aType) {
case nsIAccessibleRelation::RELATION_NODE_CHILD_OF: {
@ -956,8 +954,6 @@ XULTreeItemAccessibleBase::GroupPosition()
uint64_t
XULTreeItemAccessibleBase::NativeState()
{
if (!mTreeView)
return states::DEFUNCT;
// focusable and selectable states
uint64_t state = NativeInteractiveState();
@ -1062,8 +1058,6 @@ XULTreeItemAccessibleBase::GetSiblingAtOffset(int32_t aOffset,
bool
XULTreeItemAccessibleBase::IsExpandable()
{
if (!mTreeView)
return false;
bool isContainer = false;
mTreeView->IsContainer(mRow, &isContainer);
@ -1089,8 +1083,6 @@ XULTreeItemAccessibleBase::IsExpandable()
void
XULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn, nsAString& aName)
{
if (!mTreeView)
return;
mTreeView->GetCellText(mRow, aColumn, aName);

View File

@ -778,8 +778,6 @@ XULTreeGridCellAccessible::RelationByType(uint32_t aType)
void
XULTreeGridCellAccessible::CellInvalidated()
{
if (!mTreeView)
return;
nsAutoString textEquiv;
@ -852,8 +850,6 @@ XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent,
bool
XULTreeGridCellAccessible::IsEditable() const
{
if (!mTreeView)
return false;
// XXX: logic corresponds to tree.xml, it's preferable to have interface
// method to check it.

View File

@ -13,7 +13,6 @@ const { exit, env, staticArgs } = require('../system');
const { when: unload } = require('../system/unload');
const { loadReason } = require('../self');
const { rootURI } = require("@loader/options");
const cfxArgs = require("@test/options");
const globals = require('../system/globals');
const xulApp = require('../system/xul-app');
const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
@ -102,11 +101,7 @@ function startup(reason, options) {
// Run the addon even in case of error (best effort approach)
require('../l10n/loader').
load(rootURI).
then(function l10nSuccess() {
if (cfxArgs.parseable) {
console.info("localization information has loaded successfully.");
}
}, function l10nFailure(error) {
then(null, function failure(error) {
console.info("Error while loading localization: " + error.message);
}).
then(function onLocalizationReady(data) {
@ -115,10 +110,6 @@ function startup(reason, options) {
definePseudo(options.loader, '@l10n/data', data ? data : null);
return ready;
}).then(function() {
if (cfxArgs.parseable) {
console.info("addon window has loaded successfully.");
}
run(options);
}).then(null, console.exception);
}
@ -137,7 +128,6 @@ function run(options) {
catch(error) {
console.exception(error);
}
// Initialize inline options localization, without preventing addon to be
// run in case of error
try {
@ -167,8 +157,7 @@ function run(options) {
quit: exit
});
}
}
catch (error) {
} catch (error) {
console.exception(error);
throw error;
}

View File

@ -1,17 +1,14 @@
/* 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/. */
"use strict";
module.metadata = {
"stability": "experimental"
};
var obsvc = require("../deprecated/observer-service");
var { exit, stdout } = require("../system");
var cfxArgs = require("@test/options");
var { Cc, Ci} = require("chrome");
function runTests(findAndRunTests) {
var harness = require("./harness");
@ -62,7 +59,7 @@ function printFailedTests(tests, print) {
iterationNumber++;
if (!singleIteration)
print(" Iteration " + iterationNumber + ":\n");
print(" Iteration " + iterationNumber + ":\n");
for each (let test in testRun) {
if (test.failed > 0) {

View File

@ -48,6 +48,20 @@ const prototypeOf = Object.getPrototypeOf;
const create = Object.create;
const keys = Object.keys;
const COMPONENT_ERROR = '`Components` is not available in this context.\n' +
'Functionality provided by Components may be available in an SDK\n' +
'module: https://jetpack.mozillalabs.com/sdk/latest/docs/ \n\n' +
'However, if you still need to import Components, you may use the\n' +
'`chrome` module\'s properties for shortcuts to Component properties:\n\n' +
'Shortcuts: \n' +
' Cc = Components' + '.classes \n' +
' Ci = Components' + '.interfaces \n' +
' Cu = Components' + '.utils \n' +
' CC = Components' + '.Constructor \n' +
'Example: \n' +
' let { Cc, Ci } = require(\'chrome\');\n';
// Workaround for bug 674195. Freezing objects from other compartments fail,
// so we use `Object.freeze` from the same component instead.
function freeze(object) {
@ -216,19 +230,26 @@ const load = iced(function load(loader, module) {
let { sandboxes, globals } = loader;
let require = Require(loader, module);
// We expose set of properties defined by `CommonJS` specification via
// prototype of the sandbox. Also globals are deeper in the prototype
// chain so that each module has access to them as well.
let descriptors = descriptor({
require: require,
module: module,
exports: module.exports,
get Components() {
// Expose `Components` property to throw error on usage with
// additional information
throw new ReferenceError(COMPONENT_ERROR);
}
});
let sandbox = sandboxes[module.uri] = Sandbox({
name: module.uri,
// Get an existing module sandbox, if any, so we can reuse its compartment
// when creating the new one to reduce memory consumption.
sandbox: sandboxes[keys(sandboxes).shift()],
// We expose set of properties defined by `CommonJS` specification via
// prototype of the sandbox. Also globals are deeper in the prototype
// chain so that each module has access to them as well.
prototype: create(globals, descriptor({
require: require,
module: module,
exports: module.exports
})),
prototype: create(globals, descriptors),
wantXrays: false
});

View File

@ -1,26 +1,24 @@
/* 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/. */
'use strict';
"use strict";
const { List } = require('sdk/deprecated/list');
function assertList(test, array, list) {
for (let i = 0, ii = array.length; i < ii; i < ii, i++) {
test.assertEqual(
function assertList(assert, array, list) {
for (let i = 0, l = array.length; i < l; i++) {
assert.equal(
array.length,
list.length,
'list must contain same amount of elements as array'
);
test.assertEqual(
assert.equal(
'List(' + array + ')',
list + '',
'toString must output array like result'
);
test.assert(
i in list,
'must contain element with index: ' + i
);
test.assertEqual(
assert.ok(i in list, 'must contain element with index: ' + i);
assert.equal(
array[i],
list[i],
'element with index: ' + i + ' should match'
@ -28,89 +26,83 @@ function assertList(test, array, list) {
}
}
const { List } = require('sdk/deprecated/list');
exports['test:test for'] = function(test) {
exports['test:test for'] = function(assert) {
let fixture = List(3, 2, 1);
test.assertEqual(3, fixture.length, 'length is 3');
assert.equal(3, fixture.length, 'length is 3');
let i = 0;
for (let key in fixture) {
test.assertEqual(i++, key, 'key should match');
assert.equal(i++, key, 'key should match');
}
};
exports['test:test for each'] = function(test) {
exports['test:test for each'] = function(assert) {
let fixture = new List(3, 2, 1);
test.assertEqual(3, fixture.length, 'length is 3');
let i = 3;
for each (let value in fixture) {
test.assertEqual(i--, value, 'value should match');
}
};
exports['test:test for of'] = function(test) {
let fixture = new List(3, 2, 1);
test.assertEqual(3, fixture.length, 'length is 3');
assert.equal(3, fixture.length, 'length is 3');
let i = 3;
for (let value of fixture) {
test.assertEqual(i--, value, 'value should match');
assert.equal(i--, value, 'value should match');
}
};
exports['test:test toString'] = function(test) {
exports['test:test for of'] = function(assert) {
let fixture = new List(3, 2, 1);
assert.equal(3, fixture.length, 'length is 3');
let i = 3;
for (let value of fixture) {
assert.equal(i--, value, 'value should match');
}
};
exports['test:test toString'] = function(assert) {
let fixture = List(3, 2, 1);
test.assertEqual(
assert.equal(
'List(3,2,1)',
fixture + '',
'toString must output array like result'
)
};
exports['test:test constructor with apply'] = function(test) {
exports['test:test constructor with apply'] = function(assert) {
let array = ['a', 'b', 'c'];
let fixture = List.apply(null, array);
test.assertEqual(
assert.equal(
3,
fixture.length,
'should have applied arguments'
);
};
exports['test:direct element access'] = function(test) {
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, test, 1];
exports['test:direct element access'] = function(assert) {
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, assert, 1];
let fixture = List.apply(null, array);
array.splice(5, 1);
array.splice(7, 1);
test.assertEqual(
assert.equal(
array.length,
fixture.length,
'list should omit duplicate elements'
);
test.assertEqual(
assert.equal(
'List(' + array + ')',
fixture.toString(),
'elements should not be rearranged'
);
for (let key in array) {
test.assert(key in fixture,'should contain key for index:' + key);
test.assertEqual(
array[key],
fixture[key],
'values should match for: ' + key
);
assert.ok(key in fixture,'should contain key for index:' + key);
assert.equal(array[key], fixture[key], 'values should match for: ' + key);
}
};
exports['test:removing adding elements'] = function(test) {
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, test, 1];
exports['test:removing adding elements'] = function(assert) {
let array = [1, 'foo', 2, 'bar', {}, 'bar', function a() {}, assert, 1];
let fixture = List.compose({
add: function() this._add.apply(this, arguments),
remove: function() this._remove.apply(this, arguments),
@ -119,11 +111,11 @@ exports['test:removing adding elements'] = function(test) {
array.splice(5, 1);
array.splice(7, 1);
assertList(test, array, fixture);
assertList(assert, array, fixture);
array.splice(array.indexOf(2), 1);
fixture.remove(2);
assertList(test, array, fixture);
assertList(assert, array, fixture);
array.splice(array.indexOf('foo'), 1);
fixture.remove('foo');
@ -131,11 +123,11 @@ exports['test:removing adding elements'] = function(test) {
fixture.remove(1);
array.push('foo');
fixture.add('foo');
assertList(test, array, fixture);
assertList(assert, array, fixture);
array.splice(0);
fixture.clear(0);
assertList(test, array, fixture);
assertList(assert, array, fixture);
array.push(1, 'foo', 2, 'bar', 3);
fixture.add(1);
@ -144,26 +136,26 @@ exports['test:removing adding elements'] = function(test) {
fixture.add('bar');
fixture.add(3);
assertList(test, array, fixture);
assertList(assert, array, fixture);
};
exports['test: remove does not leave invalid numerical properties'] = function(test) {
exports['test: remove does not leave invalid numerical properties'] = function(assert) {
let fixture = List.compose({
remove: function() this._remove.apply(this, arguments),
}).apply(null, [1, 2, 3]);
fixture.remove(1);
test.assertEqual(fixture[fixture.length], undefined);
assert.equal(fixture[fixture.length], undefined);
}
exports['test:add list item from Iterator'] = function(test) {
exports['test:add list item from Iterator'] = function(assert) {
let array = [1, 2, 3, 4], sum = 0, added = false;
let fixture = List.compose({
add: function() this._add.apply(this, arguments),
}).apply(null, array);
for each (let item in fixture) {
for (let item of fixture) {
sum += item;
if (!added) {
@ -172,35 +164,37 @@ exports['test:add list item from Iterator'] = function(test) {
}
}
test.assertEqual(sum, 1 + 2 + 3 + 4);
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
};
exports['test:remove list item from Iterator'] = function(test) {
exports['test:remove list item from Iterator'] = function(assert) {
let array = [1, 2, 3, 4], sum = 0;
let fixture = List.compose({
remove: function() this._remove.apply(this, arguments),
}).apply(null, array);
for each (let item in fixture) {
for (let item of fixture) {
sum += item;
fixture.remove(item);
}
test.assertEqual(sum, 1 + 2 + 3 + 4);
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
};
exports['test:clear list from Iterator'] = function(test) {
exports['test:clear list from Iterator'] = function(assert) {
let array = [1, 2, 3, 4], sum = 0;
let fixture = List.compose({
clear: function() this._clear()
}).apply(null, array);
for each (let item in fixture) {
for (let item of fixture) {
sum += item;
fixture.clear();
}
test.assertEqual(sum, 1 + 2 + 3 + 4);
assert.equal(sum, 1 + 2 + 3 + 4, 'sum = 1 + 2 + 3 + 4');
};
require('sdk/test').run(exports);

View File

@ -7,17 +7,24 @@ Object.defineProperty(this, 'global', { value: this });
exports.testGlobals = function(assert) {
// the only globals in module scope should be:
assert.equal(typeof module, 'object', 'have "module" global');
assert.equal(typeof exports, 'object', 'have "exports" global');
assert.equal(typeof require, 'function', 'have "require" global');
assert.equal(typeof dump, 'function', 'have "dump" global');
assert.equal(typeof console, 'object', 'have "console" global');
// module, exports, require, dump, console
assert.equal(typeof module, 'object', 'have "module", good');
assert.equal(typeof exports, 'object', 'have "exports", good');
assert.equal(typeof require, 'function', 'have "require", good');
assert.equal(typeof dump, 'function', 'have "dump", good');
assert.equal(typeof console, 'object', 'have "console", good');
// in particular, these old globals should no longer be present
assert.ok(!('packaging' in global), 'no "packaging" global was found');
assert.ok(!('memory' in global), 'no "memory" global was found');
assert.ok(/test-globals\.js$/.test(module.uri), 'should contain filename');
assert.ok(!('packaging' in global), "no 'packaging', good");
assert.ok(!('memory' in global), "no 'memory', good");
assert.ok(/test-globals\.js$/.test(module.uri),
'should contain filename');
};
require("test").run(exports);
exports.testComponent = function (assert) {
assert.throws(() => {
Components;
}, /`Components` is not available/, 'using `Components` throws');
};
require('test').run(exports);

View File

@ -6,32 +6,32 @@
const { List, addListItem, removeListItem } = require('sdk/util/list');
const { Class } = require('sdk/core/heritage');
exports.testList = function(test) {
exports.testList = function(assert) {
let list = List();
addListItem(list, 1);
for (let key in list) {
test.assertEqual(key, 0, 'key is correct');
test.assertEqual(list[key], 1, 'value is correct');
assert.equal(key, 0, 'key is correct');
assert.equal(list[key], 1, 'value is correct');
}
let count = 0;
for each (let ele in list) {
test.assertEqual(ele, 1, 'ele is correct');
test.assertEqual(++count, 1, 'count is correct');
assert.equal(ele, 1, 'ele is correct');
assert.equal(++count, 1, 'count is correct');
}
count = 0;
for (let ele of list) {
test.assertEqual(ele, 1, 'ele is correct');
test.assertEqual(++count, 1, 'count is correct');
assert.equal(ele, 1, 'ele is correct');
assert.equal(++count, 1, 'count is correct');
}
removeListItem(list, 1);
test.assertEqual(list.length, 0, 'remove worked');
assert.equal(list.length, 0, 'remove worked');
};
exports.testImplementsList = function(test) {
exports.testImplementsList = function(assert) {
let List2 = Class({
implements: [List],
initialize: function() {
@ -42,15 +42,17 @@ exports.testImplementsList = function(test) {
let count = 0;
for each (let ele in list2) {
test.assertEqual(ele, count++, 'ele is correct');
assert.equal(ele, count++, 'ele is correct');
}
count = 0;
for (let ele of list2) {
test.assertEqual(ele, count++, 'ele is correct');
assert.equal(ele, count++, 'ele is correct');
}
addListItem(list2, 3);
test.assertEqual(list2.length, 4, '3 was added');
test.assertEqual(list2[list2.length-1], 3, '3 was added');
assert.equal(list2.length, 4, '3 was added');
assert.equal(list2[list2.length-1], 3, '3 was added');
}
require('sdk/test').run(exports);

View File

@ -1,24 +1,27 @@
/* 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/. */
"use strict";
const tmp = require("sdk/test/tmp-file");
const file = require("sdk/io/file");
const testFolderURL = module.uri.split('test-tmp-file.js')[0];
exports.testCreateFromString = function (test) {
exports.testCreateFromString = function (assert) {
let expectedContent = "foo";
let path = tmp.createFromString(expectedContent);
let content = file.read(path);
test.assertEqual(content, expectedContent,
"Temporary file contains the expected content");
assert.equal(content, expectedContent,
"Temporary file contains the expected content");
}
exports.testCreateFromURL = function (test) {
exports.testCreateFromURL = function (assert) {
let url = testFolderURL + "test-tmp-file.txt";
let path = tmp.createFromURL(url);
let content = file.read(path);
test.assertEqual(content, "foo",
"Temporary file contains the expected content");
assert.equal(content, "foo",
"Temporary file contains the expected content");
}
require("sdk/test").run(exports);

View File

@ -1285,7 +1285,7 @@ nsContextMenu.prototype = {
},
playPlugin: function() {
gPluginHandler.activateSinglePlugin(this.target.ownerDocument.defaultView.top, this.target);
gPluginHandler._showClickToPlayNotification(this.browser, this.target);
},
hidePlugin: function() {

View File

@ -373,4 +373,11 @@ MOCHITEST_BROWSER_FILES += \
$(NULL)
endif
# browser_CTP_context_menu.js fails intermittently on Linux (bug 909342)
ifndef MOZ_WIDGET_GTK
MOCHITEST_BROWSER_FILES += \
browser_CTP_context_menu.js \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,103 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
var gTestBrowser = null;
var gNextTest = null;
var gPluginHost = Components.classes["@mozilla.org/plugin/host;1"].getService(Components.interfaces.nsIPluginHost);
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
clearAllPluginPermissions();
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED;
});
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
let newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
Services.prefs.setBoolPref("plugins.click_to_play", true);
getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
prepareTest(runAfterPluginBindingAttached(test1), gHttpTestRoot + "plugin_test.html");
}
function finishTest() {
clearAllPluginPermissions();
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Due to layout being async, "PluginBindAttached" may trigger later.
// This wraps a function to force a layout flush, thus triggering it,
// and schedules the function execution so they're definitely executed
// afterwards.
function runAfterPluginBindingAttached(func) {
return function() {
let doc = gTestBrowser.contentDocument;
let elems = doc.getElementsByTagName('embed');
if (elems.length < 1) {
elems = doc.getElementsByTagName('object');
}
elems[0].clientTop;
executeSoon(func);
};
}
// Test that the activate action in content menus for CTP plugins works
function test1() {
let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1, Should have a click-to-play notification");
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1, Plugin should not be activated");
window.document.addEventListener("popupshown", test2, false);
EventUtils.synthesizeMouseAtCenter(plugin,
{ type: "contextmenu", button: 2 },
gTestBrowser.contentWindow);
}
function test2() {
window.document.removeEventListener("popupshown", test2, false);
let activate = window.document.getElementById("context-ctp-play");
ok(activate, "Test 2, Should have a context menu entry for activating the plugin");
// Trigger the click-to-play popup
activate.doCommand();
let notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(notification, "Test 2, Should have a click-to-play notification");
ok(!notification.dismissed, "Test 2, The click-to-play notification should not be dismissed");
// Activate the plugin
PopupNotifications.panel.firstChild._primaryButton.click();
let plugin = gTestBrowser.contentDocument.getElementById("test");
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
waitForCondition(() => objLoadingContent.activated, test3, "Waited too long for plugin to activate");
}
function test3() {
finishTest();
}

View File

@ -171,7 +171,7 @@ var tests = {
domwindow.removeEventListener("load", _load, false);
domwindow.addEventListener("unload", function _close(event) {
if (event.target != doc)
if (event.target != doc)
return;
domwindow.removeEventListener("unload", _close, false);
ok(true, "window has been closed");

View File

@ -466,7 +466,8 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let container = document.createElement("hbox");
container.id = "breakpoint-" + aOptions.actor;
container.className = "dbg-breakpoint side-menu-widget-item-other";
container.className = "dbg-breakpoint devtools-monospace" +
" side-menu-widget-item-other";
container.setAttribute("align", "center");
container.setAttribute("flex", "1");
@ -1429,7 +1430,7 @@ WatchExpressionsView.prototype = Heritage.extend(WidgetMethods, {
arrowNode.className = "dbg-expression-arrow";
let inputNode = document.createElement("textbox");
inputNode.className = "plain dbg-expression-input";
inputNode.className = "plain dbg-expression-input devtools-monospace";
inputNode.setAttribute("value", aAttachment.initialExpression);
inputNode.setAttribute("flex", "1");
@ -2194,9 +2195,10 @@ LineResults.prototype = {
let lineLength = 0;
let firstMatch = null;
lineNumberNode.className = "plain dbg-results-line-number";
lineNumberNode.className = "plain dbg-results-line-number devtools-monospace";
lineNumberNode.setAttribute("value", aLineNumber + 1);
lineContentsNode.className = "light list-widget-item dbg-results-line-contents";
lineContentsNode.className = "light list-widget-item devtools-monospace" +
" dbg-results-line-contents";
lineContentsNode.setAttribute("flex", "1");
for (let chunk of this._store) {

View File

@ -347,35 +347,35 @@
value="&debuggerUI.searchPanelOperators;"/>
<hbox align="center">
<button id="global-operator-button"
class="searchbox-panel-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="globalSearchCommand"/>
<label id="global-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="function-operator-button"
class="searchbox-panel-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="functionSearchCommand"/>
<label id="function-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="token-operator-button"
class="searchbox-panel-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="tokenSearchCommand"/>
<label id="token-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="line-operator-button"
class="searchbox-panel-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="lineSearchCommand"/>
<label id="line-operator-label"
class="plain searchbox-panel-operator-label"/>
</hbox>
<hbox align="center">
<button id="variable-operator-button"
class="searchbox-panel-operator-button"
class="searchbox-panel-operator-button devtools-monospace"
command="variableSearchCommand"/>
<label id="variable-operator-label"
class="plain searchbox-panel-operator-label"/>

View File

@ -15,7 +15,6 @@ body {
#header {
-moz-box-sizing: border-box;
font: 12px/16px monospace;
width: 100%;
padding: 6px 9px;
display: -moz-box;
@ -44,7 +43,6 @@ body {
width: calc(100% - 2 * 10px);
position: absolute;
border-width: 1px;
font: 10px/12px monospace;
}
@media (min-width: 320px) {

View File

@ -65,11 +65,12 @@
]]>
</script>
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/layoutview.css" type="text/css"/>
<link rel="stylesheet" href="view.css" type="text/css"/>
</head>
<body class="theme-body">
<body class="theme-body devtools-monospace">
<p id="header">
<span id="element-size"></span>

View File

@ -22,6 +22,10 @@ function test() {
getInplaceEditorForSpan: inplaceEditor
} = devtools.require("devtools/shared/inplace-editor");
// Prevent intermittent "test exceeded the timeout threshold" since this is
// a slow test: https://bugzilla.mozilla.org/show_bug.cgi?id=904953.
requestLongerTimeout(2);
waitForExplicitFinish();
// Will hold the doc we're viewing

View File

@ -288,7 +288,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.url;"/>
<label id="headers-summary-url-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -298,7 +298,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.method;"/>
<label id="headers-summary-method-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -310,7 +310,7 @@
<box id="headers-summary-status-circle"
class="requests-menu-status"/>
<label id="headers-summary-status-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
<button id="headers-summary-resend"
@ -324,7 +324,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.summary.version;"/>
<label id="headers-summary-version-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -364,7 +364,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.name;"/>
<label id="response-content-image-name-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -372,7 +372,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.dimensions;"/>
<label id="response-content-image-dimensions-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -380,7 +380,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.mime;"/>
<label id="response-content-image-mime-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>
@ -388,7 +388,7 @@
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.response.encoding;"/>
<label id="response-content-image-encoding-value"
class="plain tabpanel-summary-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
</hbox>

View File

@ -59,7 +59,8 @@ function AutocompletePopup(aDocument, aOptions = {})
if (!this._panel) {
this._panel = this._document.createElementNS(XUL_NS, "panel");
this._panel.setAttribute("id", id);
this._panel.className = "devtools-autocomplete-popup " + theme + "-theme";
this._panel.className = "devtools-autocomplete-popup devtools-monospace "
+ theme + "-theme";
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("level", "top");

View File

@ -228,6 +228,7 @@ Messages.BaseMessage.prototype = {
let body = doc.createElementNS(XUL_NS, "description");
body.flex = 1;
body.classList.add("webconsole-msg-body");
body.classList.add("devtools-monospace");
container.appendChild(body);
return container;

View File

@ -147,6 +147,8 @@ MOCHITEST_BROWSER_FILES = \
browser_console_navigation_marker.js \
browser_webconsole_bug_762593_insecure_passwords_web_console_warning.js \
browser_webconsole_bug_762593_insecure_passwords_about_blank_web_console_warning.js \
browser_webconsole_allow_mixedcontent_securityerrors.js \
browser_webconsole_block_mixedcontent_securityerrors.js \
head.js \
$(NULL)
@ -254,6 +256,7 @@ MOCHITEST_BROWSER_FILES += \
test-iframe1.html \
test-iframe2.html \
test-iframe3.html \
test-mixedcontent-securityerrors.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// The test loads a web page with mixed active and display content
// on it while the "block mixed content" settings are _off_.
// It then checks that the loading mixed content warning messages
// are logged to the console and have the correct "Learn More"
// url appended to them.
// Bug 875456 - Log mixed content messages from the Mixed Content
// Blocker to the Security Pane in the Web Console
const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/en/Security/MixedContent";
function test()
{
SpecialPowers.pushPrefEnv({"set":
[["security.mixed_content.block_active_content", false],
["security.mixed_content.block_display_content", false]
]}, loadingMixedContentTest);
}
function loadingMixedContentTest()
{
addTab(TEST_URI);
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, function testSecurityErrorLogged (hud) {
waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged mixed active content",
text: "Loading mixed (insecure) active content on a secure page \"http://example.com/\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING
},
{
name: "Logged mixed passive content - image",
text: "Loading mixed (insecure) display content on a secure page \"http://example.com/tests/image/test/mochitest/blue.png\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING
},
],
}).then(() => testClickOpenNewTab(hud));
});
}, true);
}
function testClickOpenNewTab(hud) {
let warningNode = hud.outputNode.querySelector(".webconsole-learn-more-link");
// Invoke the click event and check if a new tab would
// open to the correct page.
let linkOpened = false;
let oldOpenUILinkIn = window.openUILinkIn;
window.openUILinkIn = function(aLink) {
if (aLink == LEARN_MORE_URI) {
linkOpened = true;
}
}
EventUtils.synthesizeMouse(warningNode, 2, 2, {},
warningNode.ownerDocument.defaultView);
ok(linkOpened, "Clicking the Learn More Warning node opens the desired page");
window.openUILinkIn = oldOpenUILinkIn;
finishTest();
}

View File

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// The test loads a web page with mixed active and display content
// on it while the "block mixed content" settings are _on_.
// It then checks that the blocked mixed content warning messages
// are logged to the console and have the correct "Learn More"
// url appended to them. After the first test finishes, it invokes
// a second test that overrides the mixed content blocker settings
// by clicking on the doorhanger shield and validates that the
// appropriate messages are logged to console.
// Bug 875456 - Log mixed content messages from the Mixed Content
// Blocker to the Security Pane in the Web Console
const TEST_URI = "https://example.com/browser/browser/devtools/webconsole/test/test-mixedcontent-securityerrors.html";
const LEARN_MORE_URI = "https://developer.mozilla.org/en/Security/MixedContent";
function test()
{
SpecialPowers.pushPrefEnv({"set": [["security.mixed_content.block_active_content", true],
["security.mixed_content.block_display_content", true]]}, blockMixedContentTest1);
}
function blockMixedContentTest1()
{
addTab(TEST_URI);
browser.addEventListener("load", function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, onLoad, true);
openConsole(null, function testSecurityErrorLogged (hud) {
waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged blocking mixed active content",
text: "Blocked loading mixed active content \"http://example.com/\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_ERROR
},
{
name: "Logged blocking mixed passive content - image",
text: "Blocked loading mixed active content \"http://example.com/\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_ERROR
},
],
}).then(() => {
testClickOpenNewTab(hud);
// Call the second (MCB override) test.
mixedContentOverrideTest2(hud);
});
});
}, true);
}
function mixedContentOverrideTest2(hud)
{
var notification = PopupNotifications.getNotification("mixed-content-blocked", browser);
ok(notification, "Mixed Content Doorhanger didn't appear");
// Click on the doorhanger.
notification.secondaryActions[0].callback();
waitForMessages({
webconsole: hud,
messages: [
{
name: "Logged blocking mixed active content",
text: "Loading mixed (insecure) active content on a secure"+
" page \"http://example.com/\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING
},
{
name: "Logged blocking mixed passive content - image",
text: "Loading mixed (insecure) display content on a secure page"+
" \"http://example.com/tests/image/test/mochitest/blue.png\"",
category: CATEGORY_SECURITY,
severity: SEVERITY_WARNING
},
],
}).then(() => {
testClickOpenNewTab(hud);
finishTest();
});
}
function testClickOpenNewTab(hud) {
let warningNode = hud.outputNode.querySelector(".webconsole-learn-more-link");
// Invoke the click event and check if a new tab would
// open to the correct page.
let linkOpened = false;
let oldOpenUILinkIn = window.openUILinkIn;
window.openUILinkIn = function(aLink) {
if (aLink == LEARN_MORE_URI) {
linkOpened = true;
}
}
EventUtils.synthesizeMouse(warningNode, 2, 2, {},
warningNode.ownerDocument.defaultView);
ok(linkOpened, "Clicking the Learn More Warning node opens the desired page");
window.openUILinkIn = oldOpenUILinkIn;
}

View File

@ -1087,7 +1087,7 @@ function waitForMessages(aOptions)
let partialMatch = !!(aRule.consoleTrace || aRule.consoleTime ||
aRule.consoleTimeEnd || aRule.type);
if (aRule.category && aElement.category != aRule.category) {
if ("category" in aRule && aElement.category != aRule.category) {
if (partialMatch) {
is(aElement.category, aRule.category,
"message category for rule: " + displayRule(aRule));

View File

@ -0,0 +1,21 @@
<!--
Bug 875456 - Log mixed content messages from the Mixed Content Blocker to the
Security Pane in the Web Console
-->
<!DOCTYPE HTML>
<html dir="ltr" xml:lang="en-US" lang="en-US">
<head>
<meta charset="utf8">
<title>Mixed Content test - http on https</title>
<script src="testscript.js"></script>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<iframe src="http://example.com"></iframe>
<img src="http://example.com/tests/image/test/mochitest/blue.png"></img>
</body>
</html>

View File

@ -1446,21 +1446,36 @@ WebConsoleFrame.prototype = {
*/
addMoreInfoLink: function WCF_addMoreInfoLink(aNode, aScriptError)
{
// We have a single category for now, but more are to be
// expected soon
let url;
if (aScriptError.category == "Insecure Password Field") {
this.addInsecurePasswordsWarningNode(aNode);
url = INSECURE_PASSWORDS_LEARN_MORE;
}
else if (aScriptError.category == "Mixed Content Message" ||
aScriptError.category == "Mixed Content Blocker") {
url = MIXED_CONTENT_LEARN_MORE;
}
else {
// Unknown category. Return without adding more info node.
return;
}
this.addLearnMoreWarningNode(aNode, url);
},
/*
* Appends a clickable insecure passwords warning node to the node passed
* Appends a clickable warning node to the node passed
* as a parameter to the function. When a user clicks on the appended
* warning node, the browser navigates to a page where the user can learn
* more about security issues associated with insecure passwords.
* warning node, the browser navigates to the provided url.
*
* @param aNode
* The node to which we will be adding a clickable warning node.
* @param aURL
* The url which points to the page where the user can learn more
* about security issues associated with the specific message that's
* being logged.
*/
addInsecurePasswordsWarningNode:
function WCF_addInsecurePasswordsWarningNode(aNode)
addLearnMoreWarningNode:
function WCF_addLearnMoreWarningNode(aNode, aURL)
{
let moreInfoLabel =
"[" + l10n.getStr("webConsoleMoreInfoLabel") + "]";
@ -1472,7 +1487,7 @@ WebConsoleFrame.prototype = {
linkNode.classList.add("webconsole-msg-link");
aNode.appendChild(linkNode);
// Create the actual insecure passwords warning node and make it clickable
// Create the actual warning node and make it clickable
let warningNode = this.document.createElement("label");
warningNode.setAttribute("value", moreInfoLabel);
warningNode.setAttribute("title", moreInfoLabel);
@ -1480,7 +1495,7 @@ WebConsoleFrame.prototype = {
warningNode.classList.add("webconsole-learn-more-link");
warningNode.addEventListener("click", function(aEvent) {
this.owner.openLink(INSECURE_PASSWORDS_LEARN_MORE);
this.owner.openLink(aURL);
aEvent.preventDefault();
aEvent.stopPropagation();
}.bind(this));
@ -2304,6 +2319,7 @@ WebConsoleFrame.prototype = {
let bodyNode = this.document.createElementNS(XUL_NS, "description");
bodyNode.flex = 1;
bodyNode.classList.add("webconsole-msg-body");
bodyNode.classList.add("devtools-monospace");
// Store the body text, since it is needed later for the variables view.
let body = aBody;
@ -2350,6 +2366,8 @@ WebConsoleFrame.prototype = {
// Create the timestamp.
let timestampNode = this.document.createElementNS(XUL_NS, "label");
timestampNode.classList.add("webconsole-timestamp");
timestampNode.classList.add("devtools-monospace");
let timestamp = aTimeStamp || Date.now();
let timestampString = l10n.timestampString(timestamp);
timestampNode.setAttribute("value", timestampString);
@ -2574,6 +2592,7 @@ WebConsoleFrame.prototype = {
locationNode.setAttribute("tooltiptext", aSourceURL);
locationNode.classList.add("webconsole-location");
locationNode.classList.add("text-link");
locationNode.classList.add("devtools-monospace");
// Make the location clickable.
locationNode.addEventListener("click", () => {
@ -4547,6 +4566,7 @@ var Utils = {
return CATEGORY_CSS;
case "Mixed Content Blocker":
case "Mixed Content Message":
case "CSP":
case "Invalid HSTS Headers":
case "Insecure Password Field":

View File

@ -169,9 +169,10 @@ function goUpdateConsoleCommands() {
<hbox class="jsterm-input-container" style="direction:ltr">
<stack class="jsterm-stack-node" flex="1">
<textbox class="jsterm-complete-node" multiline="true" rows="1"
tabindex="-1"/>
<textbox class="jsterm-input-node" multiline="true" rows="1" tabindex="0"/>
<textbox class="jsterm-complete-node devtools-monospace"
multiline="true" rows="1" tabindex="-1"/>
<textbox class="jsterm-input-node devtools-monospace"
multiline="true" rows="1" tabindex="0"/>
</stack>
</hbox>
</vbox>

View File

@ -598,7 +598,7 @@ var BrowserUI = {
}
break;
case "metro_viewstate_changed":
this._adjustDOMforViewState();
this._adjustDOMforViewState(aData);
if (aData == "snapped") {
FlyoutPanelsUI.hide();
Elements.autocomplete.setAttribute("orient", "vertical");
@ -646,9 +646,9 @@ var BrowserUI = {
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
},
_adjustDOMforViewState: function() {
if (MetroUtils.immersive) {
let currViewState = "";
_adjustDOMforViewState: function(aState) {
let currViewState = aState;
if (!currViewState && MetroUtils.immersive) {
switch (MetroUtils.snappedState) {
case Ci.nsIWinMetroUtils.fullScreenLandscape:
currViewState = "landscape";
@ -663,8 +663,9 @@ var BrowserUI = {
currViewState = "snapped";
break;
}
Elements.windowState.setAttribute("viewstate", currViewState);
}
Elements.windowState.setAttribute("viewstate", currViewState);
},
_titleChanged: function(aBrowser) {

View File

@ -415,8 +415,7 @@
#if MOZ_UPDATE_CHANNEL != release
#ifdef MOZ_UPDATER
<description class="text-blurb" id="currentChannelText">&channel.description.start;<label id="currentChannel"/></description>
<description class="text-blurb" id="currentChannelText2">&channel.description.end;</description>
<description class="text-blurb" id="currentChannelText">&channel.description.start;<label id="currentChannel"/>&channel.description.end;</description>
#endif
#endif
<label id="about-policy-label"

View File

@ -109,9 +109,9 @@ var StartUI = {
}
},
_adjustDOMforViewState: function() {
if (this.chromeWin.MetroUtils.immersive) {
let currViewState = "";
_adjustDOMforViewState: function(aState) {
let currViewState = aState;
if (!currViewState && this.chromeWin.MetroUtils.immersive) {
switch (this.chromeWin.MetroUtils.snappedState) {
case Ci.nsIWinMetroUtils.fullScreenLandscape:
currViewState = "landscape";
@ -126,19 +126,20 @@ var StartUI = {
currViewState = "snapped";
break;
}
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
if (currViewState == "snapped") {
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
} else {
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
}
}
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
if (currViewState == "snapped") {
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
} else {
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
}
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_viewstate_changed":
this._adjustDOMforViewState();
this._adjustDOMforViewState(aData);
break;
}
}

View File

@ -12,10 +12,11 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_METRO_FILES = \
head.js \
browser_urlbar.js \
helpers/ViewStateHelper.js \
browser_bookmarks.js \
browser_canonizeURL.js \
browser_circular_progress_indicator.js \
browser_crashprompt.js \
browser_context_menu_tests.js \
browser_context_menu_tests_01.html \
browser_context_menu_tests_02.html \
@ -25,21 +26,22 @@ MOCHITEST_METRO_FILES = \
browser_downloads.js \
browser_findbar.js \
browser_findbar.html \
browser_form_auto_complete.js \
browser_form_auto_complete.html \
browser_history.js \
browser_inputsource.js \
browser_onscreen_keyboard.js \
browser_onscreen_keyboard.html \
browser_prefs_ui.js \
browser_progress_indicator.xul \
browser_remotetabs.js \
browser_snappedState.js \
browser_tabs.js \
browser_test.js \
browser_tiles.js \
browser_tilegrid.xul \
browser_topsites.js \
browser_form_auto_complete.js \
browser_form_auto_complete.html \
browser_crashprompt.js \
browser_inputsource.js \
browser_urlbar.js \
$(NULL)
ifndef MOZ_DEBUG

View File

@ -0,0 +1,119 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
var gStartDoc = null;
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_snapped_tests need landscape mode to run.");
return;
}
runTests();
}
function showStartUI() {
if (!BrowserUI.isStartTabVisible) {
let tab = yield addTab("about:start");
gStartDoc = tab.browser.contentWindow.document;
} else {
gStartDoc = Browser.selectedBrowser.contentWindow.document;
}
}
function setUpSnapped() {
yield showStartUI();
yield setSnappedViewstate();
}
function setUpPortrait() {
yield showStartUI();
yield setPortraitViewstate();
}
function getNarrowTitle(aVboxId) {
let vbox = gStartDoc.getElementById(aVboxId);
return vbox.querySelector(".narrow-title");
}
function narrowTitleVisible(aVboxId) {
let title = getNarrowTitle(aVboxId);
let display = getComputedStyle(title).getPropertyValue("display");
return display !== "none";
}
function wideTitleVisible(aVboxId) {
let vbox = gStartDoc.getElementById(aVboxId);
let title = vbox.querySelector(".wide-title");
let display = getComputedStyle(title).getPropertyValue("display");
return display !== "none";
}
gTests.push({
desc: "Test Snapped titles",
setUp: setUpSnapped,
run: function() {
ok(narrowTitleVisible("start-topsites"), "topsites narrow title is visible");
ok(narrowTitleVisible("start-bookmarks"), "bookmarks narrow title is visible");
ok(narrowTitleVisible("start-history"), "history narrow title is visible");
ok(!wideTitleVisible("start-topsites"), "topsites wide title is not visible");
ok(!wideTitleVisible("start-bookmarks"), "bookmarks wide title is not visible");
ok(!wideTitleVisible("start-history"), "history wide title is not visible");
},
tearDown: restoreViewstate
});
gTests.push({
desc: "Test Snapped titles",
setUp: setUpSnapped,
run: function() {
let topsites = gStartDoc.getElementById("start-topsites");
let bookmarks = gStartDoc.getElementById("start-bookmarks");
let history = gStartDoc.getElementById("start-history");
ok(topsites.hasAttribute("expanded"), "topsites is expanded");
ok(!bookmarks.hasAttribute("expanded"), "bookmarks is collapsed");
ok(!history.hasAttribute("expanded"), "history is collapsed");
// Expand bookmarks
sendElementTap(Browser.selectedBrowser.contentWindow, getNarrowTitle("start-bookmarks"));
yield waitForCondition(() => bookmarks.hasAttribute("expanded"));
ok(!topsites.hasAttribute("expanded"), "topsites is collapsed");
ok(bookmarks.hasAttribute("expanded"), "bookmarks is expanded");
ok(!history.hasAttribute("expanded"), "history is collapsed");
},
tearDown: restoreViewstate
});
gTests.push({
desc: "Test Snapped scrolls vertically",
setUp: setUpSnapped,
run: function() {
todo(false, "We need to populate startUI to verify that it's scrollable");
},
tearDown: restoreViewstate
});
gTests.push({
desc: "Test Portrait titles",
setUp: setUpPortrait,
run: function() {
// Check title visibility
ok(!narrowTitleVisible("start-topsites"), "topsites narrow title is not visible");
ok(!narrowTitleVisible("start-bookmarks"), "bookmarks narrow title is not visible");
ok(!narrowTitleVisible("start-history"), "history narrow title is not visible");
ok(wideTitleVisible("start-topsites"), "topsites wide title is visible");
ok(wideTitleVisible("start-bookmarks"), "bookmarks wide title is visible");
ok(wideTitleVisible("start-history"), "history wide title is visible");
},
tearDown: restoreViewstate
});

View File

@ -18,6 +18,27 @@ const chromeRoot = getRootDirectory(gTestPath);
const kDefaultWait = 2000;
const kDefaultInterval = 50;
/*=============================================================================
Load Helpers
=============================================================================*/
let splitPath = chromeRoot.split('/');
if (!splitPath[splitPath.length-1]) {
splitPath.pop();
}
// ../mochitest to make sure we're looking for the libs on the right path
// even for mochiperf tests.
splitPath.pop();
splitPath.push('mochitest');
const mochitestPath = splitPath.join('/') + '/';
[
"ViewStateHelper.js"
].forEach(function(lib) {
Services.scriptloader.loadSubScript(mochitestPath + lib, this);
}, this);
/*=============================================================================
Metro ui helpers
=============================================================================*/
@ -147,7 +168,7 @@ function getSelection(aElement) {
// browser
return aElement.contentWindow.getSelection();
};
}
function getTrimmedSelection(aElement) {
let sel = getSelection(aElement);
@ -841,7 +862,7 @@ function stubMethod(aObj, aMethod) {
let func = function() {
func.calledWith = Array.slice(arguments);
func.callCount++;
}
};
func.callCount = 0;
func.restore = function() {
return (aObj[aMethod] = origFunc);

View File

@ -0,0 +1,53 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* 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/. */
"use strict";
const snappedSize = 330;
const portraitSize = 660;
function setSnappedViewstate() {
ok(isLandscapeMode(), "setSnappedViewstate expects landscape mode to work.");
// Communicate viewstate change
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'snapped');
let browser = Browser.selectedBrowser;
// Reduce browser width to simulate small screen size.
let fullWidth = browser.clientWidth;
let padding = fullWidth - snappedSize;
browser.style.borderRight = padding + "px solid gray";
// Make sure it renders the new mode properly
yield waitForMs(0);
}
function setPortraitViewstate() {
ok(isLandscapeMode(), "setPortraitViewstate expects landscape mode to work.");
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'portrait');
let browser = Browser.selectedBrowser;
let fullWidth = browser.clientWidth;
let padding = fullWidth - portraitSize;
browser.style.borderRight = padding + "px solid gray";
// Make sure it renders the new mode properly
yield waitForMs(0);
}
function restoreViewstate() {
ok(isLandscapeMode(), "restoreViewstate expects landscape mode to work.");
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'landscape');
Browser.selectedBrowser.style.removeProperty("border-right");
yield waitForMs(0);
}

View File

@ -792,3 +792,8 @@ appbar toolbar[labelled] toolbarbutton > .toolbarbutton-text {
.appbar-secondary {
list-style-image: url(chrome://browser/skin/images/appbar-icons.png);
}
.flyout-narrow description,
.flyout-narrow label {
max-width: 266px; /* Accounts for a 40px padding on each side of the flyout */
}

View File

@ -455,10 +455,10 @@ SocialErrorListener.prototype = {
},
onLocationChange: function SPL_onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
let failure = aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE;
if (failure && Social.provider.errorState != "frameworker-error") {
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
Social.provider.errorState = "content-error";
if (!Social.provider.errorState)
Social.provider.errorState = "content-error";
schedule(function() {
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler);

View File

@ -114,9 +114,15 @@ this.webappsUI = {
DOMApplicationRegistry.confirmInstall(aData, false, localDir, null,
function (aManifest) {
if (WebappsInstaller.install(aData, aManifest)) {
installationSuccessNotification(aData, app, chromeWin);
}
WebappsInstaller.install(aData, aManifest).then(
function() {
installationSuccessNotification(aData, app, chromeWin);
},
function(error) {
Cu.reportError("Error installing webapp: " + error);
// TODO: Notify user that the installation has failed
}
);
}
);
} else {

View File

@ -11,7 +11,7 @@
.devtools-monospace {
font-family: monospace;
font-size: 85%;
font-size: 80%;
}
/* Toolbar and Toolbar items */

View File

@ -132,7 +132,6 @@
/* Sources and breakpoints view */
.dbg-breakpoint {
font-family: monospace;
-moz-margin-start: -14px;
}
@ -164,7 +163,6 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
font-family: Menlo, Monaco, monospace;
}
/* Searchbox and the search operations help panel */
@ -191,7 +189,6 @@
-moz-margin-start: 2px;
-moz-margin-end: 6px;
text-align: center;
font-family: Menlo, Monaco, monospace;
}
.searchbox-panel-operator-label {
@ -289,7 +286,6 @@
-moz-padding-end: 4px;
padding-top: 2px;
text-align: end;
font-family: monospace;
color: #8c8c8c;
}
@ -297,7 +293,6 @@
-moz-padding-start: 4px;
padding-top: 1px;
padding-bottom: 1px;
font-family: monospace;
}
.dbg-results-line-contents-string {

View File

@ -8,7 +8,7 @@ body {
}
#all-fonts {
padding: 0 5px;
padding: 0;
margin: 0;
}
@ -23,8 +23,7 @@ body {
}
.font {
padding: 10px 5px;
font-size: 0;
padding: 10px 10px;
}
.theme-dark .font {
@ -51,7 +50,6 @@ body {
}
.font-info {
font-size: 1rem;
display: block;
}

View File

@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
.variable-or-property:not(:focus) > .title > .token-string {

View File

@ -4,20 +4,6 @@
%include ../../shared/devtools/webconsole.inc.css
.webconsole-timestamp,
.webconsole-msg-body {
font-family: "DejaVu Sans Mono", monospace;
}
.jsterm-input-node,
.jsterm-complete-node {
font: 0.9em "DejaVu Sans Mono", monospace;
}
.hud-output-node {
font-size: 0.9em;
}
.jsterm-input-node {
width: 98%;
}

View File

@ -13,6 +13,7 @@
.devtools-monospace {
font-family: monospace;
font-size: 108%;
}
/* Toolbar and Toolbar items */

View File

@ -130,7 +130,6 @@
/* Sources and breakpoints view */
.dbg-breakpoint {
font-family: monospace;
-moz-margin-start: -14px;
}
@ -162,7 +161,6 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
font-family: Menlo, Monaco, monospace;
}
/* Searchbox and the search operations help panel */
@ -189,7 +187,6 @@
-moz-margin-start: 2px;
-moz-margin-end: 6px;
text-align: center;
font-family: Menlo, Monaco, monospace;
}
.searchbox-panel-operator-label {
@ -287,7 +284,6 @@
-moz-padding-end: 4px;
padding-top: 2px;
text-align: end;
font-family: monospace;
color: #8c8c8c;
}
@ -295,7 +291,6 @@
-moz-padding-start: 4px;
padding-top: 1px;
padding-bottom: 1px;
font-family: monospace;
}
.dbg-results-line-contents-string {

View File

@ -8,7 +8,7 @@ body {
}
#all-fonts {
padding: 0 5px;
padding: 0;
margin: 0;
}
@ -23,8 +23,7 @@ body {
}
.font {
padding: 10px 5px;
font-size: 0;
padding: 10px 10px;
}
.theme-dark .font {
@ -51,7 +50,6 @@ body {
}
.font-info {
font-size: 1rem;
display: block;
}

View File

@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
.variable-or-property:not(:focus) > .title > .token-string {

View File

@ -3,16 +3,4 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../shared.inc
%include ../../shared/devtools/webconsole.inc.css
/* General output styles */
.webconsole-timestamp,
.webconsole-msg-body {
font-family: Menlo, Monaco, monospace;
}
.jsterm-input-node,
.jsterm-complete-node {
font: 1em Menlo, Monaco, monospace;
}
%include ../../shared/devtools/webconsole.inc.css

View File

@ -8,7 +8,6 @@
color: GrayText;
margin-top: 0;
margin-bottom: 0;
font-family: monospace;
}
.hud-msg-node {
@ -33,7 +32,6 @@
-moz-margin-start: 3px;
-moz-margin-end: 6px;
white-space: pre-wrap;
font-family: monospace;
}
.webconsole-msg-body-piece {
@ -93,11 +91,6 @@
background: white;
}
.jsterm-input-node,
.jsterm-complete-node {
font-family: monospace;
}
.hud-output-node {
-moz-appearance: none;
border-bottom: 1px solid ThreeDShadow;

View File

@ -128,7 +128,6 @@
/* Sources and breakpoints view */
.dbg-breakpoint {
font-family: monospace;
-moz-margin-start: -14px;
}
@ -160,7 +159,6 @@
.dbg-expression-input {
-moz-padding-start: 2px !important;
font-family: Menlo, Monaco, monospace;
}
/* Searchbox and the search operations help panel */
@ -187,7 +185,6 @@
-moz-margin-start: 2px;
-moz-margin-end: 6px;
text-align: center;
font-family: Menlo, Monaco, monospace;
}
.searchbox-panel-operator-label {
@ -285,7 +282,6 @@
-moz-padding-end: 4px;
padding-top: 2px;
text-align: end;
font-family: monospace;
color: #8c8c8c;
}
@ -293,7 +289,6 @@
-moz-padding-start: 4px;
padding-top: 1px;
padding-bottom: 1px;
font-family: monospace;
}
.dbg-results-line-contents-string {

View File

@ -8,7 +8,7 @@ body {
}
#all-fonts {
padding: 0 5px;
padding: 0;
margin: 0;
}
@ -23,8 +23,7 @@ body {
}
.font {
padding: 10px 5px;
font-size: 0;
padding: 10px 10px;
}
.theme-dark .font {
@ -51,7 +50,6 @@ body {
}
.font-info {
font-size: 1rem;
display: block;
}

View File

@ -365,7 +365,6 @@ box.requests-menu-status[code^="5"] {
.tabpanel-summary-value {
-moz-padding-start: 3px;
font-family: Menlo, Monaco, monospace;
}
.variable-or-property:not(:focus) > .title > .token-string {

View File

@ -4,13 +4,6 @@
%include ../../shared/devtools/webconsole.inc.css
.webconsole-timestamp,
.webconsole-msg-body,
.jsterm-input-node,
.jsterm-complete-node {
font-family: Consolas, Lucida Console, monospace;
}
/*
* This hardcoded width likely due to a toolkit Windows specific bug.
* See http://hg.mozilla.org/mozilla-central/annotate/f38d6df93cad/toolkit/themes/winstripe/global/textbox-aero.css#l7

View File

@ -48,22 +48,6 @@ public interface Actions {
*/
void sendGeckoEvent(String geckoEvent, String data);
/**
* Sends a preferences get event to Gecko.
*
* @param requestId The id of this request.
* @param prefNames The preferences being requested.
*/
void sendPreferencesGetEvent(int requestId, String[] prefNames);
/**
* Sends a preferences observe event to Gecko.
*
* @param requestId The id of this request.
* @param prefNames The preferences being requested.
*/
void sendPreferencesObserveEvent(int requestId, String[] prefNames);
/**
* Listens for a gecko event to be sent from the Gecko instance.
* The returned object can be used to test if the event has been

View File

@ -44,8 +44,6 @@ public class FennecNativeActions implements Actions {
private Method mRegisterEventListener;
private Method mUnregisterEventListener;
private Method mBroadcastEvent;
private Method mPreferencesGetEvent;
private Method mPreferencesObserveEvent;
private Method mSetDrawListener;
private Method mQuerySql;
private Object mRobocopApi;
@ -68,8 +66,6 @@ public class FennecNativeActions implements Actions {
mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
mUnregisterEventListener = mApiClass.getMethod("unregisterEventListener", String.class, mEventListenerClass);
mBroadcastEvent = mApiClass.getMethod("broadcastEvent", String.class, String.class);
mPreferencesGetEvent = mApiClass.getMethod("preferencesGetEvent", Integer.TYPE, String[].class);
mPreferencesObserveEvent = mApiClass.getMethod("preferencesObserveEvent", Integer.TYPE, String[].class);
mSetDrawListener = mApiClass.getMethod("setDrawListener", mDrawListenerClass);
mQuerySql = mApiClass.getMethod("querySql", String.class, String.class);
@ -269,24 +265,6 @@ public class FennecNativeActions implements Actions {
}
}
private void sendPreferencesEvent(Method method, int requestId, String[] prefNames) {
try {
method.invoke(mRobocopApi, requestId, prefNames);
} catch (IllegalAccessException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
} catch (InvocationTargetException e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
}
public void sendPreferencesGetEvent(int requestId, String[] prefNames) {
sendPreferencesEvent(mPreferencesGetEvent, requestId, prefNames);
}
public void sendPreferencesObserveEvent(int requestId, String[] prefNames) {
sendPreferencesEvent(mPreferencesObserveEvent, requestId, prefNames);
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;

View File

@ -200,7 +200,7 @@ class FileKind(object):
if filename.endswith('.cpp'):
return FileKind.CPP
if filename.endswith(('inlines.h', '-inl.h')):
if filename.endswith(('inlines.h', '-inl.h', 'Inlines.h')):
return FileKind.INL_H
if filename.endswith('.h'):

View File

@ -31,6 +31,11 @@
using namespace mozilla;
enum nsMixedContentBlockerMessageType {
eBlocked = 0x00,
eUserOverride = 0x01
};
// Is mixed script blocking (fonts, plugin content, scripts, stylesheets,
// iframes, websockets, XHR) enabled?
bool nsMixedContentBlocker::sBlockMixedScript = false;
@ -147,22 +152,42 @@ nsMixedContentBlocker::~nsMixedContentBlocker()
NS_IMPL_ISUPPORTS1(nsMixedContentBlocker, nsIContentPolicy)
void
LogBlockingMixedContent(MixedContentTypes classification,
nsIURI* aContentLocation,
nsIDocument* aRootDoc)
static void
LogMixedContentMessage(MixedContentTypes aClassification,
nsIURI* aContentLocation,
nsIDocument* aRootDoc,
nsMixedContentBlockerMessageType aMessageType)
{
nsAutoCString messageCategory;
uint32_t severityFlag;
nsAutoCString messageLookupKey;
if (aMessageType == eBlocked) {
severityFlag = nsIScriptError::errorFlag;
messageCategory.AssignLiteral("Mixed Content Blocker");
if (aClassification == eMixedDisplay) {
messageLookupKey.AssignLiteral("BlockMixedDisplayContent");
} else {
messageLookupKey.AssignLiteral("BlockMixedActiveContent");
}
} else {
severityFlag = nsIScriptError::warningFlag;
messageCategory.AssignLiteral("Mixed Content Message");
if (aClassification == eMixedDisplay) {
messageLookupKey.AssignLiteral("LoadingMixedDisplayContent");
} else {
messageLookupKey.AssignLiteral("LoadingMixedActiveContent");
}
}
nsAutoCString locationSpec;
aContentLocation->GetSpec(locationSpec);
NS_ConvertUTF8toUTF16 locationSpecUTF16(locationSpec);
const PRUnichar* strings[] = { locationSpecUTF16.get() };
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
NS_LITERAL_CSTRING("Mixed Content Blocker"),
aRootDoc,
nsContentUtils::ReportToConsole(severityFlag, messageCategory, aRootDoc,
nsContentUtils::eSECURITY_PROPERTIES,
classification == eMixedDisplay ? "BlockMixedDisplayContent" : "BlockMixedActiveContent",
strings, ArrayLength(strings));
messageLookupKey.get(), strings, ArrayLength(strings));
}
NS_IMETHODIMP
@ -453,6 +478,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
// If the content is display content, and the pref says display content should be blocked, block it.
if (sBlockMixedDisplay && classification == eMixedDisplay) {
if (allowMixedContent) {
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
*aDecision = nsIContentPolicy::ACCEPT;
rootDoc->SetHasMixedActiveContentLoaded(true);
if (!rootDoc->GetHasMixedDisplayContentLoaded() && NS_SUCCEEDED(stateRV)) {
@ -460,7 +486,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
}
} else {
*aDecision = nsIContentPolicy::REJECT_REQUEST;
LogBlockingMixedContent(classification, aContentLocation, rootDoc);
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
if (!rootDoc->GetHasMixedDisplayContentBlocked() && NS_SUCCEEDED(stateRV)) {
eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_BLOCKED_MIXED_DISPLAY_CONTENT));
}
@ -471,6 +497,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
// If the content is active content, and the pref says active content should be blocked, block it
// unless the user has choosen to override the pref
if (allowMixedContent) {
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
*aDecision = nsIContentPolicy::ACCEPT;
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
if (rootDoc->GetHasMixedActiveContentLoaded()) {
@ -501,7 +528,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
} else {
//User has not overriden the pref by Disabling protection. Reject the request and update the security state.
*aDecision = nsIContentPolicy::REJECT_REQUEST;
LogBlockingMixedContent(classification, aContentLocation, rootDoc);
LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
// See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
if (rootDoc->GetHasMixedActiveContentBlocked()) {
return NS_OK;
@ -519,6 +546,9 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
} else {
// The content is not blocked by the mixed content prefs.
// Log a message that we are loading mixed content.
LogMixedContentMessage(classification, aContentLocation, rootDoc, eUserOverride);
// Fire the event from a script runner as it is unsafe to run script
// from within ShouldLoad
nsContentUtils::AddScriptRunner(

View File

@ -547,7 +547,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
sNumLivingContexts++;
SetIsDOMBinding();
#if USE_SKIA_GPU
#ifdef USE_SKIA_GPU
mForceSoftware = false;
#endif
}
@ -564,10 +564,8 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D()
NS_IF_RELEASE(sErrorTarget);
}
#if USE_SKIA_GPU
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(DemotableContexts().begin(), DemotableContexts().end(), this);
if (iter != DemotableContexts().end())
DemotableContexts().erase(iter);
#ifdef USE_SKIA_GPU
RemoveDemotableContext(this);
#endif
}
@ -746,13 +744,14 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
Redraw(newr);
}
#if USE_SKIA_GPU
void CanvasRenderingContext2D::Demote()
{
#ifdef USE_SKIA_GPU
if (!IsTargetValid() || mForceSoftware)
return;
RemoveDemotableContext(this);
RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
RefPtr<DrawTarget> oldTarget = mTarget;
mTarget = nullptr;
@ -764,11 +763,21 @@ void CanvasRenderingContext2D::Demote()
if (!IsTargetValid())
return;
// Put back the content from the old DrawTarget
// Restore the content from the old DrawTarget
mgfx::Rect r(0, 0, mWidth, mHeight);
mTarget->DrawSurface(snapshot, r, r);
// Restore the clips and transform
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
mTarget->PushClip(CurrentState().clipsPushed[i]);
}
mTarget->SetTransform(oldTarget->GetTransform());
#endif
}
#ifdef USE_SKIA_GPU
std::vector<CanvasRenderingContext2D*>&
CanvasRenderingContext2D::DemotableContexts()
{
@ -790,8 +799,6 @@ CanvasRenderingContext2D::DemoteOldestContextIfNecessary()
return;
CanvasRenderingContext2D* oldest = contexts.front();
contexts.erase(contexts.begin());
oldest->Demote();
}
@ -805,6 +812,14 @@ CanvasRenderingContext2D::AddDemotableContext(CanvasRenderingContext2D* context)
DemotableContexts().push_back(context);
}
void
CanvasRenderingContext2D::RemoveDemotableContext(CanvasRenderingContext2D* context)
{
std::vector<CanvasRenderingContext2D*>::iterator iter = std::find(DemotableContexts().begin(), DemotableContexts().end(), context);
if (iter != DemotableContexts().end())
DemotableContexts().erase(iter);
}
#define MIN_SKIA_GL_DIMENSION 16
bool

View File

@ -367,6 +367,8 @@ public:
double h, const nsAString& bgColor, uint32_t flags,
mozilla::ErrorResult& error);
void Demote();
nsresult Redraw();
// nsICanvasRenderingContextInternal
@ -567,13 +569,11 @@ protected:
}
#if USE_SKIA_GPU
// Recreate the DrawTarget in software mode
void Demote();
static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
static void DemoteOldestContextIfNecessary();
static void AddDemotableContext(CanvasRenderingContext2D* context);
static void RemoveDemotableContext(CanvasRenderingContext2D* context);
// Do not use GL
bool mForceSoftware;

View File

@ -9,6 +9,7 @@
#include "mozilla/Telemetry.h"
using namespace mozilla;
using namespace mozilla::gl;
// -----------------------------------------------------------------------------
// CONSTRUCTOR & DESTRUCTOR
@ -51,3 +52,76 @@ WebGL2Context::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
return dom::WebGL2RenderingContextBinding::Wrap(cx, scope, this);
}
// -----------------------------------------------------------------------------
// WebGL 2 initialisation
bool
WebGLContext::InitWebGL2()
{
MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!");
const WebGLExtensionID sExtensionNativelySupportedArr[] = {
ANGLE_instanced_arrays,
OES_element_index_uint,
OES_standard_derivatives,
OES_texture_float,
OES_texture_float_linear,
OES_vertex_array_object,
WEBGL_depth_texture,
WEBGL_draw_buffers
};
const GLFeature::Enum sFeatureRequiredArr[] = {
GLFeature::blend_minmax,
GLFeature::transform_feedback
};
// check WebGL extensions that are supposed to be natively supported
for (size_t i = 0; i < size_t(MOZ_ARRAY_LENGTH(sExtensionNativelySupportedArr)); i++)
{
WebGLExtensionID extension = sExtensionNativelySupportedArr[i];
if (!IsExtensionSupported(extension)) {
GenerateWarning("WebGL 2 requires %s!", GetExtensionString(extension));
return false;
}
}
// check required OpenGL extensions
if (!gl->IsExtensionSupported(GLContext::EXT_gpu_shader4)) {
GenerateWarning("WebGL 2 requires GL_EXT_gpu_shader4!");
return false;
}
// check OpenGL features
if (!gl->IsSupported(GLFeature::occlusion_query) &&
!gl->IsSupported(GLFeature::occlusion_query_boolean))
{
/*
* on desktop, we fake occlusion_query_boolean with occlusion_query if
* necessary. See WebGLContextAsyncQueries.cpp.
*/
GenerateWarning("WebGL 2 requires occlusion queries!");
return false;
}
for (size_t i = 0; i < size_t(MOZ_ARRAY_LENGTH(sFeatureRequiredArr)); i++)
{
if (!gl->IsSupported(sFeatureRequiredArr[i])) {
GenerateWarning("WebGL 2 requires GLFeature::%s!", GLContext::GetFeatureName(sFeatureRequiredArr[i]));
return false;
}
}
// ok WebGL 2 is compatible, we can enable natively supported extensions.
for (size_t i = 0; i < size_t(MOZ_ARRAY_LENGTH(sExtensionNativelySupportedArr)); i++) {
EnableExtension(sExtensionNativelySupportedArr[i]);
MOZ_ASSERT(IsExtensionEnabled(sExtensionNativelySupportedArr[i]));
}
// we initialise WebGL 2 related stuff.
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs);
return true;
}

View File

@ -615,6 +615,7 @@ WebGLContext::Render(gfxContext *ctx, gfxPattern::GraphicsFilter f, uint32_t aFl
} else if (srcPremultAlpha && !dstPremultAlpha) {
gfxUtils::UnpremultiplyImageSurface(surf);
}
surf->MarkDirty();
nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
pat->SetFilter(f);
@ -913,11 +914,6 @@ WebGLContext::GetContextAttributes(Nullable<dom::WebGLContextAttributesInitializ
result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
}
bool
WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
return mExtensions.SafeElementAt(ext);
}
/* [noscript] DOMString mozGetUnderlyingParamString(in WebGLenum pname); */
NS_IMETHODIMP
WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
@ -947,245 +943,6 @@ WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
return NS_OK;
}
bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const
{
// Chrome contexts need access to debug information even when
// webgl.disable-extensions is set. This is used in the graphics
// section of about:support.
if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
switch (ext) {
case WEBGL_debug_renderer_info:
return true;
default:
// For warnings-as-errors.
break;
}
}
return IsExtensionSupported(ext);
}
bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
if (mDisableExtensions) {
return false;
}
switch (ext) {
case OES_element_index_uint:
return gl->IsSupported(GLFeature::element_index_uint);
case OES_standard_derivatives:
return gl->IsSupported(GLFeature::standard_derivatives);
case WEBGL_lose_context:
// We always support this extension.
return true;
case OES_texture_float:
return gl->IsSupported(GLFeature::texture_float);
case OES_texture_float_linear:
return gl->IsSupported(GLFeature::texture_float_linear);
case OES_vertex_array_object:
return WebGLExtensionVertexArray::IsSupported(this);
case EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
case WEBGL_compressed_texture_s3tc:
if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc)) {
return true;
}
else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) &&
gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5))
{
return true;
}
return false;
case WEBGL_compressed_texture_atc:
return gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture);
case WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc);
case WEBGL_depth_texture:
return gl->IsSupported(GLFeature::packed_depth_stencil) &&
gl->IsSupported(GLFeature::depth_texture);
case ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
if (Preferences::GetBool("webgl.enable-draft-extensions", false) || IsWebGL2()) {
switch (ext) {
case WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
}
return false;
}
static bool
CompareWebGLExtensionName(const nsACString& name, const char *other)
{
return name.Equals(other, nsCaseInsensitiveCStringComparator());
}
JSObject*
WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& rv)
{
if (!IsContextStable())
return nullptr;
NS_LossyConvertUTF16toASCII name(aName);
WebGLExtensionID ext = WebGLExtensionID_unknown_extension;
// step 1: figure what extension is wanted
if (CompareWebGLExtensionName(name, "OES_element_index_uint"))
{
ext = OES_element_index_uint;
}
else if (CompareWebGLExtensionName(name, "OES_texture_float"))
{
ext = OES_texture_float;
}
else if (CompareWebGLExtensionName(name, "OES_texture_float_linear"))
{
ext = OES_texture_float_linear;
}
else if (CompareWebGLExtensionName(name, "OES_vertex_array_object"))
{
ext = OES_vertex_array_object;
}
else if (CompareWebGLExtensionName(name, "OES_standard_derivatives"))
{
ext = OES_standard_derivatives;
}
else if (CompareWebGLExtensionName(name, "EXT_texture_filter_anisotropic"))
{
ext = EXT_texture_filter_anisotropic;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context"))
{
ext = WEBGL_lose_context;
}
else if (CompareWebGLExtensionName(name, "WEBGL_lose_context"))
{
ext = WEBGL_lose_context;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc"))
{
ext = WEBGL_compressed_texture_s3tc;
}
else if (CompareWebGLExtensionName(name, "WEBGL_compressed_texture_s3tc"))
{
ext = WEBGL_compressed_texture_s3tc;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc"))
{
ext = WEBGL_compressed_texture_atc;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc"))
{
ext = WEBGL_compressed_texture_pvrtc;
}
else if (CompareWebGLExtensionName(name, "WEBGL_debug_renderer_info"))
{
ext = WEBGL_debug_renderer_info;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture"))
{
ext = WEBGL_depth_texture;
}
else if (CompareWebGLExtensionName(name, "WEBGL_depth_texture"))
{
ext = WEBGL_depth_texture;
}
else if (CompareWebGLExtensionName(name, "WEBGL_draw_buffers"))
{
ext = WEBGL_draw_buffers;
}
else if (CompareWebGLExtensionName(name, "ANGLE_instanced_arrays"))
{
ext = ANGLE_instanced_arrays;
}
if (ext == WebGLExtensionID_unknown_extension) {
return nullptr;
}
// step 2: check if the extension is supported
if (!IsExtensionSupported(cx, ext)) {
return nullptr;
}
// step 3: if the extension hadn't been previously been created, create it now, thus enabling it
if (!IsExtensionEnabled(ext)) {
EnableExtension(ext);
}
return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv);
}
void
WebGLContext::EnableExtension(WebGLExtensionID ext)
{
mExtensions.EnsureLengthAtLeast(ext + 1);
MOZ_ASSERT(IsExtensionEnabled(ext) == false);
WebGLExtensionBase* obj = nullptr;
switch (ext) {
case OES_element_index_uint:
obj = new WebGLExtensionElementIndexUint(this);
break;
case OES_standard_derivatives:
obj = new WebGLExtensionStandardDerivatives(this);
break;
case EXT_texture_filter_anisotropic:
obj = new WebGLExtensionTextureFilterAnisotropic(this);
break;
case WEBGL_lose_context:
obj = new WebGLExtensionLoseContext(this);
break;
case WEBGL_compressed_texture_s3tc:
obj = new WebGLExtensionCompressedTextureS3TC(this);
break;
case WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
case WEBGL_compressed_texture_pvrtc:
obj = new WebGLExtensionCompressedTexturePVRTC(this);
break;
case WEBGL_debug_renderer_info:
obj = new WebGLExtensionDebugRendererInfo(this);
break;
case WEBGL_depth_texture:
obj = new WebGLExtensionDepthTexture(this);
break;
case OES_texture_float:
obj = new WebGLExtensionTextureFloat(this);
break;
case OES_texture_float_linear:
obj = new WebGLExtensionTextureFloatLinear(this);
break;
case WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this);
break;
case OES_vertex_array_object:
obj = new WebGLExtensionVertexArray(this);
break;
case ANGLE_instanced_arrays:
obj = new WebGLExtensionInstancedArrays(this);
break;
default:
MOZ_ASSERT(false, "should not get there.");
}
mExtensions[ext] = obj;
}
void
WebGLContext::ClearScreen()
{
@ -1554,51 +1311,6 @@ WebGLContext::ForceRestoreContext()
mContextStatus = ContextLostAwaitingRestore;
}
void
WebGLContext::GetSupportedExtensions(JSContext *cx, Nullable< nsTArray<nsString> > &retval)
{
retval.SetNull();
if (!IsContextStable())
return;
nsTArray<nsString>& arr = retval.SetValue();
if (IsExtensionSupported(cx, OES_element_index_uint))
arr.AppendElement(NS_LITERAL_STRING("OES_element_index_uint"));
if (IsExtensionSupported(cx, OES_texture_float))
arr.AppendElement(NS_LITERAL_STRING("OES_texture_float"));
if (IsExtensionSupported(cx, OES_texture_float_linear))
arr.AppendElement(NS_LITERAL_STRING("OES_texture_float_linear"));
if (IsExtensionSupported(cx, OES_standard_derivatives))
arr.AppendElement(NS_LITERAL_STRING("OES_standard_derivatives"));
if (IsExtensionSupported(cx, EXT_texture_filter_anisotropic))
arr.AppendElement(NS_LITERAL_STRING("EXT_texture_filter_anisotropic"));
if (IsExtensionSupported(cx, WEBGL_lose_context))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
if (IsExtensionSupported(cx, WEBGL_lose_context))
arr.AppendElement(NS_LITERAL_STRING("WEBGL_lose_context"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_s3tc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_s3tc))
arr.AppendElement(NS_LITERAL_STRING("WEBGL_compressed_texture_s3tc"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_atc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_pvrtc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc"));
if (IsExtensionSupported(cx, WEBGL_debug_renderer_info))
arr.AppendElement(NS_LITERAL_STRING("WEBGL_debug_renderer_info"));
if (IsExtensionSupported(cx, WEBGL_depth_texture))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"));
if (IsExtensionSupported(cx, WEBGL_depth_texture))
arr.AppendElement(NS_LITERAL_STRING("WEBGL_depth_texture"));
if (IsExtensionSupported(cx, WEBGL_draw_buffers))
arr.AppendElement(NS_LITERAL_STRING("WEBGL_draw_buffers"));
if (IsExtensionSupported(cx, OES_vertex_array_object))
arr.AppendElement(NS_LITERAL_STRING("OES_vertex_array_object"));
if (IsExtensionSupported(cx, ANGLE_instanced_arrays))
arr.AppendElement(NS_LITERAL_STRING("ANGLE_instanced_arrays"));
}
//
// XPCOM goop
//

View File

@ -149,8 +149,6 @@ public:
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) = 0;
virtual bool IsWebGL2() const = 0;
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
// nsICanvasRenderingContextInternal
@ -961,7 +959,8 @@ protected:
ContextLostAwaitingRestore
};
// extensions
// -------------------------------------------------------------------------
// WebGL extensions (implemented in WebGLContextExtensions.cpp)
enum WebGLExtensionID {
EXT_texture_filter_anisotropic,
OES_element_index_uint,
@ -977,6 +976,7 @@ protected:
WEBGL_lose_context,
WEBGL_draw_buffers,
ANGLE_instanced_arrays,
WebGLExtensionID_max,
WebGLExtensionID_unknown_extension
};
nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions;
@ -991,8 +991,19 @@ protected:
bool IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const;
bool IsExtensionSupported(WebGLExtensionID ext) const;
static const char* GetExtensionString(WebGLExtensionID ext);
nsTArray<WebGLenum> mCompressedTextureFormats;
// -------------------------------------------------------------------------
// WebGL 2 specifics (implemented in WebGL2Context.cpp)
virtual bool IsWebGL2() const = 0;
bool InitWebGL2();
// -------------------------------------------------------------------------
// Validation functions (implemented in WebGLContextValidate.cpp)
bool InitAndValidateGL();

View File

@ -59,9 +59,9 @@ WebGLContext::BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buf
return;
}
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
if (!bufferSlot) {
if (!indexedBufferSlot) {
return;
}
@ -74,6 +74,11 @@ WebGLContext::BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buf
}
}
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
*indexedBufferSlot = buffer;
*bufferSlot = buffer;
MakeContextCurrent();
@ -95,9 +100,9 @@ WebGLContext::BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* bu
if (buffer && buffer->IsDeleted())
return;
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
if (!bufferSlot) {
if (!indexedBufferSlot) {
return;
}
@ -110,6 +115,11 @@ WebGLContext::BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* bu
}
}
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
*indexedBufferSlot = buffer;
*bufferSlot = buffer;
MakeContextCurrent();

View File

@ -0,0 +1,290 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLExtensions.h"
#include "GLContext.h"
#include "nsString.h"
#include "AccessCheck.h"
using namespace mozilla;
using namespace mozilla::gl;
// must match WebGLContext::WebGLExtensionID
static const char *sExtensionNames[] = {
"EXT_texture_filter_anisotropic",
"OES_element_index_uint",
"OES_standard_derivatives",
"OES_texture_float",
"OES_texture_float_linear",
"OES_vertex_array_object",
"WEBGL_compressed_texture_atc",
"WEBGL_compressed_texture_pvrtc",
"WEBGL_compressed_texture_s3tc",
"WEBGL_debug_renderer_info",
"WEBGL_depth_texture",
"WEBGL_lose_context",
"WEBGL_draw_buffers",
"ANGLE_instanced_arrays"
};
/* static */ const char*
WebGLContext::GetExtensionString(WebGLExtensionID ext)
{
static_assert(MOZ_ARRAY_LENGTH(sExtensionNames) == size_t(WebGLExtensionID_max),
"Mismatched lengths for sFeatureInfoInfos and GLFeature enums");
MOZ_ASSERT(ext < WebGLExtensionID_max, "unknown extension!");
return sExtensionNames[ext];
}
bool
WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
return mExtensions.SafeElementAt(ext);
}
bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const
{
// Chrome contexts need access to debug information even when
// webgl.disable-extensions is set. This is used in the graphics
// section of about:support.
if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) {
switch (ext) {
case WEBGL_debug_renderer_info:
return true;
default:
// For warnings-as-errors.
break;
}
}
return IsExtensionSupported(ext);
}
bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
if (mDisableExtensions) {
return false;
}
switch (ext) {
case OES_element_index_uint:
return gl->IsSupported(GLFeature::element_index_uint);
case OES_standard_derivatives:
return gl->IsSupported(GLFeature::standard_derivatives);
case WEBGL_lose_context:
// We always support this extension.
return true;
case OES_texture_float:
return gl->IsSupported(GLFeature::texture_float);
case OES_texture_float_linear:
return gl->IsSupported(GLFeature::texture_float_linear);
case OES_vertex_array_object:
return WebGLExtensionVertexArray::IsSupported(this);
case EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
case WEBGL_compressed_texture_s3tc:
if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc)) {
return true;
}
else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) &&
gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) &&
gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5))
{
return true;
}
return false;
case WEBGL_compressed_texture_atc:
return gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture);
case WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc);
case WEBGL_depth_texture:
return gl->IsSupported(GLFeature::packed_depth_stencil) &&
gl->IsSupported(GLFeature::depth_texture);
case ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
if (Preferences::GetBool("webgl.enable-draft-extensions", false) || IsWebGL2()) {
switch (ext) {
case WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
}
return false;
}
static bool
CompareWebGLExtensionName(const nsACString& name, const char *other)
{
return name.Equals(other, nsCaseInsensitiveCStringComparator());
}
JSObject*
WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& rv)
{
if (!IsContextStable())
return nullptr;
NS_LossyConvertUTF16toASCII name(aName);
WebGLExtensionID ext = WebGLExtensionID_unknown_extension;
// step 1: figure what extension is wanted
for (size_t i = 0; i < size_t(WebGLExtensionID_max); i++)
{
WebGLExtensionID extension = WebGLExtensionID(i);
if (CompareWebGLExtensionName(name, GetExtensionString(extension))) {
ext = extension;
break;
}
}
if (ext == WebGLExtensionID_unknown_extension)
{
/**
* We keep backward compatibility for these deprecated vendor-prefixed
* alias. Do not add new ones anymore. Hide it behind the
* webgl.enable-draft-extensions flag instead.
*/
if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context")) {
ext = WEBGL_lose_context;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc")) {
ext = WEBGL_compressed_texture_s3tc;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc")) {
ext = WEBGL_compressed_texture_atc;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc")) {
ext = WEBGL_compressed_texture_pvrtc;
}
else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture")) {
ext = WEBGL_depth_texture;
}
}
if (ext == WebGLExtensionID_unknown_extension) {
return nullptr;
}
// step 2: check if the extension is supported
if (!IsExtensionSupported(cx, ext)) {
return nullptr;
}
// step 3: if the extension hadn't been previously been created, create it now, thus enabling it
if (!IsExtensionEnabled(ext)) {
EnableExtension(ext);
}
return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv);
}
void
WebGLContext::EnableExtension(WebGLExtensionID ext)
{
mExtensions.EnsureLengthAtLeast(ext + 1);
MOZ_ASSERT(IsExtensionEnabled(ext) == false);
WebGLExtensionBase* obj = nullptr;
switch (ext) {
case OES_element_index_uint:
obj = new WebGLExtensionElementIndexUint(this);
break;
case OES_standard_derivatives:
obj = new WebGLExtensionStandardDerivatives(this);
break;
case EXT_texture_filter_anisotropic:
obj = new WebGLExtensionTextureFilterAnisotropic(this);
break;
case WEBGL_lose_context:
obj = new WebGLExtensionLoseContext(this);
break;
case WEBGL_compressed_texture_s3tc:
obj = new WebGLExtensionCompressedTextureS3TC(this);
break;
case WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
case WEBGL_compressed_texture_pvrtc:
obj = new WebGLExtensionCompressedTexturePVRTC(this);
break;
case WEBGL_debug_renderer_info:
obj = new WebGLExtensionDebugRendererInfo(this);
break;
case WEBGL_depth_texture:
obj = new WebGLExtensionDepthTexture(this);
break;
case OES_texture_float:
obj = new WebGLExtensionTextureFloat(this);
break;
case OES_texture_float_linear:
obj = new WebGLExtensionTextureFloatLinear(this);
break;
case WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this);
break;
case OES_vertex_array_object:
obj = new WebGLExtensionVertexArray(this);
break;
case ANGLE_instanced_arrays:
obj = new WebGLExtensionInstancedArrays(this);
break;
default:
MOZ_ASSERT(false, "should not get there.");
}
mExtensions[ext] = obj;
}
void
WebGLContext::GetSupportedExtensions(JSContext *cx, Nullable< nsTArray<nsString> > &retval)
{
retval.SetNull();
if (!IsContextStable())
return;
nsTArray<nsString>& arr = retval.SetValue();
for (size_t i = 0; i < size_t(WebGLExtensionID_max); i++)
{
WebGLExtensionID extension = WebGLExtensionID(i);
if (IsExtensionSupported(cx, extension)) {
arr.AppendElement(NS_ConvertUTF8toUTF16(GetExtensionString(extension)));
}
}
/**
* We keep backward compatibility for these deprecated vendor-prefixed
* alias. Do not add new ones anymore. Hide it behind the
* webgl.enable-draft-extensions flag instead.
*/
if (IsExtensionSupported(cx, WEBGL_lose_context))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_s3tc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_atc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc"));
if (IsExtensionSupported(cx, WEBGL_compressed_texture_pvrtc))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc"));
if (IsExtensionSupported(cx, WEBGL_depth_texture))
arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture"));
}

View File

@ -911,10 +911,6 @@ WebGLContext::InitAndValidateGL()
}
}
if (IsWebGL2()) {
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs);
}
// Always 1 for GLES2
mMaxFramebufferColorAttachments = 1;
@ -966,14 +962,7 @@ WebGLContext::InitAndValidateGL()
}
if (IsWebGL2() &&
(!IsExtensionSupported(OES_vertex_array_object) ||
!IsExtensionSupported(WEBGL_draw_buffers) ||
!IsExtensionSupported(ANGLE_instanced_arrays) ||
!gl->IsExtensionSupported(gl::GLContext::EXT_gpu_shader4) ||
!gl->IsExtensionSupported(gl::GLContext::EXT_blend_minmax) ||
(!gl->IsSupported(gl::GLFeature::occlusion_query) &&
!gl->IsSupported(gl::GLFeature::occlusion_query_boolean))
))
!InitWebGL2())
{
// Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
return false;
@ -993,15 +982,5 @@ WebGLContext::InitAndValidateGL()
mDefaultVertexArray->mAttribBuffers.SetLength(mGLMaxVertexAttribs);
mBoundVertexArray = mDefaultVertexArray;
if (IsWebGL2()) {
EnableExtension(OES_vertex_array_object);
EnableExtension(WEBGL_draw_buffers);
EnableExtension(ANGLE_instanced_arrays);
MOZ_ASSERT(IsExtensionEnabled(OES_vertex_array_object));
MOZ_ASSERT(IsExtensionEnabled(WEBGL_draw_buffers));
MOZ_ASSERT(IsExtensionEnabled(ANGLE_instanced_arrays));
}
return true;
}

View File

@ -38,6 +38,7 @@ if CONFIG['MOZ_WEBGL']:
'WebGLContextReporter.cpp',
'WebGLContextState.cpp',
'WebGLContextValidate.cpp',
'WebGLContextExtensions.cpp',
'WebGLContextFramebufferOperations.cpp',
'WebGLContextVertexArray.cpp',
'WebGLContextVertices.cpp',

View File

@ -88,6 +88,7 @@ MOCHITEST_FILES = \
file_drawImage_document_domain.html \
test_windingRuleUndefined.html \
test_strokeText_throw.html \
test_bug902651.html \
$(NULL)
# SkiaGL on Android/Gonk does not implement these composite ops yet

View File

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<title>Canvas test: canvas demotion</title>
<script src="/MochiKit/MochiKit.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body>
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
<script>
SimpleTest.waitForExplicitFinish();
addLoadEvent(function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(50, 50, 50)';
ctx.fillRect(0, 0, 100, 50);
ctx.translate(25, 25);
SpecialPowers.wrap(ctx).demote();
setTimeout(function() {
ctx.fillStyle = 'rgb(127, 127, 127)';
ctx.fillRect(0, 0, 10, 10);
var pixels = ctx.getImageData(0, 0, 1, 1);
ok(pixels.data[0] === 50, "pixels.data[0] expected 50, got " + pixels.data[0]);
ok(pixels.data[1] === 50, "pixels.data[1] expected 50, got " + pixels.data[1]);
ok(pixels.data[2] === 50, "pixels.data[2] expected 50, got " + pixels.data[2]);
pixels = ctx.getImageData(25, 25, 1, 1);
ok(pixels.data[0] === 127, "pixels.data[0] expected 127, got " + pixels.data[0]);
ok(pixels.data[1] === 127, "pixels.data[1] expected 127, got " + pixels.data[1]);
ok(pixels.data[2] === 127, "pixels.data[2] expected 127, got " + pixels.data[2]);
SimpleTest.finish();
}, 50);
});
</script>

File diff suppressed because it is too large Load Diff

View File

@ -240,6 +240,14 @@ DOMMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHi
return stream.forget();
}
void
DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled)
{
if (mStream) {
mStream->SetTrackEnabled(aTrackID, aEnabled);
}
}
bool
DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
{

View File

@ -84,6 +84,12 @@ public:
virtual bool AddDirectListener(MediaStreamDirectListener *aListener) { return false; }
virtual void RemoveDirectListener(MediaStreamDirectListener *aListener) {}
/**
* Overridden in DOMLocalMediaStreams to allow getUserMedia to disable
* media at the SourceMediaStream.
*/
virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled);
bool IsFinished();
/**
* Returns a principal indicating who may access this stream. The stream contents

View File

@ -100,6 +100,10 @@ public:
* Insert aDuration of null data at the end of the segment.
*/
virtual void AppendNullData(TrackTicks aDuration) = 0;
/**
* Replace contents with disabled data of the same duration
*/
virtual void ReplaceWithDisabled() = 0;
/**
* Remove all contents, setting duration to 0.
*/
@ -190,6 +194,15 @@ public:
}
mDuration += aDuration;
}
virtual void ReplaceWithDisabled()
{
if (GetType() != AUDIO) {
MOZ_CRASH("Disabling unknown segment type");
}
TrackTicks duration = GetDuration();
Clear();
AppendNullData(duration);
}
virtual void Clear()
{
mDuration = 0;

View File

@ -1912,29 +1912,15 @@ MediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled)
}
void
MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment)
MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment)
{
// mMutex must be owned here if this is a SourceMediaStream
if (!mDisabledTrackIDs.Contains(aTrackID)) {
return;
}
switch (aSegment->GetType()) {
case MediaSegment::AUDIO: {
TrackTicks duration = aSegment->GetDuration();
aSegment->Clear();
aSegment->AppendNullData(duration);
break;
}
case MediaSegment::VIDEO: {
for (VideoSegment::ChunkIterator i(*static_cast<VideoSegment*>(aSegment));
!i.IsEnded(); i.Next()) {
VideoChunk& chunk = *i;
chunk.SetForceBlack(true);
}
break;
}
default:
MOZ_CRASH("Unknown track type");
aSegment->ReplaceWithDisabled();
if (aRawSegment) {
aRawSegment->ReplaceWithDisabled();
}
}
@ -1990,6 +1976,10 @@ SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegme
// Indirect listeners (via subsequent TrackUnion nodes) are synced to
// playout time, and so can be delayed by buffering.
// Apply track disabling before notifying any consumers directly
// or inserting into the graph
ApplyTrackDisabling(aID, aSegment, aRawSegment);
// Must notify first, since AppendFrom() will empty out aSegment
NotifyDirectConsumers(track, aRawSegment ? aRawSegment : aSegment);
track->mData->AppendFrom(aSegment); // note: aSegment is now dead

View File

@ -459,7 +459,7 @@ public:
StreamBuffer::Track* EnsureTrack(TrackID aTrack, TrackRate aSampleRate);
void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment);
void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
DOMMediaStream* GetWrapper()
{
@ -679,6 +679,11 @@ public:
FinishWithLockHeld();
}
// Overriding allows us to hold the mMutex lock while changing the track enable status
void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
MutexAutoLock lock(mMutex);
MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
}
/**
* End all tracks and Finish() this stream. Used to voluntarily revoke access
@ -937,6 +942,11 @@ public:
virtual void ProduceOutput(GraphTime aFrom, GraphTime aTo) = 0;
void SetAutofinishImpl(bool aAutofinish) { mAutofinish = aAutofinish; }
/**
* Forward SetTrackEnabled() to the input MediaStream(s) and translate the ID
*/
virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {};
protected:
// This state is all accessed only on the media graph thread.

View File

@ -52,10 +52,7 @@ void
MediaStreamTrack::SetEnabled(bool aEnabled)
{
mEnabled = aEnabled;
MediaStream* stream = mStream->GetStream();
if (stream) {
stream->SetTrackEnabled(mTrackID, aEnabled);
}
mStream->SetTrackEnabled(mTrackID, aEnabled);
}
}

View File

@ -115,6 +115,17 @@ public:
mFilterCallback = aCallback;
}
// Forward SetTrackEnabled(output_track_id, enabled) to the Source MediaStream,
// translating the output track ID into the correct ID in the source.
virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) {
for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
if (mTrackMap[i].mOutputTrackID == aOutputID) {
mTrackMap[i].mInputPort->GetSource()->
SetTrackEnabled(mTrackMap[i].mInputTrackID, aEnabled);
}
}
}
protected:
TrackIDFilterCallback mFilterCallback;

View File

@ -107,6 +107,14 @@ public:
}
return &c->mFrame;
}
// Override default impl
virtual void ReplaceWithDisabled() MOZ_OVERRIDE {
for (ChunkIterator i(*this);
!i.IsEnded(); i.Next()) {
VideoChunk& chunk = *i;
chunk.SetForceBlack(true);
}
}
// Segment-generic methods not in MediaSegmentBase
static Type StaticType() { return VIDEO; }

View File

@ -612,7 +612,7 @@ MediaEngineWebRTCVideoSource::AllocImpl() {
mCameraThread,
this,
this,
mWindowId);
nsGlobalWindow::GetInnerWindowWithId(mWindowId));
mCameraManager->Register(mDOMCameraControl);
}
@ -662,7 +662,7 @@ MediaEngineWebRTCVideoSource::SnapshotImpl() {
// nsICameraGetCameraCallback
nsresult
MediaEngineWebRTCVideoSource::HandleEvent(nsICameraControl* camera) {
MediaEngineWebRTCVideoSource::HandleEvent(nsISupports* /* unused */) {
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
mNativeCameraControl = static_cast<nsGonkCameraControl*>(mDOMCameraControl->GetNativeCameraControl().get());

View File

@ -6,7 +6,6 @@
#define nsIXMLContentSink_h___
#include "nsIContentSink.h"
#include "nsIParserNode.h"
#include "nsISupports.h"
class nsIDocument;

View File

@ -26,7 +26,7 @@ WindowNamedPropertiesHandler::getOwnPropertyDescriptor(JSContext* aCx,
return true;
}
JSObject* global = JS_GetGlobalForObject(aCx, aProxy);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
nsresult rv =
nsDOMClassInfo::ScriptSecurityManager()->CheckPropertyAccess(aCx, global,
"Window", aId,

View File

@ -554,8 +554,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
EVENTTARGET_SCRIPTABLE_FLAGS)
#endif
NS_DEFINE_CLASSINFO_DATA(CameraControl, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1432,10 +1430,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_END
#endif
DOM_CLASSINFO_MAP_BEGIN(CameraControl, nsICameraControl)
DOM_CLASSINFO_MAP_ENTRY(nsICameraControl)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(CameraCapabilities, nsICameraCapabilities)
DOM_CLASSINFO_MAP_ENTRY(nsICameraCapabilities)
DOM_CLASSINFO_MAP_END
@ -2190,12 +2184,13 @@ nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
NS_IMETHODIMP
nsWindowSH::PostCreatePrototype(JSContext* aCx, JSObject* aProto)
{
nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, aProto);
JS::Rooted<JSObject*> proto(aCx, aProto);
nsresult rv = nsDOMClassInfo::PostCreatePrototype(aCx, proto);
NS_ENSURE_SUCCESS(rv, rv);
// We should probably move this into the CreateInterfaceObjects for Window
// once it is on WebIDL bindings.
JS::Rooted<JSObject*> proto(aCx, aProto);
WindowNamedPropertiesHandler::Install(aCx, proto);
return NS_OK;
}

View File

@ -140,7 +140,6 @@ DOMCI_CLASS(FMRadio)
DOMCI_CLASS(BluetoothDevice)
#endif
DOMCI_CLASS(CameraControl)
DOMCI_CLASS(CameraCapabilities)
DOMCI_CLASS(LockedFile)

View File

@ -255,7 +255,7 @@ nsHistory::ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
}
void
nsHistory::PushOrReplaceState(JSContext* aCx, JS::Value aData,
nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
ErrorResult& aRv, bool aReplace)
{

View File

@ -56,7 +56,7 @@ protected:
return win->GetDocShell();
}
void PushOrReplaceState(JSContext* aCx, JS::Value aData,
void PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
mozilla::ErrorResult& aRv, bool aReplace);

View File

@ -176,6 +176,14 @@ DOMInterfaces = {
'headerFile': 'CallsList.h',
},
'CameraControl': {
'nativeType': 'mozilla::nsDOMCameraControl',
'headerFile': 'DOMCameraControl.h',
'binaryNames': {
"release": "ReleaseHardware"
}
},
'CameraManager': {
'nativeType': 'nsDOMCameraManager',
'headerFile': 'DOMCameraManager.h'
@ -1815,3 +1823,13 @@ addExternalIface('XULCommandDispatcher')
addExternalIface('DataTransfer', notflattened=True)
addExternalIface('GetCameraCallback', nativeType='nsICameraGetCameraCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraErrorCallback', nativeType='nsICameraErrorCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraCapabilities', nativeType='nsICameraCapabilities', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraAutoFocusCallback', nativeType='nsICameraAutoFocusCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraShutterCallback', nativeType='nsICameraShutterCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraClosedCallback', nativeType='nsICameraClosedCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraTakePictureCallback', nativeType='nsICameraTakePictureCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraReleaseCallback', nativeType='nsICameraReleaseCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraStartRecordingCallback', nativeType='nsICameraStartRecordingCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraPreviewStateChange', nativeType='nsICameraPreviewStateChange', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraPreviewStreamCallback', nativeType='nsICameraPreviewStreamCallback', headerFile='nsIDOMCameraManager.h')
addExternalIface('CameraRecorderStateChange', nativeType='nsICameraRecorderStateChange', headerFile='nsIDOMCameraManager.h')

View File

@ -80,7 +80,14 @@ class CGNativePropertyHooks(CGThing):
def declare(self):
if self.descriptor.workers:
return ""
return "extern const NativePropertyHooks* sNativePropertyHooks;\n"
return """// We declare this as an array so that retrieving a pointer to this
// binding's property hooks only requires compile/link-time resolvable
// address arithmetic. Declaring it as a pointer instead would require
// doing a run-time load to fetch a pointer to this binding's property
// hooks. And then structures which embedded a pointer to this structure
// would require a run-time load for proper initialization, which would
// then induce static constructors. Lots of static constructors.
extern const NativePropertyHooks sNativePropertyHooks[];"""
def define(self):
if self.descriptor.workers:
return ""
@ -125,10 +132,9 @@ class CGNativePropertyHooks(CGThing):
CGGeneric(constructorID),
CGGeneric(parentHooks)],
",\n")),
pre="static const NativePropertyHooks sNativePropertyHooksStruct = {\n",
pre="const NativePropertyHooks sNativePropertyHooks[] = { {\n",
post=("\n"
"};\n"
"const NativePropertyHooks* sNativePropertyHooks = &sNativePropertyHooksStruct;\n")).define()
"} };\n")).define()
def NativePropertyHooks(descriptor):
return "&sWorkerNativePropertyHooks" if descriptor.workers else "sNativePropertyHooks"

View File

@ -7,6 +7,8 @@
#include "nsDOMClassInfo.h"
#include "jsapi.h"
#include "nsThread.h"
#include "DeviceStorage.h"
#include "mozilla/dom/CameraControlBinding.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
@ -23,15 +25,11 @@
using namespace mozilla;
using namespace mozilla::dom;
DOMCI_DATA(CameraControl, nsICameraControl)
NS_IMPL_CYCLE_COLLECTION_1(nsDOMCameraControl,
mDOMCapabilities)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsDOMCameraControl, mDOMCapabilities, mWindow)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraControl)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsICameraControl)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraControl)
@ -42,235 +40,242 @@ nsDOMCameraControl::~nsDOMCameraControl()
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
}
/* readonly attribute nsICameraCapabilities capabilities; */
NS_IMETHODIMP
nsDOMCameraControl::GetCapabilities(nsICameraCapabilities** aCapabilities)
JSObject*
nsDOMCameraControl::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return CameraControlBinding::Wrap(aCx, aScope, this);
}
nsICameraCapabilities*
nsDOMCameraControl::Capabilities()
{
if (!mDOMCapabilities) {
mDOMCapabilities = new DOMCameraCapabilities(mCameraControl);
}
nsCOMPtr<nsICameraCapabilities> capabilities = mDOMCapabilities;
capabilities.forget(aCapabilities);
return NS_OK;
return mDOMCapabilities;
}
/* attribute DOMString effect; */
NS_IMETHODIMP
nsDOMCameraControl::GetEffect(nsAString& aEffect)
void
nsDOMCameraControl::GetEffect(nsString& aEffect, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
aRv = mCameraControl->Get(CAMERA_PARAM_EFFECT, aEffect);
}
NS_IMETHODIMP
nsDOMCameraControl::SetEffect(const nsAString& aEffect)
void
nsDOMCameraControl::SetEffect(const nsAString& aEffect, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
aRv = mCameraControl->Set(CAMERA_PARAM_EFFECT, aEffect);
}
/* attribute DOMString whiteBalanceMode; */
NS_IMETHODIMP
nsDOMCameraControl::GetWhiteBalanceMode(nsAString& aWhiteBalanceMode)
void
nsDOMCameraControl::GetWhiteBalanceMode(nsString& aWhiteBalanceMode, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
aRv = mCameraControl->Get(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
NS_IMETHODIMP
nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode)
void
nsDOMCameraControl::SetWhiteBalanceMode(const nsAString& aWhiteBalanceMode, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
aRv = mCameraControl->Set(CAMERA_PARAM_WHITEBALANCE, aWhiteBalanceMode);
}
/* attribute DOMString sceneMode; */
NS_IMETHODIMP
nsDOMCameraControl::GetSceneMode(nsAString& aSceneMode)
void
nsDOMCameraControl::GetSceneMode(nsString& aSceneMode, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
aRv = mCameraControl->Get(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
NS_IMETHODIMP
nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode)
void
nsDOMCameraControl::SetSceneMode(const nsAString& aSceneMode, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
aRv = mCameraControl->Set(CAMERA_PARAM_SCENEMODE, aSceneMode);
}
/* attribute DOMString flashMode; */
NS_IMETHODIMP
nsDOMCameraControl::GetFlashMode(nsAString& aFlashMode)
void
nsDOMCameraControl::GetFlashMode(nsString& aFlashMode, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
aRv = mCameraControl->Get(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
NS_IMETHODIMP
nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode)
void
nsDOMCameraControl::SetFlashMode(const nsAString& aFlashMode, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
aRv = mCameraControl->Set(CAMERA_PARAM_FLASHMODE, aFlashMode);
}
/* attribute DOMString focusMode; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocusMode(nsAString& aFocusMode)
void
nsDOMCameraControl::GetFocusMode(nsString& aFocusMode, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
NS_IMETHODIMP
nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode)
void
nsDOMCameraControl::SetFocusMode(const nsAString& aFocusMode, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
aRv = mCameraControl->Set(CAMERA_PARAM_FOCUSMODE, aFocusMode);
}
/* attribute double zoom; */
NS_IMETHODIMP
nsDOMCameraControl::GetZoom(double* aZoom)
double
nsDOMCameraControl::GetZoom(ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_ZOOM, aZoom);
double zoom;
aRv = mCameraControl->Get(CAMERA_PARAM_ZOOM, &zoom);
return zoom;
}
NS_IMETHODIMP
nsDOMCameraControl::SetZoom(double aZoom)
void
nsDOMCameraControl::SetZoom(double aZoom, ErrorResult& aRv)
{
return mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
aRv = mCameraControl->Set(CAMERA_PARAM_ZOOM, aZoom);
}
/* attribute jsval meteringAreas; */
NS_IMETHODIMP
nsDOMCameraControl::GetMeteringAreas(JSContext* cx, JS::Value* aMeteringAreas)
JS::Value
nsDOMCameraControl::GetMeteringAreas(JSContext* cx, ErrorResult& aRv)
{
return mCameraControl->Get(cx, CAMERA_PARAM_METERINGAREAS, aMeteringAreas);
}
NS_IMETHODIMP
nsDOMCameraControl::SetMeteringAreas(JSContext* cx, const JS::Value& aMeteringAreas)
{
return mCameraControl->SetMeteringAreas(cx, aMeteringAreas);
JS::Rooted<JS::Value> areas(cx);
aRv = mCameraControl->Get(cx, CAMERA_PARAM_METERINGAREAS, areas.address());
return areas;
}
/* attribute jsval focusAreas; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocusAreas(JSContext* cx, JS::Value* aFocusAreas)
void
nsDOMCameraControl::SetMeteringAreas(JSContext* cx, JS::Handle<JS::Value> aMeteringAreas, ErrorResult& aRv)
{
return mCameraControl->Get(cx, CAMERA_PARAM_FOCUSAREAS, aFocusAreas);
}
NS_IMETHODIMP
nsDOMCameraControl::SetFocusAreas(JSContext* cx, const JS::Value& aFocusAreas)
{
return mCameraControl->SetFocusAreas(cx, aFocusAreas);
aRv = mCameraControl->SetMeteringAreas(cx, aMeteringAreas);
}
/* readonly attribute double focalLength; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocalLength(double* aFocalLength)
JS::Value
nsDOMCameraControl::GetFocusAreas(JSContext* cx, ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, aFocalLength);
JS::Rooted<JS::Value> value(cx);
aRv = mCameraControl->Get(cx, CAMERA_PARAM_FOCUSAREAS, value.address());
return value;
}
void
nsDOMCameraControl::SetFocusAreas(JSContext* cx, JS::Handle<JS::Value> aFocusAreas, ErrorResult& aRv)
{
aRv = mCameraControl->SetFocusAreas(cx, aFocusAreas);
}
/* readonly attribute double focusDistanceNear; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocusDistanceNear(double* aFocusDistanceNear)
double
nsDOMCameraControl::GetFocalLength(ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, aFocusDistanceNear);
double focalLength;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCALLENGTH, &focalLength);
return focalLength;
}
/* readonly attribute double focusDistanceOptimum; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocusDistanceOptimum(double* aFocusDistanceOptimum)
double
nsDOMCameraControl::GetFocusDistanceNear(ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, aFocusDistanceOptimum);
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCENEAR, &distance);
return distance;
}
/* readonly attribute double focusDistanceFar; */
NS_IMETHODIMP
nsDOMCameraControl::GetFocusDistanceFar(double* aFocusDistanceFar)
double
nsDOMCameraControl::GetFocusDistanceOptimum(ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, aFocusDistanceFar);
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEOPTIMUM, &distance);
return distance;
}
/* void setExposureCompensation (const JS::Value& aCompensation, JSContext* cx); */
NS_IMETHODIMP
nsDOMCameraControl::SetExposureCompensation(const JS::Value& aCompensation, JSContext* cx)
double
nsDOMCameraControl::GetFocusDistanceFar(ErrorResult& aRv)
{
if (aCompensation.isNullOrUndefined()) {
double distance;
aRv = mCameraControl->Get(CAMERA_PARAM_FOCUSDISTANCEFAR, &distance);
return distance;
}
void
nsDOMCameraControl::SetExposureCompensation(const Optional<double>& aCompensation, ErrorResult& aRv)
{
if (!aCompensation.WasPassed()) {
// use NaN to switch the camera back into auto mode
return mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, NAN);
}
aRv = mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, aCompensation.Value());
}
double
nsDOMCameraControl::GetExposureCompensation(ErrorResult& aRv)
{
double compensation;
if (!JS_ValueToNumber(cx, aCompensation, &compensation)) {
return NS_ERROR_INVALID_ARG;
}
return mCameraControl->Set(CAMERA_PARAM_EXPOSURECOMPENSATION, compensation);
aRv = mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, &compensation);
return compensation;
}
/* readonly attribute double exposureCompensation; */
NS_IMETHODIMP
nsDOMCameraControl::GetExposureCompensation(double* aExposureCompensation)
already_AddRefed<nsICameraShutterCallback>
nsDOMCameraControl::GetOnShutter(ErrorResult& aRv)
{
return mCameraControl->Get(CAMERA_PARAM_EXPOSURECOMPENSATION, aExposureCompensation);
nsCOMPtr<nsICameraShutterCallback> cb;
aRv = mCameraControl->Get(getter_AddRefs(cb));
return cb.forget();
}
/* attribute nsICameraShutterCallback onShutter; */
NS_IMETHODIMP
nsDOMCameraControl::GetOnShutter(nsICameraShutterCallback** aOnShutter)
void
nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter,
ErrorResult& aRv)
{
return mCameraControl->Get(aOnShutter);
}
NS_IMETHODIMP
nsDOMCameraControl::SetOnShutter(nsICameraShutterCallback* aOnShutter)
{
return mCameraControl->Set(aOnShutter);
aRv = mCameraControl->Set(aOnShutter);
}
/* attribute nsICameraClosedCallback onClosed; */
NS_IMETHODIMP
nsDOMCameraControl::GetOnClosed(nsICameraClosedCallback** aOnClosed)
already_AddRefed<nsICameraClosedCallback>
nsDOMCameraControl::GetOnClosed(ErrorResult& aRv)
{
return mCameraControl->Get(aOnClosed);
}
NS_IMETHODIMP
nsDOMCameraControl::SetOnClosed(nsICameraClosedCallback* aOnClosed)
{
return mCameraControl->Set(aOnClosed);
nsCOMPtr<nsICameraClosedCallback> onClosed;
aRv = mCameraControl->Get(getter_AddRefs(onClosed));
return onClosed.forget();
}
/* attribute nsICameraRecorderStateChange onRecorderStateChange; */
NS_IMETHODIMP
nsDOMCameraControl::GetOnRecorderStateChange(nsICameraRecorderStateChange** aOnRecorderStateChange)
void
nsDOMCameraControl::SetOnClosed(nsICameraClosedCallback* aOnClosed,
ErrorResult& aRv)
{
return mCameraControl->Get(aOnRecorderStateChange);
}
NS_IMETHODIMP
nsDOMCameraControl::SetOnRecorderStateChange(nsICameraRecorderStateChange* aOnRecorderStateChange)
{
return mCameraControl->Set(aOnRecorderStateChange);
aRv = mCameraControl->Set(aOnClosed);
}
/* attribute nsICameraPreviewStateChange onPreviewStateChange; */
NS_IMETHODIMP
nsDOMCameraControl::GetOnPreviewStateChange(nsICameraPreviewStateChange** aOnPreviewStateChange)
already_AddRefed<nsICameraRecorderStateChange>
nsDOMCameraControl::GetOnRecorderStateChange(ErrorResult& aRv)
{
return mCameraControl->Get(aOnPreviewStateChange);
}
NS_IMETHODIMP
nsDOMCameraControl::SetOnPreviewStateChange(nsICameraPreviewStateChange* aOnPreviewStateChange)
{
return mCameraControl->Set(aOnPreviewStateChange);
nsCOMPtr<nsICameraRecorderStateChange> cb;
aRv = mCameraControl->Get(getter_AddRefs(cb));
return cb.forget();
}
/* [implicit_jscontext] void startRecording (in jsval aOptions, in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsIDOMDeviceStorage* storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
void
nsDOMCameraControl::SetOnRecorderStateChange(nsICameraRecorderStateChange* aOnRecorderStateChange,
ErrorResult& aRv)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(storageArea, NS_ERROR_INVALID_ARG);
aRv = mCameraControl->Set(aOnRecorderStateChange);
}
void
nsDOMCameraControl::StartRecording(JSContext* aCx,
JS::Handle<JS::Value> aOptions,
nsDOMDeviceStorage& storageArea,
const nsAString& filename,
nsICameraStartRecordingCallback* onSuccess,
const Optional<nsICameraErrorCallback*>& onError,
ErrorResult& aRv)
{
MOZ_ASSERT(onSuccess, "no onSuccess handler passed");
mozilla::idl::CameraStartRecordingOptions options;
// Default values, until the dictionary parser can handle them.
options.rotation = 0;
options.maxFileSizeBytes = 0;
options.maxVideoLengthMs = 0;
nsresult rv = options.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
aRv = options.Init(aCx, aOptions.address());
if (aRv.Failed()) {
return;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
NS_WARNING("Could not get the Observer service for CameraControl::StartRecording.");
return NS_ERROR_FAILURE;
aRv.Throw(NS_ERROR_FAILURE);
return;
}
obs->NotifyObservers(nullptr,
@ -296,19 +301,21 @@ nsDOMCameraControl::StartRecording(const JS::Value& aOptions, nsIDOMDeviceStorag
#endif
nsCOMPtr<nsIFile> folder;
rv = storageArea->GetRootDirectoryForFile(filename, getter_AddRefs(folder));
NS_ENSURE_SUCCESS(rv, rv);
return mCameraControl->StartRecording(&options, folder, filename, onSuccess, onError);
aRv = storageArea.GetRootDirectoryForFile(filename, getter_AddRefs(folder));
if (aRv.Failed()) {
return;
}
aRv = mCameraControl->StartRecording(&options, folder, filename, onSuccess,
onError.WasPassed() ? onError.Value() : nullptr);
}
/* void stopRecording (); */
NS_IMETHODIMP
nsDOMCameraControl::StopRecording()
void
nsDOMCameraControl::StopRecording(ErrorResult& aRv)
{
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
NS_WARNING("Could not get the Observer service for CameraControl::StopRecording.");
return NS_ERROR_FAILURE;
aRv.Throw(NS_ERROR_FAILURE);
}
obs->NotifyObservers(nullptr,
@ -327,55 +334,71 @@ nsDOMCameraControl::StopRecording()
}
#endif
return mCameraControl->StopRecording();
aRv = mCameraControl->StopRecording();
}
/* [implicit_jscontext] void getPreviewStream (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraControl::GetPreviewStream(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
void
nsDOMCameraControl::GetPreviewStream(JSContext* aCx,
JS::Handle<JS::Value> aOptions,
nsICameraPreviewStreamCallback* onSuccess,
const Optional<nsICameraErrorCallback*>& onError,
ErrorResult& aRv)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
mozilla::idl::CameraSize size;
nsresult rv = size.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
aRv = size.Init(aCx, aOptions.address());
if (aRv.Failed()) {
return;
}
return mCameraControl->GetPreviewStream(size, onSuccess, onError);
aRv = mCameraControl->GetPreviewStream(size, onSuccess,
onError.WasPassed()
? onError.Value() : nullptr);
}
/* void resumePreview(); */
NS_IMETHODIMP
nsDOMCameraControl::ResumePreview()
void
nsDOMCameraControl::ResumePreview(ErrorResult& aRv)
{
return mCameraControl->StartPreview(nullptr);
aRv = mCameraControl->StartPreview(nullptr);
}
/* void autoFocus (in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess, nsICameraErrorCallback* onError)
already_AddRefed<nsICameraPreviewStateChange>
nsDOMCameraControl::GetOnPreviewStateChange() const
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
return mCameraControl->AutoFocus(onSuccess, onError);
nsCOMPtr<nsICameraPreviewStateChange> cb;
mCameraControl->Get(getter_AddRefs(cb));
return cb.forget();
}
/* void takePicture (in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
void
nsDOMCameraControl::SetOnPreviewStateChange(nsICameraPreviewStateChange* aCb)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
mCameraControl->Set(aCb);
}
RootedDictionary<CameraPictureOptions> options(cx);
void
nsDOMCameraControl::AutoFocus(nsICameraAutoFocusCallback* onSuccess,
const Optional<nsICameraErrorCallback*>& onError,
ErrorResult& aRv)
{
aRv = mCameraControl->AutoFocus(onSuccess,
onError.WasPassed() ? onError.Value() : nullptr);
}
void
nsDOMCameraControl::TakePicture(JSContext* aCx,
const CameraPictureOptions& aOptions,
nsICameraTakePictureCallback* onSuccess,
const Optional<nsICameraErrorCallback*>& aOnError,
ErrorResult& aRv)
{
mozilla::idl::CameraSize size;
mozilla::idl::CameraPosition pos;
JS::Rooted<JS::Value> optionVal(cx, aOptions);
if (!options.Init(cx, optionVal)) {
return NS_ERROR_FAILURE;
aRv = size.Init(aCx, &aOptions.mPictureSize);
if (aRv.Failed()) {
return;
}
nsresult rv = size.Init(cx, &options.mPictureSize);
NS_ENSURE_SUCCESS(rv, rv);
/**
* Default values, until the dictionary parser can handle them.
* NaN indicates no value provided.
@ -384,29 +407,45 @@ nsDOMCameraControl::TakePicture(const JS::Value& aOptions, nsICameraTakePictureC
pos.longitude = NAN;
pos.altitude = NAN;
pos.timestamp = NAN;
rv = pos.Init(cx, &options.mPosition);
NS_ENSURE_SUCCESS(rv, rv);
aRv = pos.Init(aCx, &aOptions.mPosition);
if (aRv.Failed()) {
return;
}
return mCameraControl->TakePicture(size, options.mRotation, options.mFileFormat, pos, options.mDateTime, onSuccess, onError);
nsICameraErrorCallback* onError =
aOnError.WasPassed() ? aOnError.Value() : nullptr;
aRv = mCameraControl->TakePicture(size, aOptions.mRotation,
aOptions.mFileFormat, pos,
aOptions.mDateTime, onSuccess, onError);
}
/* [implicit_jscontext] void GetPreviewStreamVideoMode (in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError); */
NS_IMETHODIMP
nsDOMCameraControl::GetPreviewStreamVideoMode(const JS::Value& aOptions, nsICameraPreviewStreamCallback* onSuccess, nsICameraErrorCallback* onError, JSContext* cx)
void
nsDOMCameraControl::GetPreviewStreamVideoMode(JSContext* aCx,
JS::Handle<JS::Value> aOptions,
nsICameraPreviewStreamCallback* onSuccess,
const Optional<nsICameraErrorCallback*>& onError,
ErrorResult& aRv)
{
NS_ENSURE_TRUE(onSuccess, NS_ERROR_INVALID_ARG);
mozilla::idl::CameraRecorderOptions options;
nsresult rv = options.Init(cx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
aRv = options.Init(aCx, aOptions.address());
if (aRv.Failed()) {
return;
}
return mCameraControl->GetPreviewStreamVideoMode(&options, onSuccess, onError);
aRv = mCameraControl->GetPreviewStreamVideoMode(&options, onSuccess,
onError.WasPassed()
? onError.Value() : nullptr);
}
NS_IMETHODIMP
nsDOMCameraControl::ReleaseHardware(nsICameraReleaseCallback* onSuccess, nsICameraErrorCallback* onError)
void
nsDOMCameraControl::ReleaseHardware(const Optional<nsICameraReleaseCallback*>& onSuccess,
const Optional<nsICameraErrorCallback*>& onError,
ErrorResult& aRv)
{
return mCameraControl->ReleaseHardware(onSuccess, onError);
aRv =
mCameraControl->ReleaseHardware(
onSuccess.WasPassed() ? onSuccess.Value() : nullptr,
onError.WasPassed() ? onError.Value() : nullptr);
}
class GetCameraResult : public nsRunnable

View File

@ -16,19 +16,27 @@
#include "AudioChannelAgent.h"
#include "nsProxyRelease.h"
class nsDOMDeviceStorage;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class CameraPictureOptions;
template<typename T> class Optional;
}
class ErrorResult;
// Main camera control.
class nsDOMCameraControl : public nsICameraControl
class nsDOMCameraControl MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMCameraControl)
NS_DECL_NSICAMERACONTROL
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCameraControl)
nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread,
nsICameraGetCameraCallback* onSuccess,
nsICameraErrorCallback* onError, uint64_t aWindowId);
nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow);
nsresult Result(nsresult aResult,
const nsMainThreadPtrHandle<nsICameraGetCameraCallback>& onSuccess,
const nsMainThreadPtrHandle<nsICameraErrorCallback>& onError,
@ -37,6 +45,52 @@ public:
void Shutdown();
nsPIDOMWindow* GetParentObject() const { return mWindow; }
// WebIDL
nsICameraCapabilities* Capabilities();
void GetEffect(nsString& aEffect, ErrorResult& aRv);
void SetEffect(const nsAString& aEffect, ErrorResult& aRv);
void GetWhiteBalanceMode(nsString& aMode, ErrorResult& aRv);
void SetWhiteBalanceMode(const nsAString& aMode, ErrorResult& aRv);
void GetSceneMode(nsString& aMode, ErrorResult& aRv);
void SetSceneMode(const nsAString& aMode, ErrorResult& aRv);
void GetFlashMode(nsString& aMode, ErrorResult& aRv);
void SetFlashMode(const nsAString& aMode, ErrorResult& aRv);
void GetFocusMode(nsString& aMode, ErrorResult& aRv);
void SetFocusMode(const nsAString& aMode, ErrorResult& aRv);
double GetZoom(ErrorResult& aRv);
void SetZoom(double aZoom, ErrorResult& aRv);
JS::Value GetMeteringAreas(JSContext* aCx, ErrorResult& aRv);
void SetMeteringAreas(JSContext* aCx, JS::Handle<JS::Value> aAreas, ErrorResult& aRv);
JS::Value GetFocusAreas(JSContext* aCx, ErrorResult& aRv);
void SetFocusAreas(JSContext* aCx, JS::Handle<JS::Value> aAreas, ErrorResult& aRv);
double GetFocalLength(ErrorResult& aRv);
double GetFocusDistanceNear(ErrorResult& aRv);
double GetFocusDistanceOptimum(ErrorResult& aRv);
double GetFocusDistanceFar(ErrorResult& aRv);
void SetExposureCompensation(const dom::Optional<double>& aCompensation, ErrorResult& aRv);
double GetExposureCompensation(ErrorResult& aRv);
already_AddRefed<nsICameraShutterCallback> GetOnShutter(ErrorResult& aRv);
void SetOnShutter(nsICameraShutterCallback* aCb, ErrorResult& aRv);
already_AddRefed<nsICameraClosedCallback> GetOnClosed(ErrorResult& aRv);
void SetOnClosed(nsICameraClosedCallback* aCb, ErrorResult& aRv);
already_AddRefed<nsICameraRecorderStateChange> GetOnRecorderStateChange(ErrorResult& aRv);
void SetOnRecorderStateChange(nsICameraRecorderStateChange* aCb, ErrorResult& aRv);
void AutoFocus(nsICameraAutoFocusCallback* aOnSuccess, const dom::Optional<nsICameraErrorCallback*>& aOnErro, ErrorResult& aRvr);
void TakePicture(JSContext* aCx, const dom::CameraPictureOptions& aOptions,
nsICameraTakePictureCallback* onSuccess,
const dom::Optional<nsICameraErrorCallback* >& onError,
ErrorResult& aRv);
already_AddRefed<nsICameraPreviewStateChange> GetOnPreviewStateChange() const;
void SetOnPreviewStateChange(nsICameraPreviewStateChange* aOnStateChange);
void GetPreviewStreamVideoMode(JSContext* cx, JS::Handle<JS::Value> aOptions, nsICameraPreviewStreamCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
void StartRecording(JSContext* cx, JS::Handle<JS::Value> aOptions, nsDOMDeviceStorage& storageArea, const nsAString& filename, nsICameraStartRecordingCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
void StopRecording(ErrorResult& aRv);
void GetPreviewStream(JSContext* cx, JS::Handle<JS::Value> aOptions, nsICameraPreviewStreamCallback* onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
void ResumePreview(ErrorResult& aRv);
void ReleaseHardware(const dom::Optional<nsICameraReleaseCallback* >& onSuccess, const dom::Optional<nsICameraErrorCallback* >& onError, ErrorResult& aRv);
protected:
virtual ~nsDOMCameraControl();
@ -44,12 +98,15 @@ private:
nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
protected:
/* additional members */
nsRefPtr<ICameraControl> mCameraControl; // non-DOM camera control
nsCOMPtr<nsICameraCapabilities> mDOMCapabilities;
// An agent used to join audio channel service.
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
nsCOMPtr<nsPIDOMWindow> mWindow;
};
} // namespace mozilla

View File

@ -127,9 +127,9 @@ nsDOMCameraManager::GetCamera(const CameraSelector& aOptions,
DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
// Creating this object will trigger the onSuccess handler
nsCOMPtr<nsDOMCameraControl> cameraControl =
nsRefPtr<nsDOMCameraControl> cameraControl =
new nsDOMCameraControl(cameraId, mCameraThread,
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindowId);
onSuccess, onError.WasPassed() ? onError.Value() : nullptr, mWindow);
Register(cameraControl);
}

View File

@ -59,8 +59,10 @@ private:
* store a reference in the 'mCameraControl' member (which is why it is
* defined here).
*/
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId)
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow) :
mWindow(aWindow)
{
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
}
/**

View File

@ -143,9 +143,10 @@ static const char* getKeyText(uint32_t aKey)
}
// nsDOMCameraControl implementation-specific constructor
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, uint64_t aWindowId)
: mDOMCapabilities(nullptr)
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThread, nsICameraGetCameraCallback* onSuccess, nsICameraErrorCallback* onError, nsPIDOMWindow* aWindow)
: mDOMCapabilities(nullptr), mWindow(aWindow)
{
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
/**
@ -160,8 +161,8 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
* nsDOMCameraControl or memory will leak!
*/
NS_ADDREF_THIS();
nsRefPtr<nsGonkCameraControl> control = new nsGonkCameraControl(aCameraId, aCameraThread, this, onSuccess, onError, aWindowId);
control->DispatchInit(this, onSuccess, onError, aWindowId);
nsRefPtr<nsGonkCameraControl> control = new nsGonkCameraControl(aCameraId, aCameraThread, this, onSuccess, onError, aWindow->WindowID());
control->DispatchInit(this, onSuccess, onError, aWindow->WindowID());
mCameraControl = control;
}

View File

@ -217,171 +217,8 @@ interface nsICameraErrorCallback : nsISupports
void handleEvent(in DOMString error);
};
/*
attributes here affect the preview, any pictures taken, and/or
any video recorded by the camera.
*/
[scriptable, uuid(74dc7f1f-c88f-4774-860b-44aef9de5dc8)]
interface nsICameraControl : nsISupports
{
readonly attribute nsICameraCapabilities capabilities;
/* one of the vales chosen from capabilities.effects;
default is "none" */
attribute DOMString effect;
/* one of the values chosen from capabilities.whiteBalanceModes;
default is "auto" */
attribute DOMString whiteBalanceMode;
/* one of the valus chosen from capabilities.sceneModes;
default is "auto" */
attribute DOMString sceneMode;
/* one of the values chosen from capabilities.flashModes;
default is "auto" */
attribute DOMString flashMode;
/* one of the values chosen from capabilities.focusModes;
default is "auto", if supported, or "fixed" */
attribute DOMString focusMode;
/* one of the values chosen from capabilities.zoomRatios; other
values will be rounded to the nearest supported value;
default is 1.0 */
attribute double zoom;
/* an array of one or more objects that define where the
camera will perform light metering, each defining the properties:
{
top: -1000,
left: -1000,
bottom: 1000,
right: 1000,
weight: 1000
}
'top', 'left', 'bottom', and 'right' all range from -1000 at
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
of the sensor.
objects missing one or more of these properties will be ignored;
if the array contains more than capabilities.maxMeteringAreas,
extra areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to perform light metering. */
[implicit_jscontext]
attribute jsval meteringAreas;
/* an array of one or more objects that define where the camera will
perform auto-focusing, with the same definition as meteringAreas.
if the array contains more than capabilities.maxFocusAreas, extra
areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to focus. */
[implicit_jscontext]
attribute jsval focusAreas;
/* focal length in millimetres */
readonly attribute double focalLength;
/* the distances in metres to where the image subject appears to be
in focus. 'focusDistanceOptimum' is where the subject will appear
sharpest; the difference between 'focusDistanceFar' and
'focusDistanceNear' is the image's depth of field.
'focusDistanceFar' may be infinity. */
readonly attribute double focusDistanceNear;
readonly attribute double focusDistanceOptimum;
readonly attribute double focusDistanceFar;
/* 'compensation' is optional, and if missing, will
set the camera to use automatic exposure compensation.
acceptable values must range from minExposureCompensation
to maxExposureCompensation in steps of stepExposureCompensation;
invalid values will be rounded to the nearest valid value. */
[implicit_jscontext]
void setExposureCompensation([optional] in jsval compensation);
readonly attribute double exposureCompensation;
/* the function to call on the camera's shutter event, to trigger
a shutter sound and/or a visual shutter indicator. */
attribute nsICameraShutterCallback onShutter;
/* the function to call when the camera hardware is closed
by the underlying framework, e.g. when another app makes a more
recent call to get the camera. */
attribute nsICameraClosedCallback onClosed;
/* the function to call when the recorder changes state, either because
the recording process encountered an error, or because one of the
recording limits (see CameraStartRecordingOptions) was reached. */
attribute nsICameraRecorderStateChange onRecorderStateChange;
/* the function to call when the preview stream is actually started and
stopped; this is usually used to enable and disable the camera UI,
since the low-level hardware often does not support taking pictures
unless the preview is running. */
attribute nsICameraPreviewStateChange onPreviewStateChange;
/* tell the camera to attempt to focus the image */
void autoFocus(in nsICameraAutoFocusCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* capture an image and return it as a blob to the 'onSuccess' callback;
if the camera supports it, this may be invoked while the camera is
already recording video.
invoking this function will stop the preview stream, which must be
manually restarted (e.g. by calling .play() on it). */
[implicit_jscontext]
void takePicture(in jsval aOptions, in nsICameraTakePictureCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* get a media stream to be used as a camera viewfinder in video mode;
'aOptions' is an CameraRecorderOptions object. */
[implicit_jscontext]
void getPreviewStreamVideoMode(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* start recording video; 'aOptions' is a
CameraStartRecordingOptions object. */
[implicit_jscontext]
void startRecording(in jsval aOptions, in nsIDOMDeviceStorage storageArea, in DOMString filename, in nsICameraStartRecordingCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* stop precording video. */
void stopRecording();
/* get a media stream to be used as a camera viewfinder; the options
define the desired frame size of the preview, chosen from
capabilities.previewSizes, e.g.:
{
height: 640,
width: 480,
}
*/
[implicit_jscontext]
void getPreviewStream(in jsval aOptions, in nsICameraPreviewStreamCallback onSuccess, [optional] in nsICameraErrorCallback onError);
/* call in or after the takePicture() onSuccess callback to
resume the camera preview stream. */
void resumePreview();
/* release the camera so that other applications can use it; you should
probably call this whenever the camera is not longer in the foreground
(depending on your usage model).
the callbacks are optional, unless you really need to know when
the hardware is ultimately released.
once this is called, the camera control object is to be considered
defunct; a new instance will need to be created to access the camera. */
[binaryname(ReleaseHardware)] void release([optional] in nsICameraReleaseCallback onSuccess, [optional] in nsICameraErrorCallback onError);
};
[scriptable, function, uuid(a267afbc-d91c-413a-8de5-0b94aecffa3e)]
[scriptable, function, uuid(16de7703-dc43-4766-99c5-ff30a9ab92d7)]
interface nsICameraGetCameraCallback : nsISupports
{
void handleEvent(in nsICameraControl camera);
void handleEvent(in nsISupports camera);
};

View File

@ -30,7 +30,6 @@ include URIParams;
include "mozilla/chrome/RegistryMessageUtils.h";
include "mozilla/dom/PermissionMessageUtils.h";
include "mozilla/dom/TabMessageUtils.h";
include "mozilla/dom/Element.h";
include "mozilla/HalTypes.h";
include "mozilla/layout/RenderFrameUtils.h";
include "mozilla/net/NeckoMessageUtils.h";

View File

@ -14,3 +14,5 @@ InvalidSTSHeaders=The site specified an invalid Strict-Transport-Security header
InsecurePasswordsPresentOnPage=Password fields present on an insecure (http://) page. This is a security risk that allows user login credentials to be stolen.
InsecureFormActionPasswordsPresent=Password fields present in a form with an insecure (http://) form action. This is a security risk that allows user login credentials to be stolen.
InsecurePasswordsPresentOnIframe=Password fields present on an insecure (http://) iframe. This is a security risk that allows user login credentials to be stolen.
LoadingMixedActiveContent=Loading mixed (insecure) active content on a secure page "%1$S"
LoadingMixedDisplayContent=Loading mixed (insecure) display content on a secure page "%1$S"

View File

@ -312,6 +312,17 @@ public:
}
}
// let us intervene for direct listeners when someone does track.enabled = false
virtual void SetTrackEnabled(TrackID aID, bool aEnabled) MOZ_OVERRIDE
{
// We encapsulate the SourceMediaStream and TrackUnion into one entity, so
// we can handle the disabling at the SourceMediaStream
// We need to find the input track ID for output ID aID, so we let the TrackUnion
// forward the request to the source and translate the ID
GetStream()->AsProcessedStream()->ForwardTrackEnabled(aID, aEnabled);
}
// The actual MediaStream is a TrackUnionStream. But these resources need to be
// explicitly destroyed too.
nsRefPtr<SourceMediaStream> mSourceStream;

View File

@ -1015,6 +1015,7 @@ PeerConnectionObserver.prototype = {
},
handleIceStateChanges: function(iceState) {
var histogram = Services.telemetry.getHistogramById("WEBRTC_ICE_SUCCESS_RATE");
switch (iceState) {
case Ci.IPeerConnection.kIceWaiting:
this._dompc.changeIceConnectionState("new");
@ -1033,10 +1034,12 @@ PeerConnectionObserver.prototype = {
break;
case Ci.IPeerConnection.kIceConnected:
// ICE gathering complete.
histogram.add(true);
this._dompc.changeIceConnectionState("connected");
this.callCB(this._onicechange, "connected");
break;
case Ci.IPeerConnection.kIceFailed:
histogram.add(false);
this._dompc.changeIceConnectionState("failed");
this.callCB(this._onicechange, "failed");
break;

View File

@ -5,7 +5,7 @@ fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
fails-if(!haveTestPlugin) == plugin-asyncbitmap-sanity.html div-sanity.html
fails-if(!haveTestPlugin) == plugin-asyncdxgi-sanity.html div-sanity.html
skip-if(!haveTestPlugin) == plugin-asyncbitmap-update.html plugin-async-update-ref.html
skip-if(!haveTestPlugin) == plugin-asyncdxgi-update.html plugin-async-update-ref.html
random-if(OSX==10.6||OSX==10.7) skip-if(!haveTestPlugin) == plugin-asyncdxgi-update.html plugin-async-update-ref.html
fails-if(!haveTestPlugin) == plugin-alpha-zindex.html div-alpha-zindex.html
fails-if(!haveTestPlugin) == plugin-alpha-opacity.html div-alpha-opacity.html
random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html # bug 631832

View File

@ -0,0 +1,195 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
interface CameraCapabilities;
interface GetCameraCallback;
interface CameraErrorCallback;
interface CameraShutterCallback;
interface CameraClosedCallback;
interface CameraRecorderStateChange;
interface CameraAutoFocusCallback;
interface CameraTakePictureCallback;
interface CameraPreviewStateChange;
interface CameraPreviewStreamCallback;
interface CameraStartRecordingCallback;
interface CameraReleaseCallback;
/*
attributes here affect the preview, any pictures taken, and/or
any video recorded by the camera.
*/
interface CameraControl {
readonly attribute CameraCapabilities capabilities;
/* one of the values chosen from capabilities.effects;
default is "none" */
[Throws]
attribute DOMString effect;
/* one of the values chosen from capabilities.whiteBalanceModes;
default is "auto" */
[Throws]
attribute DOMString whiteBalanceMode;
/* one of the values chosen from capabilities.sceneModes;
default is "auto" */
[Throws]
attribute DOMString sceneMode;
/* one of the values chosen from capabilities.flashModes;
default is "auto" */
[Throws]
attribute DOMString flashMode;
/* one of the values chosen from capabilities.focusModes;
default is "auto", if supported, or "fixed" */
[Throws]
attribute DOMString focusMode;
/* one of the values chosen from capabilities.zoomRatios; other
values will be rounded to the nearest supported value;
default is 1.0 */
[Throws]
attribute double zoom;
/* an array of one or more objects that define where the
camera will perform light metering, each defining the properties:
{
top: -1000,
left: -1000,
bottom: 1000,
right: 1000,
weight: 1000
}
'top', 'left', 'bottom', and 'right' all range from -1000 at
the top-/leftmost of the sensor to 1000 at the bottom-/rightmost
of the sensor.
objects missing one or more of these properties will be ignored;
if the array contains more than capabilities.maxMeteringAreas,
extra areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to perform light metering. */
[Throws]
attribute any meteringAreas;
/* an array of one or more objects that define where the camera will
perform auto-focusing, with the same definition as meteringAreas.
if the array contains more than capabilities.maxFocusAreas, extra
areas will be ignored.
this attribute can be set to null to allow the camera to determine
where to focus. */
[Throws]
attribute any focusAreas;
/* focal length in millimetres */
[Throws]
readonly attribute double focalLength;
/* the distances in metres to where the image subject appears to be
in focus. 'focusDistanceOptimum' is where the subject will appear
sharpest; the difference between 'focusDistanceFar' and
'focusDistanceNear' is the image's depth of field.
'focusDistanceFar' may be infinity. */
[Throws]
readonly attribute double focusDistanceNear;
[Throws]
readonly attribute double focusDistanceOptimum;
[Throws]
readonly attribute unrestricted double focusDistanceFar;
/* 'compensation' is optional, and if missing, will
set the camera to use automatic exposure compensation.
acceptable values must range from minExposureCompensation
to maxExposureCompensation in steps of stepExposureCompensation;
invalid values will be rounded to the nearest valid value. */
[Throws]
void setExposureCompensation(optional double compensation);
[Throws]
readonly attribute unrestricted double exposureCompensation;
/* the function to call on the camera's shutter event, to trigger
a shutter sound and/or a visual shutter indicator. */
[Throws]
attribute CameraShutterCallback? onShutter;
/* the function to call when the camera hardware is closed
by the underlying framework, e.g. when another app makes a more
recent call to get the camera. */
[Throws]
attribute CameraClosedCallback? onClosed;
/* the function to call when the recorder changes state, either because
the recording process encountered an error, or because one of the
recording limits (see CameraStartRecordingOptions) was reached. */
[Throws]
attribute CameraRecorderStateChange? onRecorderStateChange;
attribute CameraPreviewStateChange? onPreviewStateChange;
/* tell the camera to attempt to focus the image */
[Throws]
void autoFocus(CameraAutoFocusCallback onSuccess, optional CameraErrorCallback onError);
/* capture an image and return it as a blob to the 'onSuccess' callback;
if the camera supports it, this may be invoked while the camera is
already recording video.
invoking this function will stop the preview stream, which must be
manually restarted (e.g. by calling .play() on it). */
[Throws]
void takePicture(CameraPictureOptions aOptions,
CameraTakePictureCallback onSuccess,
optional CameraErrorCallback onError);
/* get a media stream to be used as a camera viewfinder in video mode;
'aOptions' is an CameraRecorderOptions object. */
[Throws]
void getPreviewStreamVideoMode(any aOptions, CameraPreviewStreamCallback onSuccess, optional CameraErrorCallback onError);
/* start recording video; 'aOptions' is a
CameraStartRecordingOptions object. */
[Throws]
void startRecording(any aOptions, DeviceStorage storageArea, DOMString filename, CameraStartRecordingCallback onSuccess, optional CameraErrorCallback onError);
/* stop precording video. */
[Throws]
void stopRecording();
/* get a media stream to be used as a camera viewfinder; the options
define the desired frame size of the preview, chosen from
capabilities.previewSizes, e.g.:
{
height: 640,
width: 480,
}
*/
[Throws]
void getPreviewStream(any aOptions, CameraPreviewStreamCallback onSuccess, optional CameraErrorCallback onError);
/* call in or after the takePicture() onSuccess callback to
resume the camera preview stream. */
[Throws]
void resumePreview();
/* release the camera so that other applications can use it; you should
probably call this whenever the camera is not longer in the foreground
(depending on your usage model).
the callbacks are optional, unless you really need to know when
the hardware is ultimately released.
once this is called, the camera control object is to be considered
defunct; a new instance will need to be created to access the camera. */
[Throws]
void release(optional CameraReleaseCallback onSuccess, optional CameraErrorCallback onError);
};

View File

@ -207,6 +207,12 @@ interface CanvasRenderingContext2D {
void asyncDrawXULElement(XULElement elem, double x, double y, double w,
double h, DOMString bgColor,
optional unsigned long flags = 0);
/**
* This causes a context that is currently using a hardware-accelerated
* backend to fallback to a software one. All state should be preserved.
*/
[ChromeOnly]
void demote();
};
CanvasRenderingContext2D implements CanvasDrawingStyles;
CanvasRenderingContext2D implements CanvasPathMethods;

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