mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 14:25:52 +00:00
Merge m-c to b2g-inbound.
This commit is contained in:
commit
8a77e0943c
2
CLOBBER
2
CLOBBER
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
103
browser/base/content/test/browser_CTP_context_menu.js
Normal file
103
browser/base/content/test/browser_CTP_context_menu.js
Normal 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();
|
||||
}
|
@ -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");
|
||||
|
@ -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) {
|
||||
|
@ -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"/>
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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));
|
||||
|
@ -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>
|
@ -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":
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
119
browser/metro/base/tests/mochitest/browser_snappedState.js
Normal file
119
browser/metro/base/tests/mochitest/browser_snappedState.js
Normal 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
|
||||
});
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
@ -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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
.devtools-monospace {
|
||||
font-family: monospace;
|
||||
font-size: 85%;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/* Toolbar and Toolbar items */
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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%;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
.devtools-monospace {
|
||||
font-family: monospace;
|
||||
font-size: 108%;
|
||||
}
|
||||
|
||||
/* Toolbar and Toolbar items */
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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'):
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
290
content/canvas/src/WebGLContextExtensions.cpp
Normal file
290
content/canvas/src/WebGLContextExtensions.cpp
Normal 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"));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ if CONFIG['MOZ_WEBGL']:
|
||||
'WebGLContextReporter.cpp',
|
||||
'WebGLContextState.cpp',
|
||||
'WebGLContextValidate.cpp',
|
||||
'WebGLContextExtensions.cpp',
|
||||
'WebGLContextFramebufferOperations.cpp',
|
||||
'WebGLContextVertexArray.cpp',
|
||||
'WebGLContextVertices.cpp',
|
||||
|
@ -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
|
||||
|
44
content/canvas/test/test_bug902651.html
Normal file
44
content/canvas/test/test_bug902651.html
Normal 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
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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());
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define nsIXMLContentSink_h___
|
||||
|
||||
#include "nsIContentSink.h"
|
||||
#include "nsIParserNode.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIDocument;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -140,7 +140,6 @@ DOMCI_CLASS(FMRadio)
|
||||
DOMCI_CLASS(BluetoothDevice)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(CameraControl)
|
||||
DOMCI_CLASS(CameraCapabilities)
|
||||
|
||||
DOMCI_CLASS(LockedFile)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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!");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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";
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
195
dom/webidl/CameraControl.webidl
Normal file
195
dom/webidl/CameraControl.webidl
Normal 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);
|
||||
};
|
@ -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
Loading…
Reference in New Issue
Block a user