mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Merge m-c to b2ginbound, a=merge
This commit is contained in:
commit
9b191c89ba
@ -417,14 +417,6 @@ this.AccessFu = { // jshint ignore:line
|
||||
let dpr = win.devicePixelRatio;
|
||||
let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
|
||||
|
||||
if (!aBrowser.contentWindow) {
|
||||
// OOP browser, add offset of browser.
|
||||
// The offset of the browser element in relation to its parent window.
|
||||
let clientRect = aBrowser.getBoundingClientRect();
|
||||
let win = aBrowser.ownerDocument.defaultView;
|
||||
offset.left += clientRect.left + win.mozInnerScreenX;
|
||||
offset.top += clientRect.top + win.mozInnerScreenY;
|
||||
}
|
||||
// Add the offset; the offset is in CSS pixels, so multiply the
|
||||
// devicePixelRatio back in before adding to preserve unit consistency.
|
||||
bounds = bounds.translate(offset.left * dpr, offset.top * dpr);
|
||||
|
@ -357,8 +357,8 @@ function runTest(testNum) {
|
||||
// Context menu for textarea before spell check initialization finishes
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null,
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -377,8 +377,8 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -409,8 +409,8 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -434,8 +434,8 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -650,8 +650,8 @@ function runTest(testNum) {
|
||||
// Context menu for selected text in input[type="password"]
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", true,
|
||||
"---", null,
|
||||
@ -743,8 +743,8 @@ function runTest(testNum) {
|
||||
// Context menu for text input field with spellcheck=false
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
|
@ -40,8 +40,8 @@ function runTest(testNum) {
|
||||
// Context menu for text input field.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -61,8 +61,8 @@ function runTest(testNum) {
|
||||
// Context menu for spell-check input.
|
||||
checkContextMenu(["context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", value,
|
||||
"context-copy", value,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
@ -90,8 +90,8 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", value,
|
||||
"context-copy", value,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
@ -115,8 +115,8 @@ function runTest(testNum) {
|
||||
// Context menu for spell-check input with a known word.
|
||||
checkContextMenu(["context-undo", value,
|
||||
"---", null,
|
||||
"context-cut", value,
|
||||
"context-copy", value,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", value,
|
||||
"---", null,
|
||||
@ -139,8 +139,8 @@ function runTest(testNum) {
|
||||
// Context menu for disabled input.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -157,15 +157,11 @@ function runTest(testNum) {
|
||||
break;
|
||||
|
||||
case 7: // password
|
||||
case 8: // email
|
||||
case 9: // url
|
||||
case 10: // tel
|
||||
case 11: // type='number'
|
||||
// Context menu for tel, password, email, url and number input fields.
|
||||
// Context menu for password input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -175,9 +171,30 @@ function runTest(testNum) {
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
if (testNum == 7) {
|
||||
input.type = 'email';
|
||||
} else if (testNum == 8) {
|
||||
input.type = 'email';
|
||||
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 8: // email
|
||||
case 9: // url
|
||||
case 10: // tel
|
||||
case 11: // type='number'
|
||||
// Context menu for tel, email, url and number input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", false,
|
||||
"---", null,
|
||||
"context-inspect", true]);
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
if (testNum == 8) {
|
||||
input.type = 'url';
|
||||
} else if (testNum == 9) {
|
||||
input.type = 'tel';
|
||||
@ -228,8 +245,8 @@ function runTest(testNum) {
|
||||
// Context menu for search input fields.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
@ -257,8 +274,8 @@ function runTest(testNum) {
|
||||
// Context menu for a read-only input.
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-cut", true,
|
||||
"context-copy", true,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
|
@ -19,7 +19,7 @@ add_task(function() {
|
||||
|
||||
let copyButton = document.getElementById("copy-button");
|
||||
ok(copyButton, "Copy button exists in Panel Menu");
|
||||
is(copyButton.getAttribute("disabled"), "true", "Copy button is initially disabled");
|
||||
ok(!copyButton.getAttribute("disabled"), "Copy button is initially enabled");
|
||||
|
||||
// copy text from URL bar
|
||||
gURLBar.value = testText;
|
||||
@ -28,7 +28,7 @@ add_task(function() {
|
||||
yield PanelUI.show();
|
||||
info("Menu panel was opened");
|
||||
|
||||
ok(!copyButton.hasAttribute("disabled"), "Copy button gets enabled");
|
||||
ok(!copyButton.hasAttribute("disabled"), "Copy button is enabled when selecting");
|
||||
|
||||
copyButton.click();
|
||||
is(gURLBar.value, testText, "Selected text is unaltered when clicking copy");
|
||||
|
@ -18,7 +18,7 @@ add_task(function() {
|
||||
|
||||
let cutButton = document.getElementById("cut-button");
|
||||
ok(cutButton, "Cut button exists in Panel Menu");
|
||||
ok(cutButton.getAttribute("disabled"), "Cut button is disabled");
|
||||
ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled");
|
||||
|
||||
// cut text from URL bar
|
||||
gURLBar.value = testText;
|
||||
@ -27,7 +27,7 @@ add_task(function() {
|
||||
yield PanelUI.show();
|
||||
info("Menu panel was opened");
|
||||
|
||||
ok(!cutButton.hasAttribute("disabled"), "Cut button gets enabled");
|
||||
ok(!cutButton.hasAttribute("disabled"), "Cut button is enabled when selecting");
|
||||
cutButton.click();
|
||||
is(gURLBar.value, "", "Selected text is removed from source when clicking on cut");
|
||||
|
||||
|
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
|
||||
var errorString;
|
||||
switch (this.props.failureReason) {
|
||||
case FAILURE_DETAILS.NO_MEDIA:
|
||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||
errorString = mozL10n.get("no_media_failure_message");
|
||||
break;
|
||||
|
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
|
||||
var errorString;
|
||||
switch (this.props.failureReason) {
|
||||
case FAILURE_DETAILS.NO_MEDIA:
|
||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||
errorString = mozL10n.get("no_media_failure_message");
|
||||
break;
|
||||
|
@ -978,7 +978,7 @@ loop.OTSdkDriver = (function() {
|
||||
|
||||
var bucket = this.mozLoop.SHARING_STATE_CHANGE[type.toUpperCase() + "_" +
|
||||
(enabled ? "ENABLED" : "DISABLED")];
|
||||
if (!bucket) {
|
||||
if (typeof bucket === "undefined") {
|
||||
console.error("No sharing state bucket found for '" + type + "'");
|
||||
return;
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ let LoopRoomsInternal = {
|
||||
* @param {String} roomToken The token for the room that needs encrypting.
|
||||
*/
|
||||
queueForEncryption: function(roomToken) {
|
||||
if (!this.encryptionQueue.queue.includes(roomToken)) {
|
||||
if (this.encryptionQueue.queue.indexOf(roomToken) == -1) {
|
||||
this.encryptionQueue.queue.push(roomToken);
|
||||
}
|
||||
|
||||
|
@ -939,6 +939,15 @@ describe("loop.conversationViews", function () {
|
||||
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||
});
|
||||
|
||||
it("should show 'no media' for FAILURE_DETAILS.NO_MEDIA reason", function() {
|
||||
view = mountTestComponent({
|
||||
cancelCall: function() {},
|
||||
failureReason: FAILURE_DETAILS.NO_MEDIA
|
||||
});
|
||||
|
||||
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||
});
|
||||
|
||||
it("should show 'generic_failure_title' when no reason is specified", function() {
|
||||
view = mountTestComponent({cancelCall: function() {}});
|
||||
|
||||
|
@ -78,16 +78,16 @@ describe("loop.OTSdkDriver", function () {
|
||||
mozLoop = {
|
||||
telemetryAddValue: sinon.stub(),
|
||||
TWO_WAY_MEDIA_CONN_LENGTH: {
|
||||
SHORTER_THAN_10S: "SHORTER_THAN_10S",
|
||||
BETWEEN_10S_AND_30S: "BETWEEN_10S_AND_30S",
|
||||
BETWEEN_30S_AND_5M: "BETWEEN_30S_AND_5M",
|
||||
MORE_THAN_5M: "MORE_THAN_5M"
|
||||
SHORTER_THAN_10S: 0,
|
||||
BETWEEN_10S_AND_30S: 1,
|
||||
BETWEEN_30S_AND_5M: 2,
|
||||
MORE_THAN_5M: 3
|
||||
},
|
||||
SHARING_STATE_CHANGE: {
|
||||
WINDOW_ENABLED: "WINDOW_ENABLED",
|
||||
WINDOW_DISABLED: "WINDOW_DISABLED",
|
||||
BROWSER_ENABLED: "BROWSER_ENABLED",
|
||||
BROWSER_DISABLED: "BROWSER_DISABLED"
|
||||
WINDOW_ENABLED: 0,
|
||||
WINDOW_DISABLED: 1,
|
||||
BROWSER_ENABLED: 2,
|
||||
BROWSER_DISABLED: 3
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -190,8 +190,8 @@ EventEmitter.decorate(this);
|
||||
/**
|
||||
* DOM query helpers.
|
||||
*/
|
||||
function $(selector, target = document) target.querySelector(selector);
|
||||
function $all(selector, target = document) target.querySelectorAll(selector);
|
||||
let $ = (selector, target = document) => target.querySelector(selector);
|
||||
let $all = (selector, target = document) => target.querySelectorAll(selector);
|
||||
|
||||
/**
|
||||
* Helper for getting an nsIURL instance out of a string.
|
||||
|
@ -57,7 +57,9 @@ CanvasDebuggerPanel.prototype = {
|
||||
|
||||
// DevToolPanel API
|
||||
|
||||
get target() this._toolbox.target,
|
||||
get target() {
|
||||
return this._toolbox.target;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
// Make sure this panel is not already destroyed.
|
||||
|
@ -6,7 +6,7 @@
|
||||
* You can also use this initialization format as a template for other tests.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
ok(target, "Should have a target available.");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* and that their stack is successfully retrieved.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* for a canvas context.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* the correct thumbnails.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* the correct "end result" screenshot.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if screenshots for arbitrary draw calls are generated properly.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_TRANSPARENT_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* by deferring the the most recent previous draw-call.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_BITMASKS_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* after generating screenshots using the actor.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_BINDINGS_URL);
|
||||
loadFrameScripts();
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* for a canvas context, and that the generated screenshots are correct.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(SET_TIMEOUT_URL);
|
||||
|
||||
let navigated = once(target, "navigate");
|
||||
|
@ -6,7 +6,7 @@
|
||||
* in the event no rAF loop is found.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, front } = yield initCanvasDebuggerBackend(NO_CANVAS_URL);
|
||||
loadFrameScripts();
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if certain function calls are properly highlighted in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if filtering the items in the call list works properly.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
let searchbox = $("#calls-searchbox");
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if the a function call's stack is properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* and jumping to source in the debugger for the topmost call item works.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* on a function call item.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if clearing the snapshots list works as expected.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if screenshots are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if thumbnails are properly displayed in the UI.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* function call items and their respective screenshots.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests that the frontend UI is properly configured when opening the tool.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { $ } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests whether the frontend behaves correctly while reording a snapshot.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests whether the frontend displays a placeholder snapshot while recording.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, L10N, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* after finishing recording.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
* of its loop, when the recording starts before the rAFs start.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_BEGIN_URL);
|
||||
let { window, EVENTS, gFront, SnapshotsListView } = panel.panelWin;
|
||||
loadFrameScripts();
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if the slider in the calls list view works as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if the slider in the calls list view works as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, gFront, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* respective to their recorded animation frame.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* respective to their recorded animation frame.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests if the stepping buttons in the call list toolbar work as advertised.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests that you can stop a recording that does not have a rAF cycle.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Tests that a recording that does not have a rAF cycle fails after timeout.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* after timeout.
|
||||
*/
|
||||
|
||||
function ifTestingSupported() {
|
||||
function* ifTestingSupported() {
|
||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_NO_CANVAS_URL);
|
||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||
|
||||
|
@ -119,7 +119,7 @@ function runTests()
|
||||
};
|
||||
|
||||
let firstShow = function() {
|
||||
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled");
|
||||
ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled");
|
||||
closeMenu(firstHide);
|
||||
};
|
||||
|
||||
@ -149,7 +149,7 @@ function runTests()
|
||||
};
|
||||
|
||||
let showAfterCut = function() {
|
||||
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after cut");
|
||||
ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after cut");
|
||||
ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after cut");
|
||||
closeMenu(hideAfterCut);
|
||||
};
|
||||
@ -167,7 +167,7 @@ function runTests()
|
||||
};
|
||||
|
||||
let showAfterPaste = function() {
|
||||
ok(cutItem.hasAttribute("disabled"), "cut menuitem is disabled after paste");
|
||||
ok(!cutItem.hasAttribute("disabled"), "cut menuitem is enabled after paste");
|
||||
ok(!pasteItem.hasAttribute("disabled"), "paste menuitem is enabled after paste");
|
||||
closeMenu(hideAfterPaste);
|
||||
};
|
||||
|
@ -66,6 +66,7 @@ support-files =
|
||||
[browser_graphs-09f.js]
|
||||
[browser_graphs-10a.js]
|
||||
[browser_graphs-10b.js]
|
||||
[browser_graphs-10c.js]
|
||||
[browser_graphs-11a.js]
|
||||
[browser_graphs-11b.js]
|
||||
[browser_graphs-12.js]
|
||||
|
86
browser/devtools/shared/test/browser_graphs-10c.js
Normal file
86
browser/devtools/shared/test/browser_graphs-10c.js
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
// Tests that graphs properly handle resizing.
|
||||
|
||||
const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
|
||||
let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
|
||||
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
|
||||
|
||||
add_task(function*() {
|
||||
yield promiseTab("about:blank");
|
||||
yield performTest();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function* performTest() {
|
||||
let [host, win, doc] = yield createHost("window");
|
||||
doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
|
||||
|
||||
let graph = new LineGraphWidget(doc.body, "fps");
|
||||
yield graph.once("ready");
|
||||
|
||||
let refreshCount = 0;
|
||||
graph.on("refresh", () => refreshCount++);
|
||||
|
||||
yield testGraph(host, graph);
|
||||
|
||||
is(refreshCount, 2, "The graph should've been refreshed 2 times.");
|
||||
|
||||
yield graph.destroy();
|
||||
host.destroy();
|
||||
}
|
||||
|
||||
function* testGraph(host, graph) {
|
||||
graph.setData(TEST_DATA);
|
||||
|
||||
host._window.resizeTo(500, 500);
|
||||
yield graph.once("refresh");
|
||||
let oldBounds = host.frame.getBoundingClientRect();
|
||||
|
||||
is (graph._width, oldBounds.width * window.devicePixelRatio,
|
||||
"The window was properly resized (1).");
|
||||
is (graph._height, oldBounds.height * window.devicePixelRatio,
|
||||
"The window was properly resized (1).");
|
||||
|
||||
dragStart(graph, 100);
|
||||
dragStop(graph, 400);
|
||||
|
||||
is(graph.getSelection().start, 100,
|
||||
"The current selection start value is correct (1).");
|
||||
is(graph.getSelection().end, 400,
|
||||
"The current selection end value is correct (1).");
|
||||
|
||||
info("Making sure the selection updates when the window is resized");
|
||||
|
||||
host._window.resizeTo(250, 250);
|
||||
yield graph.once("refresh");
|
||||
let newBounds = host.frame.getBoundingClientRect();
|
||||
|
||||
is (graph._width, newBounds.width * window.devicePixelRatio,
|
||||
"The window was properly resized (2).");
|
||||
is (graph._height, newBounds.height * window.devicePixelRatio,
|
||||
"The window was properly resized (2).");
|
||||
|
||||
let ratio = oldBounds.width / newBounds.width;
|
||||
info("The window resize ratio is: " + ratio);
|
||||
|
||||
is(graph.getSelection().start, Math.round(100 / ratio),
|
||||
"The current selection start value is correct (2).");
|
||||
is(graph.getSelection().end, Math.round(400 / ratio),
|
||||
"The current selection end value is correct (2).");
|
||||
}
|
||||
|
||||
// EventUtils just doesn't work!
|
||||
|
||||
function dragStart(graph, x, y = 1) {
|
||||
x /= window.devicePixelRatio;
|
||||
y /= window.devicePixelRatio;
|
||||
graph._onMouseMove({ testX: x, testY: y });
|
||||
graph._onMouseDown({ testX: x, testY: y });
|
||||
}
|
||||
|
||||
function dragStop(graph, x, y = 1) {
|
||||
x /= window.devicePixelRatio;
|
||||
y /= window.devicePixelRatio;
|
||||
graph._onMouseMove({ testX: x, testY: y });
|
||||
graph._onMouseUp({ testX: x, testY: y });
|
||||
}
|
@ -684,6 +684,13 @@ AbstractCanvasGraph.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle a changed size by mapping the old selection to the new width
|
||||
if (this._width && newWidth && this.hasSelection()) {
|
||||
let ratio = this._width / (newWidth * this._pixelRatio);
|
||||
this._selection.start = Math.round(this._selection.start / ratio);
|
||||
this._selection.end = Math.round(this._selection.end / ratio);
|
||||
}
|
||||
|
||||
bounds.width = newWidth;
|
||||
bounds.height = newHeight;
|
||||
this._iframe.setAttribute("width", bounds.width);
|
||||
|
@ -151,6 +151,7 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
|
||||
this._onClick = this._onClick.bind(this);
|
||||
this._onCopy = this._onCopy.bind(this);
|
||||
this._onCopyColor = this._onCopyColor.bind(this);
|
||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||
this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
|
||||
this._onClearSearch = this._onClearSearch.bind(this);
|
||||
@ -328,7 +329,7 @@ CssHtmlTree.prototype = {
|
||||
* - type {String} One of the VIEW_NODE_XXX_TYPE const in
|
||||
* style-inspector-overlays
|
||||
* - value {Object} Depends on the type of the node
|
||||
* returns null of the node isn't anything we care about
|
||||
* returns null if the node isn't anything we care about
|
||||
*/
|
||||
getNodeInfo: function(node) {
|
||||
if (!node) {
|
||||
@ -351,7 +352,7 @@ CssHtmlTree.prototype = {
|
||||
return {
|
||||
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
||||
value: selectorText.trim()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Walk up the nodes to find out where node is
|
||||
@ -715,6 +716,13 @@ CssHtmlTree.prototype = {
|
||||
command: this._onCopyColor
|
||||
});
|
||||
|
||||
// Copy data URI
|
||||
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||
command: this._onCopyImageDataUrl
|
||||
});
|
||||
|
||||
// Show Original Sources
|
||||
this.menuitemSources= createMenuItem(this._contextmenu, {
|
||||
label: "ruleView.contextmenu.showOrigSources",
|
||||
@ -745,6 +753,7 @@ CssHtmlTree.prototype = {
|
||||
this.menuitemSources.setAttribute("checked", showOrig);
|
||||
|
||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -757,14 +766,12 @@ CssHtmlTree.prototype = {
|
||||
_isColorPopup: function () {
|
||||
this._colorToCopy = "";
|
||||
|
||||
let trigger = this.popupNode;
|
||||
if (!trigger) {
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
||||
trigger.parentElement : trigger;
|
||||
|
||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||
|
||||
while (!isColorNode(container)) {
|
||||
@ -778,6 +785,52 @@ CssHtmlTree.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the context menu popup was opened with a click on an image link
|
||||
* If true, save the image url to this._imageUrlToCopy
|
||||
*/
|
||||
_isImageUrlPopup: function () {
|
||||
this._imageUrlToCopy = "";
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
let isImageUrlNode = this._isImageUrlNode(container);
|
||||
if (isImageUrlNode) {
|
||||
this._imageUrlToCopy = container.href;
|
||||
}
|
||||
|
||||
return isImageUrlNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a node is an image url
|
||||
* @param {DOMNode} node The node which we want information about
|
||||
* @return {Boolean} true if the node is an image url
|
||||
*/
|
||||
_isImageUrlNode: function (node) {
|
||||
let nodeInfo = this.getNodeInfo(node);
|
||||
if (!nodeInfo) {
|
||||
return false
|
||||
}
|
||||
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the DOM Node container for the current popupNode.
|
||||
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
_getPopupNodeContainer: function () {
|
||||
let container = null;
|
||||
let node = this.popupNode;
|
||||
|
||||
if (node) {
|
||||
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||
container = isTextNode ? node.parentElement : node;
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Context menu handler.
|
||||
*/
|
||||
@ -821,6 +874,22 @@ CssHtmlTree.prototype = {
|
||||
clipboardHelper.copyString(this._colorToCopy);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||
*/
|
||||
_onCopyImageDataUrl: Task.async(function*() {
|
||||
let message;
|
||||
try {
|
||||
let inspectorFront = this.inspector.inspector;
|
||||
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||
message = yield data.data.string();
|
||||
} catch (e) {
|
||||
message = CssHtmlTree.l10n("styleinspector.copyImageDataUrlError");
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(message);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Copy selected text.
|
||||
*
|
||||
@ -910,6 +979,10 @@ CssHtmlTree.prototype = {
|
||||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||
this.menuitemCopyColor = null;
|
||||
|
||||
// Destroy Copy Data URI menuitem.
|
||||
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||
this.menuitemCopyImageDataUrl = null;
|
||||
|
||||
// Destroy the context menu.
|
||||
this._contextmenu.removeEventListener("popupshowing", this._contextMenuUpdate);
|
||||
this._contextmenu.parentNode.removeChild(this._contextmenu);
|
||||
|
@ -1123,6 +1123,7 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
|
||||
this._onSelectAll = this._onSelectAll.bind(this);
|
||||
this._onCopy = this._onCopy.bind(this);
|
||||
this._onCopyColor = this._onCopyColor.bind(this);
|
||||
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
|
||||
this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
|
||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||
@ -1214,6 +1215,11 @@ CssRuleView.prototype = {
|
||||
accesskey: "ruleView.contextmenu.copyColor.accessKey",
|
||||
command: this._onCopyColor
|
||||
});
|
||||
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||
command: this._onCopyImageDataUrl
|
||||
});
|
||||
this.menuitemSources = createMenuItem(this._contextmenu, {
|
||||
label: "ruleView.contextmenu.showOrigSources",
|
||||
accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
|
||||
@ -1348,6 +1354,7 @@ CssRuleView.prototype = {
|
||||
}
|
||||
|
||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||
this.menuitemCopy.disabled = !copy;
|
||||
|
||||
var showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||
@ -1398,7 +1405,7 @@ CssRuleView.prototype = {
|
||||
pseudoElement: prop.rule.pseudoElement,
|
||||
sheetHref: prop.rule.domRule.href
|
||||
};
|
||||
} else if (classes.contains("theme-link") && prop) {
|
||||
} else if (classes.contains("theme-link") && !classes.contains("ruleview-rule-source") && prop) {
|
||||
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
value = {
|
||||
property: getPropertyNameAndValue(node).name,
|
||||
@ -1430,14 +1437,11 @@ CssRuleView.prototype = {
|
||||
_isColorPopup: function () {
|
||||
this._colorToCopy = "";
|
||||
|
||||
let trigger = this.doc.popupNode;
|
||||
if (!trigger) {
|
||||
let container = this._getPopupNodeContainer();
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
||||
trigger.parentElement : trigger;
|
||||
|
||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||
|
||||
while (!isColorNode(container)) {
|
||||
@ -1451,6 +1455,52 @@ CssRuleView.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the context menu popup was opened with a click on an image link
|
||||
* If true, save the image url to this._imageUrlToCopy
|
||||
*/
|
||||
_isImageUrlPopup: function () {
|
||||
this._imageUrlToCopy = "";
|
||||
|
||||
let container = this._getPopupNodeContainer();
|
||||
let isImageUrlNode = this._isImageUrlNode(container);
|
||||
if (isImageUrlNode) {
|
||||
this._imageUrlToCopy = container.href;
|
||||
}
|
||||
|
||||
return isImageUrlNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a node is an image url
|
||||
* @param {DOMNode} node The node which we want information about
|
||||
* @return {Boolean} true if the node is an image url
|
||||
*/
|
||||
_isImageUrlNode: function (node) {
|
||||
let nodeInfo = this.getNodeInfo(node);
|
||||
if (!nodeInfo) {
|
||||
return false
|
||||
}
|
||||
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the DOM Node container for the current popupNode.
|
||||
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||
* @return {DOMNode}
|
||||
*/
|
||||
_getPopupNodeContainer: function () {
|
||||
let container = null;
|
||||
let node = this.doc.popupNode;
|
||||
|
||||
if (node) {
|
||||
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||
container = isTextNode ? node.parentElement : node;
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Context menu handler.
|
||||
*/
|
||||
@ -1525,6 +1575,22 @@ CssRuleView.prototype = {
|
||||
clipboardHelper.copyString(this._colorToCopy);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||
*/
|
||||
_onCopyImageDataUrl: Task.async(function*() {
|
||||
let message;
|
||||
try {
|
||||
let inspectorFront = this.inspector.inspector;
|
||||
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||
message = yield data.data.string();
|
||||
} catch (e) {
|
||||
message = _strings.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||
}
|
||||
|
||||
clipboardHelper.copyString(message);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Toggle the original sources pref.
|
||||
*/
|
||||
@ -1729,6 +1795,10 @@ CssRuleView.prototype = {
|
||||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||
this.menuitemCopyColor = null;
|
||||
|
||||
// Destroy Copy Data URI menuitem.
|
||||
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||
this.menuitemCopyImageDataUrl = null;
|
||||
|
||||
this.menuitemSources.removeEventListener("command", this._onToggleOrigSources);
|
||||
this.menuitemSources = null;
|
||||
|
||||
|
@ -21,6 +21,7 @@ const {
|
||||
SwatchFilterTooltip
|
||||
} = require("devtools/shared/widgets/Tooltip");
|
||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Promise:promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -59,6 +60,8 @@ function HighlightersOverlay(view) {
|
||||
// Only initialize the overlay if at least one of the highlighter types is
|
||||
// supported
|
||||
this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
exports.HighlightersOverlay = HighlightersOverlay;
|
||||
@ -124,9 +127,13 @@ HighlightersOverlay.prototype = {
|
||||
if (type) {
|
||||
this.highlighterShown = type;
|
||||
let node = this.view.inspector.selection.nodeFront;
|
||||
this._getHighlighter(type).then(highlighter => {
|
||||
highlighter.show(node);
|
||||
});
|
||||
this._getHighlighter(type)
|
||||
.then(highlighter => highlighter.show(node))
|
||||
.then(shown => {
|
||||
if (shown) {
|
||||
this.emit("highlighter-shown");
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -176,6 +183,7 @@ HighlightersOverlay.prototype = {
|
||||
promise.then(null, Cu.reportError);
|
||||
}
|
||||
this.highlighterShown = null;
|
||||
this.emit("highlighter-hidden");
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -151,6 +151,7 @@ skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
|
||||
[browser_ruleview_user-property-reset.js]
|
||||
[browser_styleinspector_context-menu-copy-color_01.js]
|
||||
[browser_styleinspector_context-menu-copy-color_02.js]
|
||||
[browser_styleinspector_context-menu-copy-data-uri.js]
|
||||
[browser_styleinspector_csslogic-content-stylesheets.js]
|
||||
[browser_styleinspector_output-parser.js]
|
||||
[browser_styleinspector_refresh_when_active.js]
|
||||
|
@ -0,0 +1,99 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const PROPERTIES_URL = "chrome://global/locale/devtools/styleinspector.properties";
|
||||
const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
|
||||
|
||||
// invalid URL still needs to be reachable otherwise getImageDataUrl will timeout.
|
||||
// Reusing the properties bundle URL as a workaround
|
||||
const INVALID_IMAGE_URI = PROPERTIES_URL;
|
||||
|
||||
const ERROR_MESSAGE = Services.strings
|
||||
.createBundle(PROPERTIES_URL)
|
||||
.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||
|
||||
add_task(function*() {
|
||||
const PAGE_CONTENT = [
|
||||
"<style type=\"text/css\">",
|
||||
" .valid-background {",
|
||||
" background-image: url(" + TEST_DATA_URI + ");",
|
||||
" }",
|
||||
" .invalid-background {",
|
||||
" background-image: url(" + INVALID_IMAGE_URI + ");",
|
||||
" }",
|
||||
"</style>",
|
||||
"<div class=\"valid-background\">Valid background image</div>",
|
||||
"<div class=\"invalid-background\">Invalid background image</div>"
|
||||
].join("\n");
|
||||
|
||||
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(PAGE_CONTENT));
|
||||
|
||||
yield startTest();
|
||||
});
|
||||
|
||||
function* startTest() {
|
||||
info("Opening rule view");
|
||||
let ruleViewData = yield openRuleView();
|
||||
|
||||
info("Test valid background image URL in rule view");
|
||||
yield testCopyImageDataUrlToClipboard(ruleViewData, ".valid-background", TEST_DATA_URI);
|
||||
info("Test invalid background image URL in rue view");
|
||||
yield testCopyImageDataUrlToClipboard(ruleViewData, ".invalid-background", ERROR_MESSAGE);
|
||||
|
||||
info("Opening computed view");
|
||||
let computedViewData = yield openComputedView();
|
||||
|
||||
info("Test valid background image URL in computed view");
|
||||
yield testCopyImageDataUrlToClipboard(computedViewData, ".valid-background", TEST_DATA_URI);
|
||||
info("Test invalid background image URL in computed view");
|
||||
yield testCopyImageDataUrlToClipboard(computedViewData, ".invalid-background", ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
function* testCopyImageDataUrlToClipboard({view, inspector}, selector, expected) {
|
||||
info("Select node in inspector panel");
|
||||
yield selectNode(selector, inspector);
|
||||
|
||||
info("Retrieve background-image link for selected node in current styleinspector view");
|
||||
let property = getBackgroundImageProperty(view, selector);
|
||||
let imageLink = property.valueSpan.querySelector(".theme-link");
|
||||
ok(imageLink, "Background-image link element found");
|
||||
|
||||
info("Simulate right click on the background-image URL");
|
||||
let popup = once(view._contextmenu, "popupshown");
|
||||
|
||||
// Cannot rely on synthesizeMouseAtCenter here. The image URL can be displayed on several lines.
|
||||
// A click simulated at the exact center may click between the lines and miss the target
|
||||
// Instead, using the top-left corner of first client rect, with an offset of 2 pixels.
|
||||
let rect = imageLink.getClientRects()[0];
|
||||
let x = rect.left + 2;
|
||||
let y = rect.top + 2;
|
||||
|
||||
EventUtils.synthesizeMouseAtPoint(x, y, {button: 2, type: "contextmenu"}, getViewWindow(view));
|
||||
yield popup;
|
||||
|
||||
info("Context menu is displayed");
|
||||
ok(!view.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
|
||||
|
||||
info("Click Copy Data URI and wait for clipboard");
|
||||
yield waitForClipboard(() => view.menuitemCopyImageDataUrl.click(), expected);
|
||||
|
||||
info("Hide context menu");
|
||||
view._contextmenu.hidePopup();
|
||||
}
|
||||
|
||||
function getBackgroundImageProperty(view, selector) {
|
||||
let isRuleView = view instanceof CssRuleView;
|
||||
if (isRuleView) {
|
||||
return getRuleViewProperty(view, selector, "background-image");
|
||||
} else {
|
||||
return getComputedViewProperty(view, "background-image");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that returns the window for a given view.
|
||||
*/
|
||||
function getViewWindow(view) {
|
||||
let viewDocument = view.styleDocument ? view.styleDocument : view.doc;
|
||||
return viewDocument.defaultView;
|
||||
}
|
@ -36,7 +36,9 @@ add_task(function*() {
|
||||
|
||||
info("Faking a mousemove on a transform property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||
let h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
@ -57,7 +59,9 @@ add_task(function*() {
|
||||
|
||||
info("Faking a mousemove on a transform property");
|
||||
({valueSpan} = getComputedViewProperty(cView, "transform"));
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||
h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
|
@ -39,53 +39,64 @@ add_task(function*() {
|
||||
this.nodeFront = nodeFront;
|
||||
this.isShown = true;
|
||||
this.nbOfTimesShown ++;
|
||||
return promise.resolve(true);
|
||||
},
|
||||
hide: function() {
|
||||
this.nodeFront = null;
|
||||
this.isShown = false;
|
||||
return promise.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Inject the mock highlighter in the rule-view
|
||||
rView.highlighters.promises[TYPE] = {
|
||||
then: function(cb) {
|
||||
cb(HighlighterFront);
|
||||
}
|
||||
};
|
||||
let hs = rView.highlighters;
|
||||
hs.promises[TYPE] = promise.resolve(HighlighterFront);
|
||||
|
||||
let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
|
||||
|
||||
info("Checking that the HighlighterFront's show/hide methods are called");
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(HighlighterFront.isShown, "The highlighter is shown");
|
||||
rView.highlighters._onMouseLeave();
|
||||
let onHighlighterHidden = hs.once("highlighter-hidden");
|
||||
hs._onMouseLeave();
|
||||
yield onHighlighterHidden;
|
||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||
|
||||
info("Checking that hovering several times over the same property doesn't" +
|
||||
" show the highlighter several times");
|
||||
let nb = HighlighterFront.nbOfTimesShown;
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
is(HighlighterFront.nbOfTimesShown, nb + 1,
|
||||
"The highlighter was shown once, after several mousemove");
|
||||
|
||||
info("Checking that the right NodeFront reference is passed");
|
||||
yield selectNode("html", inspector);
|
||||
({valueSpan} = getRuleViewProperty(rView, "html", "transform"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nodeFront.tagName, "HTML",
|
||||
"The right NodeFront is passed to the highlighter (1)");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
is(HighlighterFront.nodeFront.tagName, "BODY",
|
||||
"The right NodeFront is passed to the highlighter (2)");
|
||||
|
||||
info("Checking that the highlighter gets hidden when hovering a non-transform property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "body", "color"));
|
||||
rView.highlighters._onMouseMove({target: valueSpan});
|
||||
onHighlighterHidden = hs.once("highlighter-hidden");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterHidden;
|
||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||
});
|
||||
|
@ -55,7 +55,9 @@ add_task(function*() {
|
||||
|
||||
info("Faking a mousemove on the now unoverriden property");
|
||||
({valueSpan} = getRuleViewProperty(rView, "div", "transform"));
|
||||
let onHighlighterShown = hs.once("highlighter-shown");
|
||||
hs._onMouseMove({target: valueSpan});
|
||||
yield onHighlighterShown;
|
||||
ok(hs.promises[TYPE], "The highlighter is being initialized now");
|
||||
let h = yield hs.promises[TYPE];
|
||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||
|
@ -17,8 +17,6 @@ GENERATED_SOURCES += [
|
||||
"%s.c" % cpu,
|
||||
]
|
||||
|
||||
DEFINES['ELFHACK_BUILD'] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
@ -25,6 +25,4 @@ HOST_SOURCES += [
|
||||
|
||||
HostProgram('elfhack')
|
||||
|
||||
DEFINES['ELFHACK_BUILD'] = True
|
||||
|
||||
NO_PGO = True
|
||||
|
@ -431,7 +431,7 @@ if test -z "$RUSTC" -a -n "$MOZ_RUST"; then
|
||||
To compile rust language sources, you must have 'rustc' in your path.
|
||||
See http://www.rust-lang.org/ for more information.])
|
||||
fi
|
||||
if test -n "$MOZ_RUST" -a -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||
if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||
"$_RUSTC_MAJOR_VERSION" -lt 1; then
|
||||
AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
|
||||
To compile rust language sources please install at least
|
||||
|
@ -6628,6 +6628,14 @@ nsContentUtils::IsRequestFullScreenAllowed()
|
||||
IsCallerChrome();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::IsCutCopyAllowed()
|
||||
{
|
||||
return EventStateManager::IsHandlingUserInput() ||
|
||||
IsCallerChrome();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
|
||||
|
@ -1863,6 +1863,13 @@ public:
|
||||
*/
|
||||
static bool IsRequestFullScreenAllowed();
|
||||
|
||||
/**
|
||||
* Returns true if calling execCommand with 'cut' or 'copy' arguments is
|
||||
* allowed in the current context. These are only allowed if the user initiated
|
||||
* them (like with a mouse-click or key press).
|
||||
*/
|
||||
static bool IsCutCopyAllowed();
|
||||
|
||||
/*
|
||||
* Returns true if the performance timing APIs are enabled.
|
||||
*/
|
||||
|
@ -1152,10 +1152,12 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
|
||||
mData, nullptr, nameSpaceManager, proto,
|
||||
&desc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
|
||||
!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
|
||||
NS_strlen(mData->mNameUTF16), desc)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined()) {
|
||||
desc.attributesRef() |= JSPROP_RESOLVING;
|
||||
if (!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
|
||||
NS_strlen(mData->mNameUTF16), desc)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -2121,6 +2121,9 @@ GK_ATOM(el, "el")
|
||||
GK_ATOM(ga, "ga")
|
||||
GK_ATOM(nl, "nl")
|
||||
|
||||
// mathematical language, used for MathML
|
||||
GK_ATOM(x_math, "x-math")
|
||||
|
||||
// Names for editor transactions
|
||||
GK_ATOM(TypingTxnName, "Typing")
|
||||
GK_ATOM(IMETxnName, "IME")
|
||||
|
@ -423,7 +423,7 @@ private:
|
||||
return this;
|
||||
}
|
||||
|
||||
void InsertUserEntry(PerformanceEntry* aEntry);
|
||||
void InsertUserEntry(PerformanceEntry* aEntry) override;
|
||||
|
||||
bool IsPerformanceTimingAttribute(const nsAString& aName) override;
|
||||
|
||||
|
@ -550,7 +550,7 @@ DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name,
|
||||
|
||||
// This is Enumerable: False per spec.
|
||||
return alreadyDefined ||
|
||||
JS_DefineProperty(cx, global, name, constructor, 0);
|
||||
JS_DefineProperty(cx, global, name, constructor, JSPROP_RESOLVING);
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
|
@ -7803,9 +7803,11 @@ class CGResolveHook(CGAbstractClassHook):
|
||||
// If desc.value() is undefined, then the DoResolve call
|
||||
// has already defined it on the object. Don't try to also
|
||||
// define it.
|
||||
if (!desc.value().isUndefined() &&
|
||||
!JS_DefinePropertyById(cx, obj, id, desc)) {
|
||||
return false;
|
||||
if (!desc.value().isUndefined()) {
|
||||
desc.attributesRef() |= JSPROP_RESOLVING;
|
||||
if (!JS_DefinePropertyById(cx, obj, id, desc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*resolvedp = true;
|
||||
return true;
|
||||
|
@ -63,6 +63,29 @@ StringToUsage(const nsString& aUsage, CryptoKey::KeyUsage& aUsageOut)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SECKEYPrivateKey*
|
||||
PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
|
||||
CK_ATTRIBUTE* aTemplate,
|
||||
CK_ULONG aTemplateSize)
|
||||
{
|
||||
// Create a generic object with the contents of the key
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot,
|
||||
aTemplate,
|
||||
aTemplateSize,
|
||||
PR_FALSE));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Have NSS translate the object to a private key.
|
||||
return PK11_FindKeyByKeyID(slot, aObjID, nullptr);
|
||||
}
|
||||
|
||||
CryptoKey::CryptoKey(nsIGlobalObject* aGlobal)
|
||||
: mGlobal(aGlobal)
|
||||
, mAttributes(0)
|
||||
@ -223,6 +246,73 @@ CryptoKey::SetExtractable(bool aExtractable)
|
||||
}
|
||||
}
|
||||
|
||||
// NSS exports private EC keys without the CKA_EC_POINT attribute, i.e. the
|
||||
// public value. To properly export the private key to JWK or PKCS #8 we need
|
||||
// the public key data though and so we use this method to augment a private
|
||||
// key with data from the given public key.
|
||||
nsresult
|
||||
CryptoKey::AddPublicKeyData(SECKEYPublicKey* aPublicKey)
|
||||
{
|
||||
// This should be a private key.
|
||||
MOZ_ASSERT(GetKeyType() == PRIVATE);
|
||||
// There should be a private NSS key with type 'EC'.
|
||||
MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey);
|
||||
// The given public key should have the same key type.
|
||||
MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType);
|
||||
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// Generate a random 160-bit object ID.
|
||||
ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20));
|
||||
SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len);
|
||||
if (rv != SECSuccess) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// Read EC params.
|
||||
ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0));
|
||||
rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_EC_PARAMS,
|
||||
params);
|
||||
if (rv != SECSuccess) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
// Read private value.
|
||||
ScopedSECItem value(::SECITEM_AllocItem(nullptr, nullptr, 0));
|
||||
rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_VALUE, value);
|
||||
if (rv != SECSuccess) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
|
||||
SECItem* point = &aPublicKey->u.ec.publicValue;
|
||||
CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY;
|
||||
CK_BBOOL falseValue = CK_FALSE;
|
||||
CK_KEY_TYPE ecValue = CKK_EC;
|
||||
|
||||
CK_ATTRIBUTE keyTemplate[9] = {
|
||||
{ CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) },
|
||||
{ CKA_KEY_TYPE, &ecValue, sizeof(ecValue) },
|
||||
{ CKA_TOKEN, &falseValue, sizeof(falseValue) },
|
||||
{ CKA_SENSITIVE, &falseValue, sizeof(falseValue) },
|
||||
{ CKA_PRIVATE, &falseValue, sizeof(falseValue) },
|
||||
{ CKA_ID, objID->data, objID->len },
|
||||
{ CKA_EC_PARAMS, params->data, params->len },
|
||||
{ CKA_EC_POINT, point->data, point->len },
|
||||
{ CKA_VALUE, value->data, value->len },
|
||||
};
|
||||
|
||||
mPrivateKey = PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
|
||||
PR_ARRAY_SIZE(keyTemplate));
|
||||
NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CryptoKey::ClearUsages()
|
||||
{
|
||||
@ -367,6 +457,9 @@ CryptoKey::PrivateKeyFromPkcs8(CryptoBuffer& aKeyData,
|
||||
{
|
||||
SECKEYPrivateKey* privKey;
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
if (!arena) {
|
||||
@ -582,36 +675,6 @@ CreateECPointForCoordinates(const CryptoBuffer& aX,
|
||||
return point;
|
||||
}
|
||||
|
||||
SECKEYPrivateKey*
|
||||
PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
|
||||
CK_ATTRIBUTE* aTemplate,
|
||||
CK_ULONG aTemplateSize)
|
||||
{
|
||||
// Create a generic object with the contents of the key
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot.get(),
|
||||
aTemplate,
|
||||
aTemplateSize,
|
||||
PR_FALSE));
|
||||
if (!obj.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Have NSS translate the object to a private key by inspection
|
||||
// and make a copy we can own
|
||||
ScopedSECKEYPrivateKey privKey(PK11_FindKeyByKeyID(slot.get(), aObjID,
|
||||
nullptr));
|
||||
if (!privKey.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SECKEY_CopyPrivateKey(privKey.get());
|
||||
}
|
||||
|
||||
SECKEYPrivateKey*
|
||||
CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
|
||||
@ -1089,11 +1152,15 @@ CryptoKey::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
|
||||
CryptoBuffer priv, pub;
|
||||
|
||||
if (mPrivateKey) {
|
||||
CryptoKey::PrivateKeyToPkcs8(mPrivateKey, priv, locker);
|
||||
if (NS_FAILED(CryptoKey::PrivateKeyToPkcs8(mPrivateKey, priv, locker))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPublicKey) {
|
||||
CryptoKey::PublicKeyToSpki(mPublicKey, pub, locker);
|
||||
if (NS_FAILED(CryptoKey::PublicKeyToSpki(mPublicKey, pub, locker))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_WriteUint32Pair(aWriter, mAttributes, CRYPTOKEY_SC_VERSION) &&
|
||||
|
@ -116,6 +116,7 @@ public:
|
||||
nsresult SetType(const nsString& aType);
|
||||
void SetType(KeyType aType);
|
||||
void SetExtractable(bool aExtractable);
|
||||
nsresult AddPublicKeyData(SECKEYPublicKey* point);
|
||||
void ClearUsages();
|
||||
nsresult AddUsage(const nsString& aUsage);
|
||||
nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask);
|
||||
@ -155,7 +156,7 @@ public:
|
||||
|
||||
static SECKEYPublicKey* PublicKeyFromSpki(CryptoBuffer& aKeyData,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
|
||||
static nsresult PublicKeyToSpki(SECKEYPublicKey* aPrivKey,
|
||||
static nsresult PublicKeyToSpki(SECKEYPublicKey* aPubKey,
|
||||
CryptoBuffer& aRetVal,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
|
||||
|
||||
@ -167,7 +168,7 @@ public:
|
||||
|
||||
static SECKEYPublicKey* PublicKeyFromJwk(const JsonWebKey& aKeyData,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
|
||||
static nsresult PublicKeyToJwk(SECKEYPublicKey* aPrivKey,
|
||||
static nsresult PublicKeyToJwk(SECKEYPublicKey* aPubKey,
|
||||
JsonWebKey& aRetVal,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/);
|
||||
|
||||
|
@ -1913,9 +1913,13 @@ private:
|
||||
}
|
||||
|
||||
switch (mPrivateKey->keyType) {
|
||||
case rsaKey:
|
||||
CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult, locker);
|
||||
case rsaKey: {
|
||||
nsresult rv = CryptoKey::PrivateKeyToPkcs8(mPrivateKey.get(), mResult, locker);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
default:
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
@ -2327,6 +2331,14 @@ private:
|
||||
|
||||
mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey);
|
||||
mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey);
|
||||
|
||||
// PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
|
||||
// private key, we need this later when exporting to PKCS8 and JWK though.
|
||||
if (mMechanism == CKM_EC_KEY_PAIR_GEN) {
|
||||
nsresult rv = mKeyPair.mPrivateKey->AddPublicKeyData(mPublicKey);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -298,6 +298,37 @@ TestArray.addTest(
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"JWK export of a newly generated ECDH private key",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = { name: "ECDH", namedCurve: "P-256" };
|
||||
var reBase64URL = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
function doExportToJWK(x) {
|
||||
return crypto.subtle.exportKey("jwk", x.privateKey)
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, true, ["deriveKey", "deriveBits"])
|
||||
.then(doExportToJWK)
|
||||
.then(
|
||||
complete(that, function(x) {
|
||||
return x.ext &&
|
||||
x.kty == 'EC' &&
|
||||
x.crv == 'P-256' &&
|
||||
reBase64URL.test(x.x) &&
|
||||
reBase64URL.test(x.y) &&
|
||||
reBase64URL.test(x.d) &&
|
||||
x.x.length == 43 && // 32 octets, base64-encoded
|
||||
x.y.length == 43 && // 32 octets, base64-encoded
|
||||
shallowArrayEquals(x.key_ops, ['deriveKey', 'deriveBits']);
|
||||
}),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"Derive an HMAC key from two ECDH keys and test sign/verify",
|
||||
|
@ -22,6 +22,9 @@
|
||||
<script>/*<![CDATA[*/
|
||||
"use strict";
|
||||
|
||||
// Generating 2048-bit keys takes some time.
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP encrypt/decrypt round-trip",
|
||||
|
@ -22,6 +22,9 @@
|
||||
<script>/*<![CDATA[*/
|
||||
"use strict";
|
||||
|
||||
// Generating 2048-bit keys takes some time.
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
|
||||
TestArray.addTest(
|
||||
"Test that we reject generating keys without any usage",
|
||||
function() {
|
||||
|
@ -43,7 +43,8 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
tmp->UnregisterObservers(true);
|
||||
tmp->NotifyIMEOfBlur();
|
||||
tmp->UnregisterObservers();
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWidget)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection)
|
||||
@ -86,6 +87,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
|
||||
IMEContentObserver::IMEContentObserver()
|
||||
: mESM(nullptr)
|
||||
, mPreCharacterDataChangeLength(-1)
|
||||
, mIsObserving(false)
|
||||
, mIsSelectionChangeEventPending(false)
|
||||
, mSelectionChangeCausedOnlyByComposition(false)
|
||||
, mIsPositionChangeEventPending(false)
|
||||
@ -104,17 +106,35 @@ IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
{
|
||||
MOZ_ASSERT(aEditor, "aEditor must not be null");
|
||||
|
||||
State state = GetState();
|
||||
if (NS_WARN_IF(state == eState_Observing)) {
|
||||
return; // Nothing to do.
|
||||
}
|
||||
|
||||
bool firstInitialization = state != eState_StoppedObserving;
|
||||
if (!firstInitialization) {
|
||||
// If this is now trying to initialize with new contents, all observers
|
||||
// should be registered again for simpler implementation.
|
||||
UnregisterObservers();
|
||||
// Clear members which may not be initialized again.
|
||||
mRootContent = nullptr;
|
||||
mEditor = nullptr;
|
||||
mSelection = nullptr;
|
||||
mDocShell = nullptr;
|
||||
}
|
||||
|
||||
mESM = aPresContext->EventStateManager();
|
||||
mESM->OnStartToObserveContent(this);
|
||||
|
||||
mWidget = aWidget;
|
||||
mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
|
||||
|
||||
mEditableNode =
|
||||
IMEStateManager::GetRootEditableNode(aPresContext, aContent);
|
||||
if (!mEditableNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEditor = aEditor;
|
||||
mEditor->AddEditorObserver(this);
|
||||
|
||||
nsIPresShell* presShell = aPresContext->PresShell();
|
||||
|
||||
@ -154,19 +174,23 @@ IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
}
|
||||
NS_ENSURE_TRUE_VOID(mRootContent);
|
||||
|
||||
if (IMEStateManager::IsTestingIME()) {
|
||||
nsIDocument* doc = aPresContext->Document();
|
||||
(new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
|
||||
false, false))->RunDOMEventWhenSafe();
|
||||
}
|
||||
if (firstInitialization) {
|
||||
aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
|
||||
|
||||
aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
|
||||
// While Init() notifies IME of focus, pending layout may be flushed
|
||||
// because the notification may cause querying content. Then, recursive
|
||||
// call of Init() with the latest content may be occur. In such case, we
|
||||
// shouldn't keep first initialization.
|
||||
if (GetState() != eState_Initializing) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
|
||||
// instance via IMEStateManager::UpdateIMEState(). So, this
|
||||
// instance might already have been destroyed, check it.
|
||||
if (!mRootContent) {
|
||||
return;
|
||||
// NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
|
||||
// instance via IMEStateManager::UpdateIMEState(). So, this
|
||||
// instance might already have been destroyed, check it.
|
||||
if (!mRootContent) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mDocShell = aPresContext->GetDocShell();
|
||||
@ -177,8 +201,13 @@ IMEContentObserver::Init(nsIWidget* aWidget,
|
||||
void
|
||||
IMEContentObserver::ObserveEditableNode()
|
||||
{
|
||||
MOZ_ASSERT(mSelection);
|
||||
MOZ_ASSERT(mRootContent);
|
||||
MOZ_RELEASE_ASSERT(mEditor);
|
||||
MOZ_RELEASE_ASSERT(mSelection);
|
||||
MOZ_RELEASE_ASSERT(mRootContent);
|
||||
MOZ_RELEASE_ASSERT(GetState() != eState_Observing);
|
||||
|
||||
mIsObserving = true;
|
||||
mEditor->AddEditorObserver(this);
|
||||
|
||||
mUpdatePreference = mWidget->GetIMEUpdatePreference();
|
||||
if (mUpdatePreference.WantSelectionChange()) {
|
||||
@ -203,32 +232,30 @@ IMEContentObserver::ObserveEditableNode()
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::UnregisterObservers(bool aPostEvent)
|
||||
IMEContentObserver::NotifyIMEOfBlur()
|
||||
{
|
||||
if (mEditor) {
|
||||
mEditor->RemoveEditorObserver(this);
|
||||
// If this failed to initialize, mRootContent may be null, then, we
|
||||
// should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
|
||||
if (!mRootContent || !mWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If CreateTextStateManager failed, mRootContent will be null, then, we
|
||||
// should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
|
||||
if (mRootContent && mWidget) {
|
||||
if (IMEStateManager::IsTestingIME() && mEditableNode) {
|
||||
nsIDocument* doc = mEditableNode->OwnerDoc();
|
||||
if (doc) {
|
||||
nsRefPtr<AsyncEventDispatcher> dispatcher =
|
||||
new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
|
||||
false, false);
|
||||
if (aPostEvent) {
|
||||
dispatcher->PostDOMEvent();
|
||||
} else {
|
||||
dispatcher->RunDOMEventWhenSafe();
|
||||
}
|
||||
}
|
||||
}
|
||||
// A test event handler might destroy the widget.
|
||||
if (mWidget) {
|
||||
mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
|
||||
}
|
||||
// A test event handler might destroy the widget.
|
||||
if (mWidget) {
|
||||
mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IMEContentObserver::UnregisterObservers()
|
||||
{
|
||||
if (!mIsObserving) {
|
||||
return;
|
||||
}
|
||||
mIsObserving = false;
|
||||
|
||||
if (mEditor) {
|
||||
mEditor->RemoveEditorObserver(this);
|
||||
}
|
||||
|
||||
if (mUpdatePreference.WantSelectionChange() && mSelection) {
|
||||
@ -259,7 +286,8 @@ IMEContentObserver::Destroy()
|
||||
{
|
||||
// WARNING: When you change this method, you have to check Unlink() too.
|
||||
|
||||
UnregisterObservers(false);
|
||||
NotifyIMEOfBlur();
|
||||
UnregisterObservers();
|
||||
|
||||
mEditor = nullptr;
|
||||
// Even if there are some pending notification, it'll never notify the widget.
|
||||
@ -282,16 +310,47 @@ IMEContentObserver::DisconnectFromEventStateManager()
|
||||
mESM = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
IMEContentObserver::MaybeReinitialize(nsIWidget* aWidget,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor)
|
||||
{
|
||||
if (!IsObservingContent(aPresContext, aContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetState() == eState_StoppedObserving) {
|
||||
Init(aWidget, aPresContext, aContent, aEditor);
|
||||
}
|
||||
return IsManaging(aPresContext, aContent);
|
||||
}
|
||||
|
||||
bool
|
||||
IMEContentObserver::IsManaging(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
return GetState() == eState_Observing &&
|
||||
IsObservingContent(aPresContext, aContent);
|
||||
}
|
||||
|
||||
IMEContentObserver::State
|
||||
IMEContentObserver::GetState() const
|
||||
{
|
||||
if (!mSelection || !mRootContent || !mEditableNode) {
|
||||
return false; // failed to initialize.
|
||||
return eState_NotObserving; // failed to initialize or finalized.
|
||||
}
|
||||
if (!mRootContent->IsInComposedDoc()) {
|
||||
return false; // the focused editor has already been reframed.
|
||||
// the focused editor has already been reframed.
|
||||
return eState_StoppedObserving;
|
||||
}
|
||||
return mIsObserving ? eState_Observing : eState_Initializing;
|
||||
}
|
||||
|
||||
bool
|
||||
IMEContentObserver::IsObservingContent(nsPresContext* aPresContext,
|
||||
nsIContent* aContent) const
|
||||
{
|
||||
return mEditableNode == IMEStateManager::GetRootEditableNode(aPresContext,
|
||||
aContent);
|
||||
}
|
||||
|
@ -72,6 +72,17 @@ public:
|
||||
* storing the instance.
|
||||
*/
|
||||
void DisconnectFromEventStateManager();
|
||||
/**
|
||||
* MaybeReinitialize() tries to restart to observe the editor's root node.
|
||||
* This is useful when the editor is reframed and all children are replaced
|
||||
* with new node instances.
|
||||
* @return Returns true if the instance is managing the content.
|
||||
* Otherwise, false.
|
||||
*/
|
||||
bool MaybeReinitialize(nsIWidget* aWidget,
|
||||
nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
nsIEditor* aEditor);
|
||||
bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
|
||||
bool IsEditorHandlingEventForComposition() const;
|
||||
bool KeepAliveDuringDeactive() const
|
||||
@ -133,6 +144,15 @@ public:
|
||||
private:
|
||||
~IMEContentObserver() {}
|
||||
|
||||
enum State {
|
||||
eState_NotObserving,
|
||||
eState_Initializing,
|
||||
eState_StoppedObserving,
|
||||
eState_Observing
|
||||
};
|
||||
State GetState() const;
|
||||
bool IsObservingContent(nsPresContext* aPresContext,
|
||||
nsIContent* aContent) const;
|
||||
void MaybeNotifyIMEOfTextChange(const TextChangeData& aTextChangeData);
|
||||
void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition);
|
||||
void MaybeNotifyIMEOfPositionChange();
|
||||
@ -140,11 +160,13 @@ private:
|
||||
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
|
||||
void ObserveEditableNode();
|
||||
/**
|
||||
* UnregisterObservers() unresiters all listeners and observers.
|
||||
* @param aPostEvent When true, DOM event will be posted to the thread.
|
||||
* Otherwise, dispatched when safe.
|
||||
* NotifyIMEOfBlur() notifies IME of blur.
|
||||
*/
|
||||
void UnregisterObservers(bool aPostEvent);
|
||||
void NotifyIMEOfBlur();
|
||||
/**
|
||||
* UnregisterObservers() unregisters all listeners and observers.
|
||||
*/
|
||||
void UnregisterObservers();
|
||||
void StoreTextChangeData(const TextChangeData& aTextChangeData);
|
||||
void FlushMergeableNotifications();
|
||||
|
||||
@ -221,6 +243,7 @@ private:
|
||||
uint32_t mPreAttrChangeLength;
|
||||
int64_t mPreCharacterDataChangeLength;
|
||||
|
||||
bool mIsObserving;
|
||||
bool mIsSelectionChangeEventPending;
|
||||
bool mSelectionChangeCausedOnlyByComposition;
|
||||
bool mIsPositionChangeEventPending;
|
||||
|
@ -180,7 +180,6 @@ GetNotifyIMEMessageName(IMEMessage aMessage)
|
||||
nsIContent* IMEStateManager::sContent = nullptr;
|
||||
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||
bool IMEStateManager::sIsTestingIME = false;
|
||||
bool IMEStateManager::sIsGettingNewIMEState = false;
|
||||
|
||||
// sActiveIMEContentObserver points to the currently active IMEContentObserver.
|
||||
@ -649,9 +648,23 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
return;
|
||||
}
|
||||
|
||||
// If the IMEContentObserver instance isn't managing the editor's current
|
||||
// editable root content, the editor frame might be reframed. We should
|
||||
// recreate the instance at that time.
|
||||
// Even if there is active IMEContentObserver, it may not be observing the
|
||||
// editor with current editable root content due to reframed. In such case,
|
||||
// We should try to reinitialize the IMEContentObserver.
|
||||
if (sActiveIMEContentObserver && IsIMEObserverNeeded(aNewIMEState)) {
|
||||
PR_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::UpdateIMEState(), try to reinitialize the "
|
||||
"active IMEContentObserver"));
|
||||
if (!sActiveIMEContentObserver->MaybeReinitialize(widget, sPresContext,
|
||||
aContent, aEditor)) {
|
||||
PR_LOG(sISMLog, PR_LOG_ERROR,
|
||||
("ISM: IMEStateManager::UpdateIMEState(), failed to reinitialize the "
|
||||
"active IMEContentObserver"));
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no active IMEContentObserver or it isn't observing the
|
||||
// editor correctly, we should recreate it.
|
||||
bool createTextStateManager =
|
||||
(!sActiveIMEContentObserver ||
|
||||
!sActiveIMEContentObserver->IsManaging(sPresContext, aContent));
|
||||
@ -1128,18 +1141,9 @@ IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
|
||||
|
||||
// static
|
||||
bool
|
||||
IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
|
||||
IMEStateManager::IsIMEObserverNeeded(const IMEState& aState)
|
||||
{
|
||||
switch (aWidget->GetInputContext().mIMEState.mEnabled) {
|
||||
case IMEState::ENABLED:
|
||||
case IMEState::PASSWORD:
|
||||
return true;
|
||||
case IMEState::PLUGIN:
|
||||
case IMEState::DISABLED:
|
||||
return false;
|
||||
default:
|
||||
MOZ_CRASH("Unknown IME enable state");
|
||||
}
|
||||
return aState.IsEditable();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -1193,20 +1197,14 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
||||
return; // Sometimes, there are no widgets.
|
||||
}
|
||||
|
||||
// If it's not text ediable, we don't need to create IMEContentObserver.
|
||||
if (!IsEditableIMEState(widget)) {
|
||||
// If it's not text editable, we don't need to create IMEContentObserver.
|
||||
if (!IsIMEObserverNeeded(widget->GetInputContext().mIMEState)) {
|
||||
MOZ_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver() doesn't create "
|
||||
"IMEContentObserver because of non-editable IME state"));
|
||||
return;
|
||||
}
|
||||
|
||||
static bool sInitializeIsTestingIME = true;
|
||||
if (sInitializeIsTestingIME) {
|
||||
Preferences::AddBoolVarCache(&sIsTestingIME, "test.IME", false);
|
||||
sInitializeIsTestingIME = false;
|
||||
}
|
||||
|
||||
MOZ_LOG(sISMLog, PR_LOG_DEBUG,
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver() is creating an "
|
||||
"IMEContentObserver instance..."));
|
||||
|
@ -138,7 +138,6 @@ public:
|
||||
|
||||
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
static bool IsTestingIME() { return sIsTestingIME; }
|
||||
|
||||
protected:
|
||||
static nsresult OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
@ -157,12 +156,11 @@ protected:
|
||||
|
||||
static bool IsEditable(nsINode* node);
|
||||
|
||||
static bool IsEditableIMEState(nsIWidget* aWidget);
|
||||
static bool IsIMEObserverNeeded(const IMEState& aState);
|
||||
|
||||
static nsIContent* sContent;
|
||||
static nsPresContext* sPresContext;
|
||||
static bool sInstalledMenuKeyboardListener;
|
||||
static bool sIsTestingIME;
|
||||
static bool sIsGettingNewIMEState;
|
||||
|
||||
class MOZ_STACK_CLASS GettingNewIMEStateBlocker final
|
||||
|
@ -224,23 +224,34 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsIPrincipal* principal;
|
||||
if (window) {
|
||||
doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
loadGroup = doc->GetDocumentLoadGroup();
|
||||
} else {
|
||||
principal = aGlobal->PrincipalOrNull();
|
||||
if (NS_WARN_IF(!principal)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
|
||||
|
||||
nsRefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
|
||||
nsRefPtr<FetchDriver> fetch =
|
||||
new FetchDriver(r, doc->NodePrincipal(), loadGroup);
|
||||
nsRefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
|
||||
fetch->SetDocument(doc);
|
||||
aRv = fetch->Fetch(resolver);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -411,6 +422,23 @@ UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest)
|
||||
doc->GetReferrer(referrer);
|
||||
aRequest->SetReferrer(referrer);
|
||||
}
|
||||
} else if (NS_IsMainThread()) {
|
||||
// Pull the principal from the global for non-worker scripts.
|
||||
nsIPrincipal *principal = aGlobal->PrincipalOrNull();
|
||||
bool isNull;
|
||||
// Only set the referrer if the principal is present,
|
||||
// and the principal is not null or the system principal.
|
||||
if (principal &&
|
||||
NS_SUCCEEDED(principal->GetIsNullPrincipal(&isNull)) && !isNull &&
|
||||
!nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))) && uri) {
|
||||
nsAutoCString referrer;
|
||||
if (NS_SUCCEEDED(uri->GetSpec(referrer))) {
|
||||
aRequest->SetReferrer(NS_ConvertUTF8toUTF16(referrer));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
|
@ -3353,6 +3353,19 @@ nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv)
|
||||
return false;
|
||||
}
|
||||
|
||||
// cut & copy are always allowed
|
||||
bool isCutCopy = commandID.LowerCaseEqualsLiteral("cut") ||
|
||||
commandID.LowerCaseEqualsLiteral("copy");
|
||||
if (isCutCopy) {
|
||||
return nsContentUtils::IsCutCopyAllowed();
|
||||
}
|
||||
|
||||
// Report false for restricted commands
|
||||
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
|
||||
if (restricted && !nsContentUtils::IsCallerChrome()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if editing is not on, bail
|
||||
if (!IsEditingOnAfterFlush()) {
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
|
@ -15,6 +15,7 @@ Implement HTML5 sandbox attribute for IFRAMEs
|
||||
/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
|
||||
/** Navigation tests Part 1**/
|
||||
|
||||
SimpleTest.requestLongerTimeout(2); // slow on Android
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
|
@ -16,6 +16,7 @@ Implement HTML5 sandbox attribute for IFRAMEs
|
||||
/** Navigation tests Part 2**/
|
||||
|
||||
SimpleTest.expectAssertions(0);
|
||||
SimpleTest.requestLongerTimeout(2); // slow on Android
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
|
@ -2246,6 +2246,14 @@ TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
|
||||
aEvent.mReply.mRect =
|
||||
aEvent.mReply.mRect.Union(mIMECompositionRects[i]);
|
||||
}
|
||||
if (aEvent.mInput.mOffset < mIMECacheText.Length()) {
|
||||
aEvent.mReply.mString =
|
||||
Substring(mIMECacheText, aEvent.mInput.mOffset,
|
||||
mIMECacheText.Length() >= aEvent.mInput.EndOffset() ?
|
||||
aEvent.mInput.mLength : UINT32_MAX);
|
||||
} else {
|
||||
aEvent.mReply.mString.Truncate();
|
||||
}
|
||||
aEvent.mReply.mOffset = aEvent.mInput.mOffset;
|
||||
aEvent.mReply.mRect = aEvent.mReply.mRect - GetChildProcessOffset();
|
||||
aEvent.mReply.mWritingMode = mWritingMode;
|
||||
|
@ -6,6 +6,9 @@
|
||||
#ifndef mozilla_dom_CanvasCaptureMediaStream_h_
|
||||
#define mozilla_dom_CanvasCaptureMediaStream_h_
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "StreamBuffer.h"
|
||||
|
||||
namespace mozilla {
|
||||
class DOMMediaStream;
|
||||
class MediaStreamListener;
|
||||
|
@ -207,7 +207,7 @@ IdpSandbox.prototype = {
|
||||
wantGlobalProperties: [
|
||||
'indexedDB', 'XMLHttpRequest', 'TextEncoder', 'TextDecoder',
|
||||
'URL', 'URLSearchParams', 'atob', 'btoa', 'Blob', 'crypto',
|
||||
'rtcIdentityProvider'
|
||||
'rtcIdentityProvider', 'fetch'
|
||||
]
|
||||
});
|
||||
let registrar = this.sandbox.rtcIdentityProvider;
|
||||
|
@ -1078,6 +1078,17 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
||||
StopPrerollingVideo();
|
||||
}
|
||||
|
||||
// Schedule the state machine to send stream data as soon as possible or
|
||||
// the VideoQueue() is empty before the Push().
|
||||
// VideoQueue() is empty implies the state machine thread doesn't have
|
||||
// precise time information about video frames. Once the first video
|
||||
// frame pushed in the queue, schedule the state machine as soon as
|
||||
// possible to render the video frame or delay the state machine thread
|
||||
// accurately.
|
||||
if (mAudioCaptured || VideoQueue().GetSize() == 1) {
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
// For non async readers, if the requested video sample was slow to
|
||||
// arrive, increase the amount of audio we buffer to ensure that we
|
||||
// don't run out of audio. This is unnecessary for async readers,
|
||||
@ -1097,11 +1108,6 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
||||
DECODER_LOG("Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld",
|
||||
mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs);
|
||||
}
|
||||
|
||||
// Schedule the state machine to send stream data as soon as possible.
|
||||
if (mAudioCaptured) {
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DECODER_STATE_SEEKING: {
|
||||
@ -2959,9 +2965,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
// Current frame has already been presented, wait until it's time to
|
||||
// present the next frame.
|
||||
if (frame && !currentFrame) {
|
||||
int64_t now = IsPlaying() ? clock_time : mStartTime + mPlayDuration;
|
||||
|
||||
remainingTime = frame->mTime - now;
|
||||
remainingTime = frame->mTime - clock_time;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3043,6 +3047,22 @@ void MediaDecoderStateMachine::AdvanceFrame()
|
||||
currentFrame = nullptr;
|
||||
}
|
||||
|
||||
// The remainingTime is negative (include zero):
|
||||
// 1. When the clock_time is larger than the latest video frame's endtime.
|
||||
// All the video frames should be rendered or dropped, nothing left in
|
||||
// VideoQueue. And since the VideoQueue is empty, we don't need to wake up
|
||||
// statemachine thread immediately, so set the remainingTime to default value.
|
||||
// 2. Current frame's endtime is smaller than clock_time but there still exist
|
||||
// newer frames in queue. Re-calculate the remainingTime.
|
||||
if (remainingTime <= 0) {
|
||||
VideoData* nextFrame = VideoQueue().PeekFront();
|
||||
if (nextFrame) {
|
||||
remainingTime = nextFrame->mTime - clock_time;
|
||||
} else {
|
||||
remainingTime = AUDIO_DURATION_USECS;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t delay = remainingTime / mPlaybackRate;
|
||||
if (delay > 0) {
|
||||
ScheduleStateMachineIn(delay);
|
||||
|
@ -67,33 +67,6 @@ IsValidTimestampUs(int64_t aTimestamp)
|
||||
return aTimestamp >= INT64_C(0);
|
||||
}
|
||||
|
||||
MediaCodecReader::VideoResourceListener::VideoResourceListener(
|
||||
MediaCodecReader* aReader)
|
||||
: mReader(aReader)
|
||||
{
|
||||
}
|
||||
|
||||
MediaCodecReader::VideoResourceListener::~VideoResourceListener()
|
||||
{
|
||||
mReader = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::VideoResourceListener::codecReserved()
|
||||
{
|
||||
if (mReader) {
|
||||
mReader->VideoCodecReserved();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::VideoResourceListener::codecCanceled()
|
||||
{
|
||||
if (mReader) {
|
||||
mReader->VideoCodecCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
MediaCodecReader::TrackInputCopier::~TrackInputCopier()
|
||||
{
|
||||
}
|
||||
@ -276,7 +249,6 @@ MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
|
||||
, mNextParserPosition(INT64_C(0))
|
||||
, mParsedDataLength(INT64_C(0))
|
||||
{
|
||||
mVideoListener = new VideoResourceListener(this);
|
||||
}
|
||||
|
||||
MediaCodecReader::~MediaCodecReader()
|
||||
@ -676,14 +648,6 @@ MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Configure video codec after the codecReserved.
|
||||
if (mVideoTrack.mSource != nullptr) {
|
||||
if (!ConfigureMediaCodec(mVideoTrack)) {
|
||||
DestroyMediaCodec(mVideoTrack);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: start streaming
|
||||
|
||||
if (!UpdateDuration()) {
|
||||
@ -1295,8 +1259,8 @@ MediaCodecReader::CreateTaskQueues()
|
||||
bool
|
||||
MediaCodecReader::CreateMediaCodecs()
|
||||
{
|
||||
if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) &&
|
||||
CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) {
|
||||
if (CreateMediaCodec(mLooper, mAudioTrack, nullptr) &&
|
||||
CreateMediaCodec(mLooper, mVideoTrack, nullptr)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1306,7 +1270,6 @@ MediaCodecReader::CreateMediaCodecs()
|
||||
bool
|
||||
MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
Track& aTrack,
|
||||
bool aAsync,
|
||||
wp<MediaCodecProxy::CodecResourceListener> aListener)
|
||||
{
|
||||
if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) {
|
||||
@ -1321,6 +1284,10 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
NS_WARNING("Couldn't create MediaCodecProxy");
|
||||
return false;
|
||||
}
|
||||
if (!aTrack.mCodec->AskMediaCodecAndWait()) {
|
||||
NS_WARNING("AskMediaCodecAndWait fail");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
|
||||
aTrack.mInputCopier = new VorbisInputCopier;
|
||||
@ -1343,14 +1310,10 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!aAsync) {
|
||||
// Pending configure() and start() to codecReserved() if the creation
|
||||
// should be asynchronous.
|
||||
if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)){
|
||||
NS_WARNING("Couldn't create and configure MediaCodec synchronously");
|
||||
DestroyMediaCodec(aTrack);
|
||||
return false;
|
||||
}
|
||||
if (!aTrack.mCodec->allocated() || !ConfigureMediaCodec(aTrack)) {
|
||||
NS_WARNING("Couldn't create and configure MediaCodec synchronously");
|
||||
DestroyMediaCodec(aTrack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1869,6 +1832,7 @@ MediaCodecReader::EnsureCodecFormatParsed(Track& aTrack)
|
||||
size_t size = 0;
|
||||
int64_t timeUs = INT64_C(0);
|
||||
uint32_t flags = 0;
|
||||
FillCodecInputData(aTrack);
|
||||
while ((status = aTrack.mCodec->dequeueOutputBuffer(&index, &offset, &size,
|
||||
&timeUs, &flags)) != INFO_FORMAT_CHANGED) {
|
||||
if (status == OK) {
|
||||
@ -1879,17 +1843,11 @@ MediaCodecReader::EnsureCodecFormatParsed(Track& aTrack)
|
||||
NS_WARNING("Couldn't get output buffers from MediaCodec");
|
||||
return false;
|
||||
}
|
||||
} else if (status != -EAGAIN && status != INVALID_OPERATION){
|
||||
} else if (status != -EAGAIN && status != INVALID_OPERATION) {
|
||||
// FIXME: let INVALID_OPERATION pass?
|
||||
return false; // something wrong!!!
|
||||
}
|
||||
|
||||
status = FillCodecInputData(aTrack);
|
||||
if (status == INFO_FORMAT_CHANGED) {
|
||||
break;
|
||||
} else if (status != OK) {
|
||||
return false;
|
||||
}
|
||||
FillCodecInputData(aTrack);
|
||||
}
|
||||
return aTrack.mCodec->getOutputFormat(&format) == OK;
|
||||
}
|
||||
@ -1917,22 +1875,4 @@ MediaCodecReader::ClearColorConverterBuffer()
|
||||
mColorConverterBufferSize = 0;
|
||||
}
|
||||
|
||||
// Called on Binder thread.
|
||||
void
|
||||
MediaCodecReader::VideoCodecReserved()
|
||||
{
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
}
|
||||
|
||||
// Called on Binder thread.
|
||||
void
|
||||
MediaCodecReader::VideoCodecCanceled()
|
||||
{
|
||||
if (mVideoTrack.mTaskQueue) {
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources);
|
||||
mVideoTrack.mTaskQueue->Dispatch(task.forget());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -177,11 +177,6 @@ protected:
|
||||
// Called on MediaCodecReader::mLooper thread.
|
||||
void onMessageReceived(const android::sp<android::AMessage>& aMessage);
|
||||
|
||||
// Receive a notify from ResourceListener.
|
||||
// Called on Binder thread.
|
||||
virtual void VideoCodecReserved();
|
||||
virtual void VideoCodecCanceled();
|
||||
|
||||
virtual bool CreateExtractor();
|
||||
|
||||
// Check the underlying HW resource is available and store the result in
|
||||
@ -194,28 +189,6 @@ protected:
|
||||
bool mIsWaitingResources;
|
||||
|
||||
private:
|
||||
|
||||
// An intermediary class that can be managed by android::sp<T>.
|
||||
// Redirect codecReserved() and codecCanceled() to MediaCodecReader.
|
||||
class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
|
||||
{
|
||||
public:
|
||||
VideoResourceListener(MediaCodecReader* aReader);
|
||||
~VideoResourceListener();
|
||||
|
||||
virtual void codecReserved();
|
||||
virtual void codecCanceled();
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
VideoResourceListener() = delete;
|
||||
VideoResourceListener(const VideoResourceListener& rhs) = delete;
|
||||
const VideoResourceListener& operator=(const VideoResourceListener& rhs) = delete;
|
||||
|
||||
MediaCodecReader* mReader;
|
||||
};
|
||||
friend class VideoResourceListener;
|
||||
|
||||
class VorbisInputCopier : public TrackInputCopier
|
||||
{
|
||||
virtual bool Copy(android::MediaBuffer* aSourceBuffer,
|
||||
@ -354,7 +327,6 @@ private:
|
||||
bool CreateMediaCodecs();
|
||||
static bool CreateMediaCodec(android::sp<android::ALooper>& aLooper,
|
||||
Track& aTrack,
|
||||
bool aAsync,
|
||||
android::wp<android::MediaCodecProxy::CodecResourceListener> aListener);
|
||||
static bool ConfigureMediaCodec(Track& aTrack);
|
||||
void DestroyMediaCodecs();
|
||||
@ -415,8 +387,6 @@ private:
|
||||
|
||||
void ReleaseAllTextureClients();
|
||||
|
||||
android::sp<VideoResourceListener> mVideoListener;
|
||||
|
||||
android::sp<android::ALooper> mLooper;
|
||||
android::sp<android::MetaData> mMetaData;
|
||||
|
||||
|
@ -21,12 +21,8 @@
|
||||
|
||||
IDPJS.prototype = {
|
||||
getLogin: function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id);
|
||||
return new Promise(resolve => {
|
||||
xhr.onload = e => resolve(xhr.status === 200);
|
||||
xhr.send();
|
||||
});
|
||||
return fetch('https://example.com/.well-known/idp-proxy/idp.sjs?' + this.id)
|
||||
.then(response => response.status === 200);
|
||||
},
|
||||
checkLogin: function(result) {
|
||||
return this.getLogin()
|
||||
|
@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=346659
|
||||
|
||||
/** Test for Bug 346659 **/
|
||||
var numTests = 10;
|
||||
SimpleTest.requestLongerTimeout(2); // test takes a long time on android and b2g emulators
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var wins = [];
|
||||
|
@ -39,6 +39,7 @@ function testSameOriginBlobURL() {
|
||||
var blob = new Blob(["english ", "sentence"], { type: "text/plain" });
|
||||
var url = URL.createObjectURL(blob);
|
||||
return fetch(url).then(function(res) {
|
||||
URL.revokeObjectURL(url);
|
||||
ok(true, "Blob URL fetch should resolve");
|
||||
if (res.type == "error") {
|
||||
ok(false, "Blob URL fetch should not fail.");
|
||||
|
@ -307,6 +307,15 @@ const knownFailures = {
|
||||
"QE-Proposed-UNBOOKMARK_TEXT-1-dM": true,
|
||||
"QE-Proposed-UNBOOKMARK_TEXT-1-body": true,
|
||||
"QE-Proposed-UNBOOKMARK_TEXT-1-div": true,
|
||||
"QE-Proposed-COPY_TEXT-1-dM": true,
|
||||
"QE-Proposed-COPY_TEXT-1-body": true,
|
||||
"QE-Proposed-COPY_TEXT-1-div": true,
|
||||
"QE-Proposed-CUT_TEXT-1-dM": true,
|
||||
"QE-Proposed-CUT_TEXT-1-body": true,
|
||||
"QE-Proposed-CUT_TEXT-1-div": true,
|
||||
"QE-Proposed-PASTE_TEXT-1-dM": true,
|
||||
"QE-Proposed-PASTE_TEXT-1-body": true,
|
||||
"QE-Proposed-PASTE_TEXT-1-div": true,
|
||||
"QS-Proposed-SUB_SPAN.sub-1-SI-dM": true,
|
||||
"QS-Proposed-SUB_SPAN.sub-1-SI-body": true,
|
||||
"QS-Proposed-SUB_SPAN.sub-1-SI-div": true,
|
||||
|
@ -162,4 +162,5 @@ skip-if = e10s
|
||||
[test_spellcheck_pref.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_bug1068979.html]
|
||||
[test_bug1109465.html]
|
||||
[test_bug1109465.html]
|
||||
[test_bug1162952.html]
|
||||
|
43
editor/libeditor/tests/test_bug1162952.html
Normal file
43
editor/libeditor/tests/test_bug1162952.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1162952
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 1162952</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1162952">Mozilla Bug 1162952</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 1162952 **/
|
||||
var userCallbackRun = false;
|
||||
|
||||
document.addEventListener('keydown', function() {
|
||||
// During a user callback, the commands should be enabled
|
||||
userCallbackRun = true;
|
||||
is(true, document.queryCommandEnabled('cut'));
|
||||
is(true, document.queryCommandEnabled('copy'));
|
||||
});
|
||||
|
||||
// Otherwise, they should be disabled
|
||||
is(false, document.queryCommandEnabled('cut'));
|
||||
is(false, document.queryCommandEnabled('copy'));
|
||||
|
||||
// Fire a user callback
|
||||
synthesizeKey('A', {});
|
||||
|
||||
ok(userCallbackRun, "User callback should've been run");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -45,7 +45,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=408231
|
||||
["justifyleft", "true"],
|
||||
["justifyright", "true"],
|
||||
["outdent", "true"],
|
||||
//["paste", "true"],
|
||||
["paste", "false"],
|
||||
["redo", "false"],
|
||||
["removeformat", "true"],
|
||||
["selectall", "true"],
|
||||
|
@ -35,6 +35,7 @@ var gBlock1, gBlock2;
|
||||
var alwaysEnabledCommands = [
|
||||
"contentReadOnly",
|
||||
"copy",
|
||||
"cut",
|
||||
"enableInlineTableEditing",
|
||||
"enableObjectResizing",
|
||||
"insertBrOnReturn",
|
||||
@ -89,9 +90,12 @@ function runTests() {
|
||||
IsCommandEnabled(commands[i]);
|
||||
|
||||
// These are privileged, and available only to chrome.
|
||||
commands = ["cut", "paste", "copy"];
|
||||
commands = ["paste"];
|
||||
for (i = 0; i < commands.length; i++) {
|
||||
IsCommandEnabled(commands[i]);
|
||||
is(document.queryCommandEnabled(commands[i]), false,
|
||||
"Command should not be enabled for non-privileged code");
|
||||
is(SpecialPowers.wrap(document).queryCommandEnabled(commands[i]), true,
|
||||
"Command should be enabled for privileged code");
|
||||
try {
|
||||
document.execCommand(commands[i], false, false);
|
||||
ok(false, "Thould have thrown: " + commands[i]);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user