Merge m-c to inbound, a=merge

MozReview-Commit-ID: 3HW7YWDqTBQ
This commit is contained in:
Wes Kocher 2016-12-23 14:40:42 -08:00
commit e28b562783
78 changed files with 14913 additions and 13646 deletions

View File

@ -0,0 +1,252 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
this.EXPORTED_SYMBOLS = [
"Panel",
];
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Timer.jsm");
this.Panel = function(panelElt, iframeURL) {
this.p = panelElt;
this.iframeURL = iframeURL;
this._initPanel();
this.urlbar.addEventListener("keydown", this);
this.urlbar.addEventListener("input", this);
this._emitQueue = [];
};
this.Panel.prototype = {
get document() {
return this.p.ownerDocument;
},
get window() {
return this.document.defaultView;
},
get urlbar() {
return this.window.gURLBar;
},
iframe: null,
get iframeDocument() {
return this.iframe.contentDocument;
},
get iframeWindow() {
return this.iframe.contentWindow;
},
destroy() {
this.p.destroyAddonIframe(this);
this.urlbar.removeEventListener("keydown", this);
this.urlbar.removeEventListener("input", this);
},
_initPanel() {
this.iframe = this.p.initAddonIframe(this, {
_invalidate: this._invalidate.bind(this),
});
if (!this.iframe) {
// This will be the case when somebody else already owns the iframe.
// First consumer wins right now.
return;
}
let onLoad = event => {
this.iframe.removeEventListener("load", onLoad, true);
this._initIframeContent(event.target.defaultView);
};
this.iframe.addEventListener("load", onLoad, true);
this.iframe.setAttribute("src", this.iframeURL);
},
_initIframeContent(win) {
// Clone the urlbar API functions into the iframe window.
win = XPCNativeWrapper.unwrap(win);
let apiInstance = Cu.cloneInto(iframeAPIPrototype, win, {
cloneFunctions: true,
});
apiInstance._panel = this;
Object.defineProperty(win, "urlbar", {
get() {
return apiInstance;
},
});
},
// This is called by the popup directly. It overrides the popup's own
// _invalidate method.
_invalidate() {
this._emit("reset");
this._currentIndex = 0;
if (this._appendResultTimeout) {
this.window.clearTimeout(this._appendResultTimeout);
}
this._appendCurrentResult();
},
// This emulates the popup's own _appendCurrentResult method, except instead
// of appending results to the popup, it emits "result" events to the iframe.
_appendCurrentResult() {
let controller = this.p.mInput.controller;
for (let i = 0; i < this.p.maxResults; i++) {
let idx = this._currentIndex;
if (idx >= this.p._matchCount) {
break;
}
let url = controller.getValueAt(idx);
let action = this.urlbar._parseActionUrl(url);
this._emit("result", {
url: url,
action: action,
image: controller.getImageAt(idx),
title: controller.getCommentAt(idx),
type: controller.getStyleAt(idx),
text: controller.searchString.replace(/^\s+/, "").replace(/\s+$/, ""),
});
this._currentIndex++;
}
if (this._currentIndex < this.p.matchCount) {
this._appendResultTimeout = this.window.setTimeout(() => {
this._appendCurrentResult();
});
}
},
get height() {
return this.iframe.getBoundingClientRect().height;
},
set height(val) {
this.p.removeAttribute("height");
this.iframe.style.height = val + "px";
},
handleEvent(event) {
let methName = "_on" + event.type[0].toUpperCase() + event.type.substr(1);
this[methName](event);
},
_onKeydown(event) {
let emittedEvent = this._emitUrlbarEvent(event);
if (emittedEvent && emittedEvent.defaultPrevented) {
event.preventDefault();
event.stopPropagation();
}
},
_onInput(event) {
this._emitUrlbarEvent(event);
},
_emitUrlbarEvent(event) {
let properties = [
"altKey",
"code",
"ctrlKey",
"key",
"metaKey",
"shiftKey",
];
let detail = properties.reduce((memo, prop) => {
memo[prop] = event[prop];
return memo;
}, {});
return this._emit(event.type, detail);
},
_emit(eventName, detailObj = null) {
this._emitQueue.push({
name: eventName,
detail: detailObj,
});
return this._processEmitQueue();
},
_processEmitQueue() {
if (!this._emitQueue.length) {
return null;
}
// iframe.contentWindow can be undefined right after the iframe is created,
// even after a number of seconds have elapsed. Don't know why. But that's
// entirely the reason for having a queue instead of simply dispatching
// events as they're created, unfortunately.
if (!this.iframeWindow) {
if (!this._processEmitQueueTimer) {
this._processEmitQueueTimer = setInterval(() => {
this._processEmitQueue();
}, 100);
}
return null;
}
if (this._processEmitQueueTimer) {
clearInterval(this._processEmitQueueTimer);
delete this._processEmitQueueTimer;
}
let { name, detail } = this._emitQueue.shift();
let win = XPCNativeWrapper.unwrap(this.iframeWindow);
let event = new this.iframeWindow.CustomEvent(name, {
detail: Cu.cloneInto(detail, win),
cancelable: true,
});
this.iframeWindow.dispatchEvent(event);
// More events may be queued up, so recurse. Do it after a turn of the
// event loop to avoid growing the stack as big as the queue, and to let the
// caller handle the returned event first.
setTimeout(() => {
this._processEmitQueue();
}, 100);
return event;
},
};
// This is the consumer API that's cloned into the iframe window. Be careful of
// defining static values on this, or even getters and setters (that aren't real
// functions). The cloning process means that such values are copied by value,
// at the time of cloning, which is probably not what you want. That's why some
// of these are functions even though it'd be nicer if they were getters and
// setters.
let iframeAPIPrototype = {
getPanelHeight() {
return this._panel.height;
},
setPanelHeight(val) {
this._panel.height = val;
},
getValue() {
return this._panel.urlbar.value;
},
setValue(val) {
this._panel.urlbar.value = val;
},
getMaxResults() {
return this._panel.p.maxResults;
},
setMaxResults(val) {
this._panel.p.maxResults = val;
},
enter() {
this._panel.urlbar.handleCommand();
},
};

View File

@ -49,6 +49,12 @@ support-files =
moz.png
[browser_tabMatchesInAwesomebar_perwindowpb.js]
skip-if = os == 'linux' # Bug 1104755
[browser_urlbarAddonIframe.js]
support-files =
Panel.jsm
urlbarAddonIframe.html
urlbarAddonIframe.js
urlbarAddonIframeContentScript.js
[browser_urlbarAboutHomeLoading.js]
[browser_urlbarAutoFillTrimURLs.js]
[browser_urlbarCopying.js]

View File

@ -0,0 +1,220 @@
"use strict";
// The purpose of this test is to test the urlbar popup's add-on iframe. It has
// a few parts:
//
// (1) This file, a normal browser mochitest.
// (2) html/js files that are loaded in the urlbar popup's add-on iframe:
// urlbarAddonIframe.{html,js}
// (3) A content script that mediates between the first two parts:
// urlbarAddonIframeContentScript.js
//
// The main test file (this file) sends messages to the content script, which
// forwards them as events to the iframe. These messages tell the iframe js to
// do various things like call functions on the urlbar API and expect events.
// In response, the iframe js dispatches ack events to the content script, which
// forwards them as messages to the main test file.
//
// The content script may not be necessary right now since the iframe is not
// remote. But this structure ensures that if the iframe is made remote in the
// future, then the test won't have to change very much, and ideally not at all.
//
// Actually there's one other part:
//
// (4) The Panel.jsm that's bundled with add-ons that use the iframe.
//
// Panel.jsm defines the API that's made available to add-on scripts running in
// the iframe. This API is orthogonal to the add-on iframe itself. You could
// load any html/js in the iframe, technically. But the purpose of the iframe
// is to support this Panel.jsm API, so that's what this test tests.
const PANEL_JSM_BASENAME = "Panel.jsm";
const IFRAME_BASENAME = "urlbarAddonIframe.html";
const CONTENT_SCRIPT_BASENAME = "urlbarAddonIframeContentScript.js";
// The iframe's message manager.
let gMsgMan;
add_task(function* () {
let rootDirURL = getRootDirectory(gTestPath);
let jsmURL = rootDirURL + PANEL_JSM_BASENAME;
let iframeURL = rootDirURL + IFRAME_BASENAME;
let contentScriptURL = rootDirURL + CONTENT_SCRIPT_BASENAME;
let { Panel } = Cu.import(jsmURL, {});
let panel = new Panel(gURLBar.popup, iframeURL);
registerCleanupFunction(() => {
panel.destroy();
Assert.ok(gURLBar.popup._addonIframe === null, "iframe should be gone");
});
let iframe = gURLBar.popup._addonIframe;
Assert.ok(!!iframe, "iframe should not be null");
gMsgMan =
iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
gMsgMan.loadFrameScript(contentScriptURL, false);
yield promiseIframeLoad();
// urlbar.getValue
let value = "this value set by the test";
gURLBar.value = value;
let readValue = yield promiseUrlbarFunctionCall("getValue");
Assert.equal(readValue, value, "value");
// urlbar.setValue
value = "this value set by the iframe";
yield promiseUrlbarFunctionCall("setValue", value);
Assert.equal(gURLBar.value, value, "setValue");
// urlbar.getMaxResults
let maxResults = gURLBar.popup.maxResults;
Assert.equal(typeof(maxResults), "number", "Sanity check");
let readMaxResults = yield promiseUrlbarFunctionCall("getMaxResults");
Assert.equal(readMaxResults, maxResults, "getMaxResults");
// urlbar.setMaxResults
let newMaxResults = maxResults + 10;
yield promiseUrlbarFunctionCall("setMaxResults", newMaxResults);
Assert.equal(gURLBar.popup.maxResults, newMaxResults, "setMaxResults");
gURLBar.popup.maxResults = maxResults;
// urlbar.enter
value = "http://mochi.test:8888/";
yield promiseUrlbarFunctionCall("setValue", value);
Assert.equal(gURLBar.value, value, "setValue");
yield promiseUrlbarFunctionCall("enter");
let browser = gBrowser.selectedBrowser;
yield BrowserTestUtils.browserLoaded(browser);
Assert.equal(browser.currentURI.spec, value,
"enter should have loaded the URL");
// input, reset, and result events. There should always be at least one
// result, the heuristic result.
value = "test";
let promiseValues = yield Promise.all([
promiseEvent("input")[1],
promiseEvent("reset")[1],
promiseEvent("result")[1],
promiseAutocompleteResultPopup(value, window, true),
]);
// Check the heuristic result.
let result = promiseValues[2];
let engineName = Services.search.currentEngine.name;
Assert.equal(result.url,
`moz-action:searchengine,{"engineName":"${engineName}","input":"test","searchQuery":"test"}`,
"result.url");
Assert.ok("action" in result, "result.action");
Assert.equal(result.action.type, "searchengine", "result.action.type");
Assert.ok("params" in result.action, "result.action.params");
Assert.equal(result.action.params.engineName, engineName,
"result.action.params.engineName");
Assert.equal(typeof(result.image), "string", "result.image");
Assert.equal(result.title, engineName, "result.title");
Assert.equal(result.type, "action searchengine heuristic", "result.type");
Assert.equal(result.text, value, "result.text");
// keydown event. promiseEvent sends an async message to the iframe, but
// synthesizeKey is sync, so we need to wait until the content JS receives
// the message and adds its event listener before synthesizing the key.
let keydownPromises = promiseEvent("keydown");
yield keydownPromises[0];
EventUtils.synthesizeKey("KEY_ArrowDown", {
type: "keydown",
code: "ArrowDown",
});
yield keydownPromises[1];
// urlbar.getPanelHeight
let height = iframe.getBoundingClientRect().height;
let readHeight = yield promiseUrlbarFunctionCall("getPanelHeight");
Assert.equal(readHeight, height, "getPanelHeight");
// urlbar.setPanelHeight
let newHeight = height + 100;
yield promiseUrlbarFunctionCall("setPanelHeight", newHeight);
yield new Promise(resolve => {
// The height change is animated, so give it time to complete. Again, wait
// a sec to be safe.
setTimeout(resolve, 1000);
});
Assert.equal(iframe.getBoundingClientRect().height, newHeight,
"setPanelHeight");
});
function promiseIframeLoad() {
let msgName = "TestIframeLoadAck";
return new Promise(resolve => {
info("Waiting for iframe load ack");
gMsgMan.addMessageListener(msgName, function onMsg(msg) {
info("Received iframe load ack");
gMsgMan.removeMessageListener(msgName, onMsg);
resolve();
});
});
}
/**
* Returns a single promise that's resolved when the content JS has called the
* function.
*/
function promiseUrlbarFunctionCall(...args) {
return promiseMessage("function", args)[0];
}
/**
* Returns two promises in an array. The first is resolved when the content JS
* has added its event listener. The second is resolved when the content JS
* has received the event.
*/
function promiseEvent(type) {
return promiseMessage("event", type, 2);
}
let gNextMessageID = 1;
/**
* Returns an array of promises, one per ack. Each is resolved when the content
* JS acks the message. numExpectedAcks is the number of acks you expect.
*/
function promiseMessage(type, data, numExpectedAcks = 1) {
let testMsgName = "TestMessage";
let ackMsgName = "TestMessageAck";
let msgID = gNextMessageID++;
gMsgMan.sendAsyncMessage(testMsgName, {
type: type,
messageID: msgID,
data: data,
});
let ackPromises = [];
for (let i = 0; i < numExpectedAcks; i++) {
let ackIndex = i;
ackPromises.push(new Promise(resolve => {
info("Waiting for message ack: " + JSON.stringify({
type: type,
msgID: msgID,
ackIndex: ackIndex,
}));
gMsgMan.addMessageListener(ackMsgName, function onMsg(msg) {
// Messages have IDs so that an ack can be correctly paired with the
// initial message it's replying to. It's not an error if the ack's ID
// isn't equal to msgID here. That will happen when multiple messages
// have been sent in a single turn of the event loop so that they're all
// waiting on acks. Same goes for ackIndex.
if (msg.data.messageID != msgID || msg.data.ackIndex != ackIndex) {
return;
}
info("Received message ack: " + JSON.stringify({
type: type,
msgID: msg.data.messageID,
ackIndex: ackIndex,
}));
gMsgMan.removeMessageListener(ackMsgName, onMsg);
resolve(msg.data.data);
});
}));
}
return ackPromises;
}

View File

@ -0,0 +1,8 @@
<html>
<head>
<script src="http://mochi.test:8888/browser/browser/base/content/test/urlbar/urlbarAddonIframe.js"></script>
</head>
<body>
Hello
</body>
</html>

View File

@ -0,0 +1,52 @@
// Listen for messages from the test.
addEventListener("TestEvent", event => {
let type = event.detail.type;
dump("urlbarAddonIframe.js got TestEvent, type=" + type +
" messageID=" + event.detail.messageID + "\n");
switch (type) {
case "function":
callUrlbarFunction(event.detail);
break;
case "event":
expectEvent(event.detail);
break;
}
});
// Calls a urlbar API function.
function callUrlbarFunction(detail) {
let args = detail.data;
let methodName = args.shift();
dump("urlbarAddonIframe.js calling urlbar." + methodName + "\n");
let rv = urlbar[methodName](...args);
ack(detail, rv);
}
// Waits for an event of a specified type to happen.
function expectEvent(detail) {
let type = detail.data;
dump("urlbarAddonIframe.js expecting event of type " + type + "\n");
// Ack that the message was received and an event listener was added.
ack(detail, null, 0);
addEventListener(type, function onEvent(event) {
dump("urlbarAddonIframe.js got event of type " + type + "\n");
if (event.type != type) {
return;
}
dump("urlbarAddonIframe.js got expected event\n");
removeEventListener(type, onEvent);
// Ack that the event was received.
ack(detail, event.detail, 1);
});
}
// Sends an ack to the test.
function ack(originalEventDetail, ackData = null, ackIndex = 0) {
dispatchEvent(new CustomEvent("TestEventAck", {
detail: {
messageID: originalEventDetail.messageID,
ackIndex: ackIndex,
data: ackData,
},
}));
}

View File

@ -0,0 +1,23 @@
// Forward messages from the test to the iframe as events.
addMessageListener("TestMessage", msg => {
content.dispatchEvent(new content.CustomEvent("TestEvent", {
detail: Components.utils.cloneInto(msg.data, content),
}));
});
// Forward events from the iframe to the test as messages.
addEventListener("TestEventAck", event => {
// The waiveXrays call is copied from the contentSearch.js part of
// browser_ContentSearch.js test. Not sure whether it's necessary here.
sendAsyncMessage("TestMessageAck", Components.utils.waiveXrays(event.detail));
}, true, true);
// Send a message to the test when the iframe is loaded.
if (content.document.readyState == "complete") {
sendAsyncMessage("TestIframeLoadAck");
} else {
addEventListener("load", function onLoad(event) {
removeEventListener("load", onLoad);
sendAsyncMessage("TestIframeLoadAck");
}, true, true);
}

View File

@ -1459,7 +1459,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
</getter>
</property>
<property name="maxResults" readonly="true">
<property name="maxResults">
<getter>
<![CDATA[
if (!this._maxResults) {
@ -1471,6 +1471,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
return this._maxResults;
]]>
</getter>
<setter>
<![CDATA[
return this._maxResults = parseInt(val);
]]>
</setter>
</property>
<method name="openAutocompletePopup">
@ -1817,6 +1822,99 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
]]></body>
</method>
<field name="_addonIframe">null</field>
<field name="_addonIframeOwner">null</field>
<field name="_addonIframeOverriddenFunctionsByName">{}</field>
<!-- These methods must be overridden and properly handled by the API
runtime so that it doesn't break the popup. If any of these methods
is not overridden, then initAddonIframe should throw. -->
<field name="_addonIframeOverrideFunctionNames">[
"_invalidate",
]</field>
<field name="_addonIframeHiddenAnonids">[
"search-suggestions-notification",
"richlistbox",
"one-off-search-buttons",
]</field>
<field name="_addonIframeHiddenDisplaysByAnonid">{}</field>
<method name="initAddonIframe">
<parameter name="owner"/>
<parameter name="overrides"/>
<body><![CDATA[
if (this._addonIframeOwner) {
// Another add-on has already requested the iframe. Return null to
// signal to the calling add-on that it should not take over the
// popup. First add-on wins for now.
return null;
}
// Make sure all overrides are provided before doing anything.
for (let name of this._addonIframeOverrideFunctionNames) {
if (typeof(overrides[name]) != "function") {
throw new Error(
"Override for method '" + name + "' must be given"
);
}
}
// OK, insert the iframe.
this._addonIframeOwner = owner;
this._addonIframe = this._makeAddonIframe();
this._addonIframeOverriddenFunctionsByName = {};
for (let name of this._addonIframeOverrideFunctionNames) {
this._addonIframeOverriddenFunctionsByName[name] = this[name];
this[name] = overrides[name];
}
return this._addonIframe;
]]></body>
</method>
<method name="destroyAddonIframe">
<parameter name="owner"/>
<body><![CDATA[
if (this._addonIframeOwner != owner) {
throw new Error("You're not the iframe owner");
}
this._addonIframeOwner = null;
this._addonIframe.remove();
this._addonIframe = null;
for (let anonid of this._addonIframeHiddenAnonids) {
let child = document.getAnonymousElementByAttribute(
this, "anonid", anonid
);
child.style.display =
this._addonIframeHiddenDisplaysByAnonid[anonid];
}
for (let name in this._addonIframeOverriddenFunctionsByName) {
this[name] = this._addonIframeOverriddenFunctionsByName[name];
}
this._addonIframeOverriddenFunctionsByName = {};
]]></body>
</method>
<method name="_makeAddonIframe">
<body><![CDATA[
this._addonIframeHiddenDisplaysByAnonid = {};
for (let anonid of this._addonIframeHiddenAnonids) {
let child = document.getAnonymousElementByAttribute(
this, "anonid", anonid
);
this._addonIframeHiddenDisplaysByAnonid[anonid] =
child.style.display;
child.style.display = "none";
}
let XUL_NS =
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let iframe = document.createElementNS(XUL_NS, "iframe");
iframe.setAttribute("type", "content");
iframe.setAttribute("flex", "1");
iframe.style.transition = "height 100ms";
this.appendChild(iframe);
return iframe;
]]></body>
</method>
</implementation>
<handlers>

View File

@ -9,9 +9,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "clearTimeout",
XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
"resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyGetter(this, "colorUtils", () => {
return require("devtools/shared/css/color").colorUtils;
});
XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
"@mozilla.org/inspector/dom-utils;1",
"inIDOMUtils");
Cu.import("resource://devtools/shared/event-emitter.js");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
@ -528,7 +528,7 @@ extensions.registerSchemaAPI("browserAction", "addon_parent", context => {
let tab = details.tabId !== null ? TabManager.getTab(details.tabId, context) : null;
let color = details.color;
if (!Array.isArray(color)) {
let col = colorUtils.colorToRGBA(color);
let col = DOMUtils.colorToRGBA(color);
color = col && [col.r, col.g, col.b, Math.round(col.a * 255)];
}
BrowserAction.for(extension).setProperty(tab, "badgeBackgroundColor", color);

View File

@ -17,10 +17,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "styleSheetService",
"@mozilla.org/content/style-sheet-service;1",
"nsIStyleSheetService");
XPCOMUtils.defineLazyGetter(this, "colorUtils", () => {
return require("devtools/shared/css/color").colorUtils;
});
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");

View File

@ -88,7 +88,9 @@ TooltipsOverlay.prototype = {
if (this.isRuleView) {
// Color picker tooltip
this.colorPicker = new SwatchColorPickerTooltip(toolbox.doc, this.view.inspector);
this.colorPicker = new SwatchColorPickerTooltip(toolbox.doc,
this.view.inspector,
this._cssProperties);
// Cubic bezier tooltip
this.cubicBezier = new SwatchCubicBezierTooltip(toolbox.doc);
// Filter editor tooltip

View File

@ -40,8 +40,11 @@ const CSS_GRID_ENABLED_PREF = "layout.css.grid.enabled";
* where CSS_TYPES is defined in devtools/shared/css/properties-db.js
* @param {Function} isValidOnClient - A function that checks if a css property
* name/value combo is valid.
* @param {Function} supportsCssColor4ColorFunction - A function for checking
* the supporting of css-color-4 color function.
*/
function OutputParser(document, {supportsType, isValidOnClient}) {
function OutputParser(document,
{supportsType, isValidOnClient, supportsCssColor4ColorFunction}) {
this.parsed = [];
this.doc = document;
this.supportsType = supportsType;
@ -50,6 +53,8 @@ function OutputParser(document, {supportsType, isValidOnClient}) {
this.angleSwatches = new WeakMap();
this._onColorSwatchMouseDown = this._onColorSwatchMouseDown.bind(this);
this._onAngleSwatchMouseDown = this._onAngleSwatchMouseDown.bind(this);
this.cssColor4 = supportsCssColor4ColorFunction();
}
OutputParser.prototype = {
@ -186,7 +191,8 @@ OutputParser.prototype = {
if (options.expectCubicBezier && token.text === "cubic-bezier") {
this._appendCubicBezier(functionText, options);
} else if (colorOK() && colorUtils.isValidCSSColor(functionText)) {
} else if (colorOK() &&
colorUtils.isValidCSSColor(functionText, this.cssColor4)) {
this._appendColor(functionText, options);
} else {
this._appendTextNode(functionText);
@ -203,7 +209,8 @@ OutputParser.prototype = {
options.expectDisplay && token.text === "grid" &&
text === token.text) {
this._appendGrid(token.text, options);
} else if (colorOK() && colorUtils.isValidCSSColor(token.text)) {
} else if (colorOK() &&
colorUtils.isValidCSSColor(token.text, this.cssColor4)) {
this._appendColor(token.text, options);
} else if (angleOK(token.text)) {
this._appendAngle(token.text, options);
@ -216,7 +223,7 @@ OutputParser.prototype = {
case "id":
case "hash": {
let original = text.substring(token.startOffset, token.endOffset);
if (colorOK() && colorUtils.isValidCSSColor(original)) {
if (colorOK() && colorUtils.isValidCSSColor(original, this.cssColor4)) {
this._appendColor(original, options);
} else {
this._appendTextNode(original);
@ -392,7 +399,7 @@ OutputParser.prototype = {
* _mergeOptions().
*/
_appendColor: function (color, options = {}) {
let colorObj = new colorUtils.CssColor(color);
let colorObj = new colorUtils.CssColor(color, this.cssColor4);
if (this._isValidColor(colorObj)) {
let container = this._createNode("span", {

View File

@ -42,15 +42,15 @@ const CSS_COLOR_4_TESTS = [
function run_test() {
for (let test of OLD_STYLE_TESTS) {
let ours = colorUtils.colorToRGBA(test, true);
let ours = colorUtils.colorToRGBA(test, false);
let platform = DOMUtils.colorToRGBA(test);
deepEqual(ours, platform, "color " + test + " matches DOMUtils");
ok(ours !== null, "'" + test + "' is a color");
}
for (let test of CSS_COLOR_4_TESTS) {
let oursOld = colorUtils.colorToRGBA(test, true);
let oursNew = colorUtils.colorToRGBA(test, false);
let oursOld = colorUtils.colorToRGBA(test, false);
let oursNew = colorUtils.colorToRGBA(test, true);
let platform = DOMUtils.colorToRGBA(test);
notEqual(oursOld, platform, "old style parser for color " + test +
" should not match DOMUtils");

View File

@ -28,8 +28,12 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml";
* inline editor.
* @param {InspectorPanel} inspector
* The inspector panel, needed for the eyedropper.
* @param {Function} supportsCssColor4ColorFunction
* A function for checking the supporting of css-color-4 color function.
*/
function SwatchColorPickerTooltip(document, inspector) {
function SwatchColorPickerTooltip(document,
inspector,
{supportsCssColor4ColorFunction}) {
let stylesheet = "chrome://devtools/content/shared/widgets/spectrum.css";
SwatchBasedEditorTooltip.call(this, document, stylesheet);
@ -40,6 +44,7 @@ function SwatchColorPickerTooltip(document, inspector) {
this.spectrum = this.setColorPickerContent([0, 0, 0, 1]);
this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
this._openEyeDropper = this._openEyeDropper.bind(this);
this.cssColor4 = supportsCssColor4ColorFunction();
}
SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.prototype, {
@ -157,14 +162,14 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
},
_colorToRgba: function (color) {
color = new colorUtils.CssColor(color);
color = new colorUtils.CssColor(color, this.cssColor4);
let rgba = color._getRGBATuple();
return [rgba.r, rgba.g, rgba.b, rgba.a];
},
_toDefaultType: function (color) {
let colorObj = new colorUtils.CssColor(color);
colorObj.setAuthoredUnitFromColor(this._originalColor);
colorObj.setAuthoredUnitFromColor(this._originalColor, this.cssColor4);
return colorObj.toString();
},

View File

@ -30,8 +30,12 @@ exports.CssPropertiesActor = ActorClassWithSpec(cssPropertiesSpec, {
getCSSDatabase() {
const properties = generateCssProperties();
const pseudoElements = DOMUtils.getCSSPseudoElementNames();
const supportedFeature = {
// checking for css-color-4 color function support.
"css-color-4-color-function": DOMUtils.isValidCSSColor("rgb(1 1 1 / 100%"),
};
return { properties, pseudoElements };
return { properties, pseudoElements, supportedFeature };
}
});

View File

@ -28,6 +28,10 @@ const SPECIALVALUES = new Set([
* Usage:
* let {colorUtils} = require("devtools/shared/css/color");
* let color = new colorUtils.CssColor("red");
* // In order to support css-color-4 color function, pass true to the
* // second argument.
* // e.g.
* // let color = new colorUtils.CssColor("red", true);
*
* color.authored === "red"
* color.hasAlpha === false
@ -58,8 +62,9 @@ const SPECIALVALUES = new Set([
* Valid values for COLOR_UNIT_PREF are contained in CssColor.COLORUNIT.
*/
function CssColor(colorValue) {
function CssColor(colorValue, supportsCssColor4ColorFunction = false) {
this.newColor(colorValue);
this.cssColor4 = supportsCssColor4ColorFunction;
}
module.exports.colorUtils = {
@ -92,6 +97,9 @@ CssColor.prototype = {
// A lower-cased copy of |authored|.
lowerCased: null,
// Whether the value should be parsed using css-color-4 rules.
cssColor4: false,
_setColorUnitUppercase: function (color) {
// Specifically exclude the case where the color is
// case-insensitive. This makes it so that "#000" isn't
@ -136,7 +144,7 @@ CssColor.prototype = {
},
get valid() {
return isValidCSSColor(this.authored);
return isValidCSSColor(this.authored, this.cssColor4);
},
/**
@ -393,7 +401,7 @@ CssColor.prototype = {
* appropriate.
*/
_getRGBATuple: function () {
let tuple = colorToRGBA(this.authored);
let tuple = colorToRGBA(this.authored, this.cssColor4);
tuple.a = parseFloat(tuple.a.toFixed(1));
@ -481,11 +489,13 @@ function roundTo(number, digits) {
* Color in the form of hex, hsl, hsla, rgb, rgba.
* @param {Number} alpha
* Alpha value for the color, between 0 and 1.
* @param {Boolean} useCssColor4ColorFunction
* use css-color-4 color function or not.
* @return {String}
* Converted color with `alpha` value in rgba form.
*/
function setAlpha(colorValue, alpha) {
let color = new CssColor(colorValue);
function setAlpha(colorValue, alpha, useCssColor4ColorFunction = false) {
let color = new CssColor(colorValue, useCssColor4ColorFunction);
// Throw if the color supplied is not valid.
if (!color.valid) {
@ -1049,12 +1059,11 @@ function parseOldStyleRgb(lexer, hasAlpha) {
* color's components. Any valid CSS color form can be passed in.
*
* @param {String} name the color
* @param {Boolean} oldColorFunctionSyntax use old color function syntax or the
* css-color-4 syntax
* @param {Boolean} useCssColor4ColorFunction use css-color-4 color function or not.
* @return {Object} an object of the form {r, g, b, a}; or null if the
* name was not a valid color
*/
function colorToRGBA(name, oldColorFunctionSyntax = true) {
function colorToRGBA(name, useCssColor4ColorFunction = false) {
name = name.trim().toLowerCase();
if (name in cssColors) {
@ -1089,7 +1098,7 @@ function colorToRGBA(name, oldColorFunctionSyntax = true) {
let hsl = func.text === "hsl" || func.text === "hsla";
let vals;
if (oldColorFunctionSyntax) {
if (!useCssColor4ColorFunction) {
let hasAlpha = (func.text === "rgba" || func.text === "hsla");
vals = hsl ? parseOldStyleHsl(lexer, hasAlpha) : parseOldStyleRgb(lexer, hasAlpha);
} else {
@ -1110,8 +1119,9 @@ function colorToRGBA(name, oldColorFunctionSyntax = true) {
* Check whether a string names a valid CSS color.
*
* @param {String} name The string to check
* @param {Boolean} useCssColor4ColorFunction use css-color-4 color function or not.
* @return {Boolean} True if the string is a CSS color name.
*/
function isValidCSSColor(name) {
return colorToRGBA(name) !== null;
function isValidCSSColor(name, useCssColor4ColorFunction = false) {
return colorToRGBA(name, useCssColor4ColorFunction) !== null;
}

View File

@ -46,6 +46,20 @@ const CssPropertiesFront = FrontClassWithSpec(cssPropertiesSpec, {
}
});
/**
* Query the feature supporting status in the featureSet.
*
* @param {Hashmap} featureSet the feature set hashmap
* @param {String} feature the feature name string
* @return {Boolean} has the feature or not
*/
function hasFeature(featureSet, feature) {
if (feature in featureSet) {
return featureSet[feature];
}
return false;
}
/**
* Ask questions to a CSS database. This class does not care how the database
* gets loaded in, only the questions that you can ask to it.
@ -62,10 +76,16 @@ function CssProperties(db) {
this.properties = db.properties;
this.pseudoElements = db.pseudoElements;
// supported feature
this.cssColor4ColorFunction = hasFeature(db.supportedFeature,
"css-color-4-color-function");
this.isKnown = this.isKnown.bind(this);
this.isInherited = this.isInherited.bind(this);
this.supportsType = this.supportsType.bind(this);
this.isValidOnClient = this.isValidOnClient.bind(this);
this.supportsCssColor4ColorFunction =
this.supportsCssColor4ColorFunction.bind(this);
// A weakly held dummy HTMLDivElement to test CSS properties on the client.
this._dummyElements = new WeakMap();
@ -181,6 +201,15 @@ CssProperties.prototype = {
}
return [];
},
/**
* Checking for the css-color-4 color function support.
*
* @return {Boolean} Return true if the server supports css-color-4 color function.
*/
supportsCssColor4ColorFunction() {
return this.cssColor4ColorFunction;
},
};
/**
@ -296,6 +325,11 @@ function normalizeCssData(db) {
reattachCssColorValues(db);
// If there is no supportedFeature in db, create an empty one.
if (!db.supportedFeature) {
db.supportedFeature = {};
}
return db;
}

View File

@ -10952,7 +10952,8 @@ nsDocShell::DoURILoad(nsIURI* aURI,
if (aBaseURI) {
nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
if (vsc) {
vsc->SetBaseURI(aBaseURI);
rv = vsc->SetBaseURI(aBaseURI);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
}
} else {

View File

@ -18965,7 +18965,7 @@ DatabaseMaintenance::DetermineMaintenanceAction(
bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode();
if (QuotaManager::kRunningXPCShellTests) {
if (QuotaManager::IsRunningXPCShellTests()) {
// If we're running XPCShell then we want to test both the low disk space
// and normal disk space code paths so pick semi-randomly based on the
// current time.

View File

@ -129,7 +129,6 @@ protected:
layers::ImageContainer* mImageContainer;
const VideoInfo& mConfig;
RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
};

View File

@ -1797,11 +1797,13 @@ nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted)
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetMuted failed");
if (mMuted != aMuted) {
mMuted = aMuted;
AudioChannelService::AudibleState audible = aMuted ?
AudioChannelService::AudibleState::eNotAudible :
AudioChannelService::AudibleState::eAudible;
mAudioChannelAgent->NotifyStartedAudible(audible,
AudioChannelService::AudibleChangedReasons::eVolumeChanged);
if (mAudioChannelAgent) {
AudioChannelService::AudibleState audible = aMuted ?
AudioChannelService::AudibleState::eNotAudible :
AudioChannelService::AudibleState::eAudible;
mAudioChannelAgent->NotifyStartedAudible(audible,
AudioChannelService::AudibleChangedReasons::eVolumeChanged);
}
}
return rv;
}

View File

@ -106,8 +106,6 @@ namespace quota {
using namespace mozilla::ipc;
const bool QuotaManager::kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
// We want profiles to be platform-independent so we always need to replace
// the same characters on every platform. Windows has the most extensive set
// of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and

View File

@ -19,6 +19,8 @@
#include "Client.h"
#include "PersistenceType.h"
#include "prenv.h"
#define QUOTA_MANAGER_CONTRACTID "@mozilla.org/dom/quota/manager;1"
class mozIStorageConnection;
@ -113,7 +115,11 @@ private:
public:
NS_INLINE_DECL_REFCOUNTING(QuotaManager)
static const bool kRunningXPCShellTests;
static bool IsRunningXPCShellTests()
{
static bool kRunningXPCShellTests = !!PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR");
return kRunningXPCShellTests;
}
static const char kReplaceChars[];

View File

@ -438,7 +438,7 @@ QuotaManagerService::PerformIdleMaintenance()
#ifdef MOZ_WIDGET_ANDROID
// Android XPCShell doesn't load the AndroidBridge that is needed to make
// GetCurrentBatteryInformation work...
if (!QuotaManager::kRunningXPCShellTests)
if (!QuotaManager::IsRunningXPCShellTests())
#endif
{
// In order to give the correct battery level, hal must have registered
@ -450,7 +450,7 @@ QuotaManagerService::PerformIdleMaintenance()
// If we're running XPCShell because we always want to be able to test this
// code so pretend that we're always charging.
if (QuotaManager::kRunningXPCShellTests) {
if (QuotaManager::IsRunningXPCShellTests()) {
batteryInfo.level() = 100;
batteryInfo.charging() = true;
}
@ -459,7 +459,7 @@ QuotaManagerService::PerformIdleMaintenance()
return;
}
if (QuotaManager::kRunningXPCShellTests) {
if (QuotaManager::IsRunningXPCShellTests()) {
// We don't want user activity to impact this code if we're running tests.
Unused << Observe(nullptr, OBSERVER_TOPIC_IDLE, nullptr);
} else if (!mIdleObserverRegistered) {

View File

@ -1201,12 +1201,23 @@ EditorBase::SetAttribute(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue)
{
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return SetAttribute(element, attribute, aValue);
}
nsresult
EditorBase::SetAttribute(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue)
{
RefPtr<ChangeAttributeTransaction> transaction =
CreateTxnForSetAttribute(*element, *attribute, aValue);
CreateTxnForSetAttribute(*aElement, *aAttribute, aValue);
return DoTransaction(transaction);
}
@ -1235,12 +1246,22 @@ NS_IMETHODIMP
EditorBase::RemoveAttribute(nsIDOMElement* aElement,
const nsAString& aAttribute)
{
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return RemoveAttribute(element, attribute);
}
nsresult
EditorBase::RemoveAttribute(Element* aElement,
nsIAtom* aAttribute)
{
RefPtr<ChangeAttributeTransaction> transaction =
CreateTxnForRemoveAttribute(*element, *attribute);
CreateTxnForRemoveAttribute(*aElement, *aAttribute);
return DoTransaction(transaction);
}
@ -2180,25 +2201,28 @@ EditorBase::CloneAttribute(const nsAString& aAttribute,
nsIDOMNode* aSourceNode)
{
NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
nsAutoString attrValue;
bool isAttrSet;
nsresult rv = GetAttributeValue(sourceElement,
aAttribute,
attrValue,
&isAttrSet);
NS_ENSURE_SUCCESS(rv, rv);
if (isAttrSet) {
rv = SetAttribute(destElement, aAttribute, attrValue);
} else {
rv = RemoveAttribute(destElement, aAttribute);
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
return rv;
nsCOMPtr<Element> destElement = do_QueryInterface(aDestNode);
nsCOMPtr<Element> sourceElement = do_QueryInterface(aSourceNode);
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return CloneAttribute(attribute, destElement, sourceElement);
}
nsresult
EditorBase::CloneAttribute(nsIAtom* aAttribute,
Element* aDestElement,
Element* aSourceElement)
{
nsAutoString attrValue;
if (aSourceElement->GetAttr(kNameSpaceID_None, aAttribute, attrValue)) {
return SetAttribute(aDestElement, aAttribute, attrValue);
}
return RemoveAttribute(aDestElement, aAttribute);
}
/**
@ -2237,11 +2261,9 @@ EditorBase::CloneAttributes(Element* aDest,
RefPtr<nsDOMAttributeMap> destAttributes = aDest->Attributes();
while (RefPtr<Attr> attr = destAttributes->Item(0)) {
if (destInBody) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName());
RemoveAttribute(aDest, attr->NodeInfo()->NameAtom());
} else {
ErrorResult ignored;
aDest->RemoveAttribute(attr->NodeName(), ignored);
aDest->UnsetAttr(kNameSpaceID_None, attr->NodeInfo()->NameAtom(), true);
}
}
@ -2253,13 +2275,13 @@ EditorBase::CloneAttributes(Element* aDest,
nsAutoString value;
attr->GetValue(value);
if (destInBody) {
SetAttributeOrEquivalent(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName(), value, false);
SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value,
false);
} else {
// The element is not inserted in the document yet, we don't want to put
// a transaction on the UndoStack
SetAttributeOrEquivalent(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName(), value, true);
SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value,
true);
}
}
}
@ -4590,21 +4612,32 @@ EditorBase::CreateHTMLContent(nsIAtom* aTag)
kNameSpaceID_XHTML);
}
nsresult
NS_IMETHODIMP
EditorBase::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
return SetAttribute(aElement, aAttribute, aValue);
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (NS_WARN_IF(!element)) {
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return SetAttributeOrEquivalent(element, attribute, aValue,
aSuppressTransaction);
}
nsresult
NS_IMETHODIMP
EditorBase::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction)
{
return RemoveAttribute(aElement, aAttribute);
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (NS_WARN_IF(!element)) {
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return RemoveAttributeOrEquivalent(element, attribute, aSuppressTransaction);
}
nsresult

View File

@ -234,6 +234,19 @@ public:
nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset);
nsresult CloneAttribute(nsIAtom* aAttribute, Element* aDestElement,
Element* aSourceElement);
nsresult RemoveAttribute(Element* aElement, nsIAtom* aAttribute);
virtual nsresult RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) = 0;
nsresult SetAttribute(Element* aElement, nsIAtom* aAttribute,
const nsAString& aValue);
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) = 0;
/**
* Method to replace certain CreateElementNS() calls.
*

View File

@ -3278,15 +3278,15 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
}
}
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsIDOMElement> curElement = do_QueryInterface(curNode);
NS_NAMED_LITERAL_STRING(typestr, "type");
nsCOMPtr<Element> curElement = do_QueryInterface(curNode);
if (aBulletType && !aBulletType->IsEmpty()) {
rv = mHTMLEditor->SetAttribute(curElement, typestr, *aBulletType);
rv = mHTMLEditor->SetAttribute(curElement, nsGkAtoms::type,
*aBulletType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
rv = mHTMLEditor->RemoveAttribute(curElement, typestr);
rv = mHTMLEditor->RemoveAttribute(curElement, nsGkAtoms::type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -4807,7 +4807,6 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
NS_ENSURE_TRUE(node && alignType, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIContent> firstChild, lastChild;
nsCOMPtr<Element> divNode;
bool useCSS = mHTMLEditor->IsCSSEnabled();
@ -4815,24 +4814,25 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
firstChild = mHTMLEditor->GetFirstEditableChild(*node);
NS_ENSURE_STATE(mHTMLEditor);
lastChild = mHTMLEditor->GetLastEditableChild(*node);
NS_NAMED_LITERAL_STRING(attr, "align");
if (!firstChild) {
// this cell has no content, nothing to align
} else if (firstChild == lastChild &&
firstChild->IsHTMLElement(nsGkAtoms::div)) {
// the cell already has a div containing all of its content: just
// act on this div.
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(firstChild);
RefPtr<Element> divElem = firstChild->AsElement();
if (useCSS) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem, attr,
nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem,
nsGkAtoms::align,
*alignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
nsresult rv = mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align,
*alignType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -4840,28 +4840,29 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
} else {
// else we need to put in a div, set the alignment, and toss in all the children
NS_ENSURE_STATE(mHTMLEditor);
divNode = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0);
NS_ENSURE_STATE(divNode);
RefPtr<Element> divElem = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0);
NS_ENSURE_STATE(divElem);
// set up the alignment on the div
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(divNode);
if (useCSS) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv =
mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, *alignType, false);
mHTMLEditor->SetAttributeOrEquivalent(divElem, nsGkAtoms::align,
*alignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
nsresult rv =
mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align, *alignType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// tuck the children into the end of the active div
while (lastChild && (lastChild != divNode)) {
while (lastChild && (lastChild != divElem)) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->MoveNode(lastChild, divNode, 0);
nsresult rv = mHTMLEditor->MoveNode(lastChild, divElem, 0);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(mHTMLEditor);
lastChild = mHTMLEditor->GetLastEditableChild(*node);
@ -6460,9 +6461,9 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
}
// remove ID attribute on the paragraph we just created
nsCOMPtr<nsIDOMElement> rightElt = do_QueryInterface(rightPara);
RefPtr<Element> rightElt = rightPara->AsElement();
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->RemoveAttribute(rightElt, NS_LITERAL_STRING("id"));
rv = mHTMLEditor->RemoveAttribute(rightElt, nsGkAtoms::id);
NS_ENSURE_SUCCESS(rv, rv);
// check both halves of para to see if we need mozBR
@ -8321,18 +8322,18 @@ HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode,
NS_ENSURE_SUCCESS(rv, rv);
} else if (isBlock || HTMLEditUtils::IsHR(child)) {
// the current node is a block element
nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(child);
nsCOMPtr<Element> curElem = do_QueryInterface(child);
if (HTMLEditUtils::SupportsAlignAttr(child)) {
// remove the ALIGN attribute if this element can have it
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->RemoveAttribute(curElem, NS_LITERAL_STRING("align"));
rv = mHTMLEditor->RemoveAttribute(curElem, nsGkAtoms::align);
NS_ENSURE_SUCCESS(rv, rv);
}
if (useCSS) {
if (HTMLEditUtils::IsTable(child) || HTMLEditUtils::IsHR(child)) {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->SetAttributeOrEquivalent(curElem,
NS_LITERAL_STRING("align"),
nsGkAtoms::align,
aAlignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -8452,21 +8453,17 @@ HTMLEditRules::AlignBlock(Element& aElement,
nsresult rv = RemoveAlignment(aElement.AsDOMNode(), aAlignType,
aContentsOnly == ContentsOnly::yes);
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_STRING(attr, "align");
if (htmlEditor->IsCSSEnabled()) {
// Let's use CSS alignment; we use margin-left and margin-right for tables
// and text-align for other block-level elements
rv = htmlEditor->SetAttributeOrEquivalent(
static_cast<nsIDOMElement*>(aElement.AsDOMNode()),
attr, aAlignType, false);
&aElement, nsGkAtoms::align, aAlignType, false);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// HTML case; this code is supposed to be called ONLY if the element
// supports the align attribute but we'll never know...
if (HTMLEditUtils::SupportsAlignAttr(aElement.AsDOMNode())) {
rv = htmlEditor->SetAttribute(
static_cast<nsIDOMElement*>(aElement.AsDOMNode()),
attr, aAlignType);
rv = htmlEditor->SetAttribute(&aElement, nsGkAtoms::align, aAlignType);
NS_ENSURE_SUCCESS(rv, rv);
}
}

View File

@ -2596,7 +2596,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
// New call to use instead to get proper HTML element, bug 39919
nsCOMPtr<nsIAtom> realTagAtom = NS_Atomize(realTagName);
nsCOMPtr<Element> newElement = CreateHTMLContent(realTagAtom);
RefPtr<Element> newElement = CreateHTMLContent(realTagAtom);
if (!newElement) {
return nullptr;
}
@ -2628,8 +2628,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
} else if (tagName.EqualsLiteral("td")) {
nsresult rv =
SetAttributeOrEquivalent(
static_cast<nsIDOMElement*>(newElement->AsDOMNode()),
NS_LITERAL_STRING("valign"), NS_LITERAL_STRING("top"), true);
newElement, nsGkAtoms::valign, NS_LITERAL_STRING("top"), true);
NS_ENSURE_SUCCESS(rv, nullptr);
}
// ADD OTHER TAGS HERE
@ -4447,93 +4446,83 @@ HTMLEditor::IsEmptyNodeImpl(nsINode* aNode,
// add to aElement the CSS inline styles corresponding to the HTML attribute
// aAttribute with its value aValue
nsresult
HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
HTMLEditor::SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
MOZ_ASSERT(aAttribute);
nsAutoScriptBlocker scriptBlocker;
if (IsCSSEnabled() && mCSSEditUtils) {
nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
MOZ_ASSERT(element);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
MOZ_ASSERT(attribute);
int32_t count =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(element, nullptr,
attribute, &aValue,
aSuppressTransaction);
if (count) {
// we found an equivalence ; let's remove the HTML attribute itself if it is set
nsAutoString existingValue;
bool wasSet = false;
nsresult rv =
GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
NS_ENSURE_SUCCESS(rv, rv);
if (!wasSet) {
return NS_OK;
}
return aSuppressTransaction ?
element->UnsetAttr(kNameSpaceID_None, attribute, true) :
RemoveAttribute(aElement, aAttribute);
}
// count is an integer that represents the number of CSS declarations applied to the
// element. If it is zero, we found no equivalence in this implementation for the
// attribute
if (attribute == nsGkAtoms::style) {
// if it is the style attribute, just add the new value to the existing style
// attribute's value
nsAutoString existingValue;
bool wasSet = false;
nsresult rv = GetAttributeValue(aElement, NS_LITERAL_STRING("style"),
existingValue, &wasSet);
NS_ENSURE_SUCCESS(rv, rv);
existingValue.Append(' ');
existingValue.Append(aValue);
return aSuppressTransaction ?
element->SetAttr(kNameSpaceID_None, attribute, existingValue, true) :
SetAttribute(aElement, aAttribute, existingValue);
}
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
if (!IsCSSEnabled() || !mCSSEditUtils) {
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
return aSuppressTransaction ?
element->SetAttr(kNameSpaceID_None, attribute, aValue, true) :
aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
SetAttribute(aElement, aAttribute, aValue);
}
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) :
SetAttribute(aElement, aAttribute, aValue);
int32_t count =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr,
aAttribute, &aValue,
aSuppressTransaction);
if (count) {
// we found an equivalence ; let's remove the HTML attribute itself if it
// is set
nsAutoString existingValue;
if (!aElement->GetAttr(kNameSpaceID_None, aAttribute, existingValue)) {
return NS_OK;
}
return aSuppressTransaction ?
aElement->UnsetAttr(kNameSpaceID_None, aAttribute, true) :
RemoveAttribute(aElement, aAttribute);
}
// count is an integer that represents the number of CSS declarations applied
// to the element. If it is zero, we found no equivalence in this
// implementation for the attribute
if (aAttribute == nsGkAtoms::style) {
// if it is the style attribute, just add the new value to the existing
// style attribute's value
nsAutoString existingValue;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, existingValue);
existingValue.Append(' ');
existingValue.Append(aValue);
return aSuppressTransaction ?
aElement->SetAttr(kNameSpaceID_None, aAttribute, existingValue, true) :
SetAttribute(aElement, aAttribute, existingValue);
}
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
return aSuppressTransaction ?
aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
SetAttribute(aElement, aAttribute, aValue);
}
nsresult
HTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
HTMLEditor::RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction)
{
nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_OK);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
MOZ_ASSERT(attribute);
MOZ_ASSERT(aElement);
MOZ_ASSERT(aAttribute);
if (IsCSSEnabled() && mCSSEditUtils) {
nsresult rv =
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(
element, nullptr, attribute, nullptr, aSuppressTransaction);
aElement, nullptr, aAttribute, nullptr, aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!element->HasAttr(kNameSpaceID_None, attribute)) {
if (!aElement->HasAttr(kNameSpaceID_None, aAttribute)) {
return NS_OK;
}
return aSuppressTransaction ?
element->UnsetAttr(kNameSpaceID_None, attribute, /* aNotify = */ true) :
aElement->UnsetAttr(kNameSpaceID_None, aAttribute, /* aNotify = */ true) :
RemoveAttribute(aElement, aAttribute);
}

View File

@ -121,6 +121,16 @@ public:
virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
virtual bool IsEditable(nsINode* aNode) override;
using EditorBase::IsEditable;
virtual nsresult RemoveAttributeOrEquivalent(
Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) override;
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
using EditorBase::RemoveAttributeOrEquivalent;
using EditorBase::SetAttributeOrEquivalent;
// nsStubMutationObserver overrides
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
@ -329,14 +339,6 @@ public:
*/
virtual nsresult SelectEntireDocument(Selection* aSelection) override;
NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction) override;
/**
* Join together any adjacent editable text nodes in the range.
*/

View File

@ -910,35 +910,30 @@ HTMLEditor::SetFinalSize(int32_t aX,
// we want one transaction only from a user's point of view
AutoEditBatch batchIt(this);
NS_NAMED_LITERAL_STRING(widthStr, "width");
NS_NAMED_LITERAL_STRING(heightStr, "height");
nsCOMPtr<Element> resizedObject = do_QueryInterface(mResizedObject);
NS_ENSURE_TRUE(resizedObject, );
if (mResizedObjectIsAbsolutelyPositioned) {
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::top, y);
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::top, y);
}
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::left, x);
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::left, x);
}
}
if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned) {
if (setWidth && mResizedObject->HasAttr(kNameSpaceID_None, nsGkAtoms::width)) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), widthStr);
RemoveAttribute(mResizedObject, nsGkAtoms::width);
}
if (setHeight && mResizedObject->HasAttr(kNameSpaceID_None,
nsGkAtoms::height)) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), heightStr);
RemoveAttribute(mResizedObject, nsGkAtoms::height);
}
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width,
width);
}
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height,
height);
}
} else {
@ -948,30 +943,30 @@ HTMLEditor::SetFinalSize(int32_t aX,
// triggering an immediate reflow; otherwise, we have problems
// with asynchronous reflow
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width,
width);
}
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height,
height);
}
if (setWidth) {
nsAutoString w;
w.AppendInt(width);
SetAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), widthStr, w);
SetAttribute(mResizedObject, nsGkAtoms::width, w);
}
if (setHeight) {
nsAutoString h;
h.AppendInt(height);
SetAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), heightStr, h);
SetAttribute(mResizedObject, nsGkAtoms::height, h);
}
if (setWidth) {
mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::width,
EmptyString());
}
if (setHeight) {
mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::height,
EmptyString());
}
}

View File

@ -731,9 +731,6 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// if we weren't passed an attribute, then we want to
// remove any matching inlinestyles entirely
if (!aAttribute || aAttribute->IsEmpty()) {
NS_NAMED_LITERAL_STRING(styleAttr, "style");
NS_NAMED_LITERAL_STRING(classAttr, "class");
bool hasStyleAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::style);
bool hasClassAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::_class);
if (aProperty && (hasStyleAttr || hasClassAttr)) {
@ -741,14 +738,14 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// just remove the element... We need to create above the element
// a span that will carry those styles or class, then we can delete
// the node.
nsCOMPtr<Element> spanNode =
RefPtr<Element> spanNode =
InsertContainerAbove(&aNode, nsGkAtoms::span);
NS_ENSURE_STATE(spanNode);
nsresult rv =
CloneAttribute(styleAttr, spanNode->AsDOMNode(), aNode.AsDOMNode());
CloneAttribute(nsGkAtoms::style, spanNode, aNode.AsElement());
NS_ENSURE_SUCCESS(rv, rv);
rv =
CloneAttribute(classAttr, spanNode->AsDOMNode(), aNode.AsDOMNode());
CloneAttribute(nsGkAtoms::_class, spanNode, aNode.AsElement());
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = RemoveContainer(&aNode);

View File

@ -1425,9 +1425,9 @@ TextEditRules::CreateMozBR(nsIDOMNode* inParent,
NS_ENSURE_SUCCESS(rv, rv);
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
nsCOMPtr<Element> brElem = do_QueryInterface(brNode);
if (brElem) {
rv = mTextEditor->SetAttribute(brElem, NS_LITERAL_STRING("type"),
rv = mTextEditor->SetAttribute(brElem, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"));
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -309,9 +309,9 @@ TextEditor::UpdateMetaCharset(nsIDOMDocument* aDocument,
}
// set attribute to <original prefix> charset=text/html
nsCOMPtr<nsIDOMElement> metaElement = do_QueryInterface(metaNode);
RefPtr<Element> metaElement = metaNode->AsElement();
MOZ_ASSERT(metaElement);
rv = EditorBase::SetAttribute(metaElement, NS_LITERAL_STRING("content"),
rv = EditorBase::SetAttribute(metaElement, nsGkAtoms::content,
Substring(originalStart, start) +
charsetEquals +
NS_ConvertASCIItoUTF16(aCharacterSet));
@ -1618,8 +1618,8 @@ TextEditor::GetDOMEventTarget()
nsresult
TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
TextEditor::SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
@ -1627,8 +1627,8 @@ TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
}
nsresult
TextEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
TextEditor::RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction)
{
return EditorBase::RemoveAttribute(aElement, aAttribute);

View File

@ -63,14 +63,17 @@ public:
// nsIEditorMailSupport overrides
NS_DECL_NSIEDITORMAILSUPPORT
// Overrides of EditorBase interface methods
NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction) override;
// Overrides of EditorBase
virtual nsresult RemoveAttributeOrEquivalent(
Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) override;
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
using EditorBase::RemoveAttributeOrEquivalent;
using EditorBase::SetAttributeOrEquivalent;
NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot,
nsISelectionController* aSelCon, uint32_t aFlags,

View File

@ -155,7 +155,7 @@ nsContentDLF::CreateInstance(const char* aCommand,
// type of the data. If it's known, use it; otherwise use
// text/plain.
nsAutoCString type;
viewSourceChannel->GetOriginalContentType(type);
mozilla::Unused << viewSourceChannel->GetOriginalContentType(type);
bool knownType =
(!type.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE) &&
IsTypeInList(type, gHTMLTypes)) ||

View File

@ -7353,12 +7353,9 @@ bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
nsSVGUtils::MaskUsage maskUsage;
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
if (!maskUsage.shouldGenerateMaskLayer && !maskUsage.shouldApplyClipPath &&
!maskUsage.shouldGenerateClipMaskLayer) {
return false;
}
if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyBasicShape) {
// XXX Bug 1323912. nsSVGIntegrationUtils::PaintMask can not handle opacity
// correctly. Turn it off before bug fixed.
if (maskUsage.opacity != 1.0) {
return false;
}

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<title>Paint clip-path onto mask layer</title>
<style type="text/css">
#inner {
width: 200px;
height: 200px;
box-sizing: border-box;
background: blue;
/* make clip-path pained on mask layer */
border: 1px solid transparent;
will-change: transform;
}
#outer {
width: 200px;
height: 200px;
clip-path: inset(0px 100px 100px 0px);
/* make it fixed so that inner div has different AGR with outter div */
position: fixed;
}
</style>
<div id="outer">
<div id="inner"></div>
</div>
</html>

View File

@ -464,3 +464,4 @@ default-preferences
== paint-on-maskLayer-1a.html paint-on-maskLayer-1-ref.html
== paint-on-maskLayer-1b.html paint-on-maskLayer-1-ref.html
== paint-on-maskLayer-1c.html paint-on-maskLayer-1-ref.html

View File

@ -744,9 +744,6 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
nsSVGUtils::MaskUsage maskUsage;
nsSVGUtils::DetermineMaskUsage(aParams.frame, aParams.handleOpacity,
maskUsage);
MOZ_ASSERT(maskUsage.shouldGenerateMaskLayer ||
maskUsage.shouldApplyClipPath ||
maskUsage.shouldGenerateClipMaskLayer);
nsIFrame* frame = aParams.frame;
if (!ValidateSVGFrame(frame)) {
@ -781,23 +778,52 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
SurfaceFormat::A8);
}
if (maskUsage.shouldApplyBasicShape) {
matSR.SetContext(&ctx);
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
offsetToUserSpace);
nsCSSClipPathInstance::ApplyBasicShapeClip(ctx, frame);
if (!maskUsage.shouldGenerateMaskLayer) {
// Only have basic-shape clip-path effect. Fill clipped region by
// opaque white.
ctx.SetColor(Color(0.0, 0.0, 0.0, 1.0));
ctx.Fill();
ctx.PopClip();
return result;
}
}
// Paint mask onto ctx.
if (maskUsage.shouldGenerateMaskLayer) {
matSR.Restore();
matSR.SetContext(&ctx);
SetupContextMatrix(frame, aParams, offsetToBoundingBox,
offsetToUserSpace);
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
bool opacityApplied = !HasNonSVGMask(maskFrames);
result = PaintMaskSurface(aParams, maskTarget,
opacityApplied ? maskUsage.opacity : 1.0,
// XXX Bug 1323912.
MOZ_ASSERT(maskUsage.opacity == 1.0,
"nsSVGIntegrationUtils::PaintMask can not handle opacity now.");
result = PaintMaskSurface(aParams, maskTarget, 1.0,
firstFrame->StyleContext(), maskFrames,
ctx.CurrentMatrix(), offsetToUserSpace);
if (result != DrawResult::SUCCESS) {
if (maskUsage.shouldApplyBasicShape) {
ctx.PopClip();
}
return result;
}
}
if (maskUsage.shouldApplyBasicShape) {
ctx.PopClip();
return result;
}
// Paint clip-path onto ctx.
if (maskUsage.shouldGenerateClipMaskLayer || maskUsage.shouldApplyClipPath) {
matSR.Restore();

View File

@ -27,6 +27,8 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MetaData.h>
#include "mozilla/Assertions.h"
namespace stagefright {
MetaData::MetaData() {
@ -192,7 +194,10 @@ bool MetaData::setData(
ssize_t i = mItems.indexOfKey(key);
if (i < 0) {
typed_data item;
// TODO: "i" will be negative value when OOM,
// we should consider handling this case instead of asserting.
i = mItems.add(key, item);
MOZ_RELEASE_ASSERT(i >= 0, "Item cannot be added due to OOM.");
overwrote_existing = false;
}

View File

@ -8,10 +8,14 @@ package org.mozilla.gecko.activitystream;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.keepsafe.switchboard.SwitchBoard;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.Experiments;
import org.mozilla.gecko.GeckoSharedPrefs;
@ -20,6 +24,7 @@ import org.mozilla.gecko.util.StringUtils;
import org.mozilla.gecko.util.publicsuffix.PublicSuffix;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class ActivityStream {

View File

@ -0,0 +1,170 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.activitystream;
import android.support.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.R;
import org.mozilla.gecko.db.BrowserContract;
import java.util.HashMap;
/**
* Telemetry constants and an 'extras' builder specific to Activity Stream.
*/
public class ActivityStreamTelemetry {
public static class Contract {
// Keys
public final static String FX_ACCOUNT_PRESENT = "fx_account_present";
public final static String ITEM = "item";
public final static String SOURCE_TYPE = "source_type";
public final static String SOURCE_SUBTYPE = "source_subtype";
public final static String ACTION_POSITION = "action_position";
public final static String COUNT = "count";
// Values
public final static String TYPE_TOPSITES = "topsites";
public final static String TYPE_HIGHLIGHTS = "highlights";
public final static String SUBTYPE_PINNED = "pinned";
public final static String SUBTYPE_SUGGESTED = "suggested";
public final static String SUBTYPE_TOP = "top";
public final static String SUBTYPE_VISITED = "visited";
public final static String SUBTYPE_BOOKMARKED = "bookmarked";
public final static String ITEM_SHARE = "share";
public final static String ITEM_ADD_BOOKMARK = "add_bookmark";
public final static String ITEM_REMOVE_BOOKMARK = "remove_bookmark";
public final static String ITEM_PIN = "pin";
public final static String ITEM_UNPIN = "unpin";
public final static String ITEM_COPY = "copy";
public final static String ITEM_ADD_TO_HOMESCREEN = "homescreen";
public final static String ITEM_NEW_TAB = "newtab";
public final static String ITEM_DISMISS = "dismiss";
public final static String ITEM_DELETE_HISTORY = "delete";
}
/**
* A helper class used for composing an 'extras' field. It encapsulates a holder of "global"
* key/value pairs which will be present in every 'extras' constructed by this class, and a
* static builder which is aware of Activity Stream telemetry needs.
*/
public final static class Extras {
private static final HashMap<String, Object> globals = new HashMap<>();
public static void setGlobal(String key, Object value) {
globals.put(key, value);
}
public static Builder builder() {
return new Builder();
}
/**
* Allows composing a JSON extras blob, which is then "built" into a string representation.
*/
public final static class Builder {
private final JSONObject data;
private Builder() {
data = new JSONObject(globals);
}
/**
* @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
* Integer, Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be
* {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
* infinities}.
* @return this object.
*/
public Builder set(@NonNull String key, Object value) {
try {
data.put(key, value);
} catch (JSONException e) {
throw new IllegalArgumentException("Key can't be null");
}
return this;
}
/**
* Sets extras values describing a context menu interaction based on the menu item ID.
*
* @param itemId ID of a menu item, which is transformed into a corresponding item
* key/value pair and passed off to {@link this#set(String, Object)}.
* @return this object.
*/
public Builder fromMenuItemId(int itemId) {
switch (itemId) {
case R.id.share:
this.set(Contract.ITEM, Contract.ITEM_SHARE);
break;
case R.id.copy_url:
this.set(Contract.ITEM, Contract.ITEM_COPY);
break;
case R.id.add_homescreen:
this.set(Contract.ITEM, Contract.ITEM_ADD_TO_HOMESCREEN);
break;
// Our current privacy guidelines do not allow us to write to disk
// Private Browsing-only telemetry that could indicate that PB mode is used.
// See Bug 1325323 for context.
case R.id.open_new_private_tab:
case R.id.open_new_tab:
this.set(Contract.ITEM, Contract.ITEM_NEW_TAB);
break;
case R.id.dismiss:
this.set(Contract.ITEM, Contract.ITEM_DISMISS);
break;
case R.id.delete:
this.set(Contract.ITEM, Contract.ITEM_DELETE_HISTORY);
break;
}
return this;
}
public Builder forHighlightSource(Utils.HighlightSource source) {
switch (source) {
case VISITED:
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_VISITED);
break;
case BOOKMARKED:
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_BOOKMARKED);
break;
default:
throw new IllegalStateException("Unknown highlight source: " + source);
}
return this;
}
public Builder forTopSiteType(int type) {
switch (type) {
case BrowserContract.TopSites.TYPE_PINNED:
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_PINNED);
break;
case BrowserContract.TopSites.TYPE_SUGGESTED:
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_SUGGESTED);
break;
case BrowserContract.TopSites.TYPE_TOP:
this.set(Contract.SOURCE_SUBTYPE, Contract.SUBTYPE_TOP);
break;
// While we also have a "blank" type, it is not used by Activity Stream.
default:
throw new IllegalStateException("Unknown top site type: " + type);
}
return this;
}
public String build() {
return data.toString();
}
}
}
}

View File

@ -0,0 +1,32 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.activitystream;
import android.database.Cursor;
import org.mozilla.gecko.db.BrowserContract;
/**
* Various util methods and constants that are shared by different parts of Activity Stream.
*/
public class Utils {
public enum HighlightSource {
VISITED,
BOOKMARKED
}
public static HighlightSource highlightSource(final Cursor cursor) {
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.BOOKMARK_ID))) {
return HighlightSource.BOOKMARKED;
}
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID))) {
return HighlightSource.VISITED;
}
throw new IllegalArgumentException("Unknown highlight source.");
}
}

View File

@ -606,6 +606,7 @@ public class BrowserContract {
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "highlights");
public static final String DATE = "date";
public static final String METADATA = "metadata";
}
@RobocopTarget

View File

@ -1192,11 +1192,16 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.POSITION) + " AS " + Bookmarks.POSITION + ", " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.URL) + ", " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.TITLE) + ", " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.DATE_CREATED) + " AS " + Highlights.DATE + " " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.DATE_CREATED) + " AS " + Highlights.DATE + ", " +
DBUtils.qualifyColumn(PageMetadata.TABLE_NAME, PageMetadata.JSON) + " AS " + Highlights.METADATA + " " +
"FROM " + Bookmarks.TABLE_NAME + " " +
"LEFT JOIN " + History.TABLE_NAME + " ON " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.URL) + " = " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.URL) + " " +
// 1:1 relationship (Metadata is added via INSERT OR REPLACE)
"LEFT JOIN " + PageMetadata.TABLE_NAME + " ON " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.GUID) + " = " +
DBUtils.qualifyColumn(PageMetadata.TABLE_NAME, PageMetadata.HISTORY_GUID) + " " +
"WHERE " + DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.DATE_CREATED) + " > " + threeDaysAgo + " " +
"AND (" + DBUtils.qualifyColumn(History.TABLE_NAME, History.VISITS) + " <= 3 " +
"OR " + DBUtils.qualifyColumn(History.TABLE_NAME, History.VISITS) + " IS NULL) " +
@ -1218,11 +1223,16 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.POSITION) + " AS " + Bookmarks.POSITION + ", " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.URL) + ", " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.TITLE) + ", " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.DATE_LAST_VISITED) + " AS " + Highlights.DATE + " " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.DATE_LAST_VISITED) + " AS " + Highlights.DATE + ", " +
DBUtils.qualifyColumn(PageMetadata.TABLE_NAME, PageMetadata.JSON) + " AS " + Highlights.METADATA + " " +
"FROM " + History.TABLE_NAME + " " +
"LEFT JOIN " + Bookmarks.TABLE_NAME + " ON " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.URL) + " = " +
DBUtils.qualifyColumn(Bookmarks.TABLE_NAME, Bookmarks.URL) + " " +
// 1:1 relationship (Metadata is added via INSERT OR REPLACE)
"LEFT JOIN " + PageMetadata.TABLE_NAME + " ON " +
DBUtils.qualifyColumn(History.TABLE_NAME, History.GUID) + " = " +
DBUtils.qualifyColumn(PageMetadata.TABLE_NAME, PageMetadata.HISTORY_GUID) + " " +
"WHERE " + DBUtils.qualifyColumn(History.TABLE_NAME, History.DATE_LAST_VISITED) + " < " + last30Minutes + " " +
"AND " + DBUtils.qualifyColumn(History.TABLE_NAME, History.VISITS) + " <= 3 " +
"AND " + DBUtils.qualifyColumn(History.TABLE_NAME, History.TITLE) + " NOT NULL AND " + DBUtils.qualifyColumn(History.TABLE_NAME, History.TITLE) + " != '' " +

View File

@ -11,20 +11,17 @@ import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.Loader;
import android.support.v4.graphics.ColorUtils;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.widget.FrameLayout;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.activitystream.topsites.TopSitesPagerAdapter;
import org.mozilla.gecko.util.ContextUtils;
import org.mozilla.gecko.widget.RecyclerViewClickSupport;
public class ActivityStream extends FrameLayout {
@ -62,6 +59,11 @@ public class ActivityStream extends FrameLayout {
desiredTileWidth = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_width);
desiredTilesHeight = resources.getDimensionPixelSize(R.dimen.activity_stream_desired_tile_height);
tileMargin = resources.getDimensionPixelSize(R.dimen.activity_stream_base_margin);
ActivityStreamTelemetry.Extras.setGlobal(
ActivityStreamTelemetry.Contract.FX_ACCOUNT_PRESENT,
FirefoxAccounts.firefoxAccountsExist(context)
);
}
void setOnUrlOpenListeners(HomePager.OnUrlOpenListener onUrlOpenListener, HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {

View File

@ -14,6 +14,7 @@ import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
@ -21,9 +22,15 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.activitystream.Utils;
import org.mozilla.gecko.activitystream.ActivityStream.LabelCallback;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
@ -42,6 +49,8 @@ import java.util.concurrent.Future;
import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
public abstract class StreamItem extends RecyclerView.ViewHolder {
private static final String LOGTAG = "GeckoStreamItem";
public StreamItem(View itemView) {
super(itemView);
}
@ -135,17 +144,15 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
public static class HighlightItem extends StreamItem implements IconCallback {
public static final int LAYOUT_ID = R.layout.activity_stream_card_history_item;
enum HighlightSource {
VISITED,
BOOKMARKED
}
String title;
String url;
JSONObject metadata;
@Nullable Boolean isPinned;
@Nullable Boolean isBookmarked;
Utils.HighlightSource source;
final FaviconView vIconView;
final TextView vLabel;
final TextView vTimeSince;
@ -180,12 +187,23 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
menuButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_HIGHLIGHTS)
.forHighlightSource(source);
ActivityStreamContextMenu.show(v.getContext(),
menuButton,
extras,
ActivityStreamContextMenu.MenuMode.HIGHLIGHT,
title, url, isBookmarked, isPinned,
onUrlOpenListener, onUrlOpenInBackgroundListener,
vIconView.getWidth(), vIconView.getHeight());
Telemetry.sendUIEvent(
TelemetryContract.Event.SHOW,
TelemetryContract.Method.CONTEXT_MENU,
extras.build()
);
}
});
@ -193,12 +211,21 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
}
public void bind(Cursor cursor, int tilesWidth, int tilesHeight) {
final long time = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.DATE));
final String ago = DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0).toString();
title = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.History.TITLE));
url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
source = Utils.highlightSource(cursor);
try {
final String rawMetadata = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.METADATA));
if (rawMetadata != null) {
metadata = new JSONObject(rawMetadata);
}
} catch (JSONException e) {
Log.w(LOGTAG, "JSONException while parsing page metadata", e);
}
vLabel.setText(title);
vTimeSince.setText(ago);
@ -208,11 +235,9 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
layoutParams.height = tilesHeight;
vIconView.setLayoutParams(layoutParams);
final HighlightSource source = highlightSource(cursor);
updateStateForSource(source, cursor);
updateStateForSource(source);
updateUiForSource(source);
updatePage(url);
updatePage(metadata, url);
if (ongoingIconLoad != null) {
ongoingIconLoad.cancel(true);
@ -225,7 +250,7 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
.execute(this);
}
private void updateStateForSource(HighlightSource source, Cursor cursor) {
private void updateStateForSource(Utils.HighlightSource source) {
// We can only be certain of bookmark state if an item is a bookmark item.
// Otherwise, due to the underlying highlights query, we have to look up states when
// menus are displayed.
@ -243,7 +268,7 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
}
}
private void updateUiForSource(HighlightSource source) {
private void updateUiForSource(Utils.HighlightSource source) {
switch (source) {
case BOOKMARKED:
vSourceView.setText(R.string.activity_stream_highlight_label_bookmarked);
@ -260,12 +285,22 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
vSourceIconView.setImageResource(0);
break;
}
// TODO Why?
// vSourceView.setText(vSourceView.getText());
}
private void updatePage(final String url) {
private void updatePage(final JSONObject metadata, final String url) {
// First try to set the provider name from the page's metadata.
try {
if (metadata != null && metadata.has("provider")) {
vPageView.setText(metadata.getString("provider"));
return;
}
} catch (JSONException e) {
// Broken JSON? Continue with fallback.
}
// If there's no provider name available then let's try to extract one from the URL.
extractLabel(itemView.getContext(), url, false, new LabelCallback() {
@Override
public void onLabelExtracted(String label) {
@ -279,16 +314,4 @@ public abstract class StreamItem extends RecyclerView.ViewHolder {
vIconView.updateImage(response);
}
}
private static HighlightItem.HighlightSource highlightSource(final Cursor cursor) {
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.BOOKMARK_ID))) {
return HighlightItem.HighlightSource.BOOKMARKED;
}
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Combined.HISTORY_ID))) {
return HighlightItem.HighlightSource.VISITED;
}
throw new IllegalArgumentException("Unknown highlight source.");
}
}

View File

@ -13,6 +13,8 @@ import android.view.ViewGroup;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.activitystream.Utils;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.activitystream.StreamItem.HighlightItem;
@ -113,15 +115,25 @@ public class StreamRecyclerAdapter extends RecyclerView.Adapter<StreamItem> impl
return;
}
highlightsCursor.moveToPosition(
translatePositionToCursor(position));
int actualPosition = translatePositionToCursor(position);
highlightsCursor.moveToPosition(actualPosition);
final String url = highlightsCursor.getString(
highlightsCursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
onUrlOpenListener.onUrlOpen(url, EnumSet.of(HomePager.OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM, "as_highlights");
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
.forHighlightSource(Utils.highlightSource(highlightsCursor))
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_HIGHLIGHTS)
.set(ActivityStreamTelemetry.Contract.ACTION_POSITION, actualPosition)
.set(ActivityStreamTelemetry.Contract.COUNT, highlightsCursor.getCount());
Telemetry.sendUIEvent(
TelemetryContract.Event.LOAD_URL,
TelemetryContract.Method.LIST_ITEM,
extras.build()
);
}
@Override

View File

@ -18,6 +18,7 @@ import org.mozilla.gecko.IntentHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.home.HomePager;
@ -38,18 +39,20 @@ public abstract class ActivityStreamContextMenu
TOPSITE
}
final Context context;
private final Context context;
final String title;
final String url;
private final String title;
private final String url;
private final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder;
// We might not know bookmarked/pinned states, so we allow for null values.
// If we aren't told what these are in the constructor, we look them up in postInit.
private @Nullable Boolean isBookmarked;
private @Nullable Boolean isPinned;
final HomePager.OnUrlOpenListener onUrlOpenListener;
final HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener;
private final HomePager.OnUrlOpenListener onUrlOpenListener;
private final HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener;
public abstract MenuItem getItemByID(int id);
@ -57,15 +60,17 @@ public abstract class ActivityStreamContextMenu
public abstract void dismiss();
final MenuMode mode;
private final MenuMode mode;
/* package-private */ ActivityStreamContextMenu(final Context context,
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
final MenuMode mode,
final String title, @NonNull final String url,
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
this.context = context;
this.telemetryExtraBuilder = telemetryExtraBuilder;
this.mode = mode;
@ -83,7 +88,7 @@ public abstract class ActivityStreamContextMenu
* Your implementation must be ready to return items from getItemByID() before postInit() is
* called, i.e. you should probably inflate your menu items before this call.
*/
protected void postInit() {
/* package-local */ void postInit() {
final MenuItem bookmarkItem = getItemByID(R.id.bookmark);
if (Boolean.TRUE.equals(this.isBookmarked)) {
bookmarkItem.setTitle(R.string.bookmark_remove);
@ -106,19 +111,19 @@ public abstract class ActivityStreamContextMenu
// Disable the bookmark item until we know its bookmark state
bookmarkItem.setEnabled(false);
(new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
(new UIAsyncTask.WithoutParams<Boolean>(ThreadUtils.getBackgroundHandler()) {
@Override
protected Void doInBackground() {
isBookmarked = BrowserDB.from(context).isBookmark(context.getContentResolver(), url);
return null;
protected Boolean doInBackground() {
return BrowserDB.from(context).isBookmark(context.getContentResolver(), url);
}
@Override
protected void onPostExecute(Void aVoid) {
if (isBookmarked) {
protected void onPostExecute(Boolean hasBookmark) {
if (hasBookmark) {
bookmarkItem.setTitle(R.string.bookmark_remove);
}
isBookmarked = hasBookmark;
bookmarkItem.setEnabled(true);
}
}).execute();
@ -128,19 +133,19 @@ public abstract class ActivityStreamContextMenu
// Disable the pin item until we know its pinned state
pinItem.setEnabled(false);
(new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
(new UIAsyncTask.WithoutParams<Boolean>(ThreadUtils.getBackgroundHandler()) {
@Override
protected Void doInBackground() {
isPinned = BrowserDB.from(context).isPinnedForAS(context.getContentResolver(), url);
return null;
protected Boolean doInBackground() {
return BrowserDB.from(context).isPinnedForAS(context.getContentResolver(), url);
}
@Override
protected void onPostExecute(Void aVoid) {
if (isPinned) {
protected void onPostExecute(Boolean hasPin) {
if (hasPin) {
pinItem.setTitle(R.string.contextmenu_top_sites_unpin);
}
isPinned = hasPin;
pinItem.setEnabled(true);
}
}).execute();
@ -150,30 +155,25 @@ public abstract class ActivityStreamContextMenu
final MenuItem deleteHistoryItem = getItemByID(R.id.delete);
deleteHistoryItem.setVisible(false);
(new UIAsyncTask.WithoutParams<Void>(ThreadUtils.getBackgroundHandler()) {
boolean hasHistory;
(new UIAsyncTask.WithoutParams<Boolean>(ThreadUtils.getBackgroundHandler()) {
@Override
protected Void doInBackground() {
protected Boolean doInBackground() {
final Cursor cursor = BrowserDB.from(context).getHistoryForURL(context.getContentResolver(), url);
// It's tempting to throw here, but crashing because of a (hopefully) inconsequential
// oddity is somewhat questionable.
if (cursor == null) {
return false;
}
try {
if (cursor != null &&
cursor.getCount() == 1) {
hasHistory = true;
} else {
hasHistory = false;
}
return cursor.getCount() == 1;
} finally {
cursor.close();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
if (hasHistory) {
deleteHistoryItem.setVisible(true);
}
protected void onPostExecute(Boolean hasHistory) {
deleteHistoryItem.setVisible(hasHistory);
}
}).execute();
}
@ -181,49 +181,76 @@ public abstract class ActivityStreamContextMenu
@Override
public boolean onNavigationItemSelected(MenuItem item) {
final int menuItemId = item.getItemId();
// Sets extra telemetry which doesn't require additional state information.
// Pin and bookmark items are handled separately below, since they do require state
// information to handle correctly.
telemetryExtraBuilder.fromMenuItemId(menuItemId);
switch (item.getItemId()) {
case R.id.share:
// NB: Generic menu item action event will be sent at the end of this function.
// We have a seemingly duplicate telemetry event here because we want to emit
// a concrete event in case it is used by other queries to estimate feature usage.
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST, "as_contextmenu");
IntentHelper.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title, false);
break;
case R.id.bookmark:
final TelemetryContract.Event telemetryEvent;
final String telemetryExtra;
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(context);
final boolean isReaderViewPage = rch.isURLCached(url);
// While isBookmarked is nullable, behaviour of postInit - disabling 'bookmark' item
// until we know value of isBookmarked - guarantees that it will be set when we get here.
if (isBookmarked) {
telemetryEvent = TelemetryContract.Event.UNSAVE;
if (isReaderViewPage) {
telemetryExtra = "as_bookmark_reader";
} else {
telemetryExtra = "as_bookmark";
}
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_REMOVE_BOOKMARK);
} else {
telemetryEvent = TelemetryContract.Event.SAVE;
telemetryExtra = "as_bookmark";
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_ADD_BOOKMARK);
}
// NB: Generic menu item action event will be sent at the end of this function.
// We have a seemingly duplicate telemetry event here because we want to emit
// a concrete event in case it is used by other queries to estimate feature usage.
Telemetry.sendUIEvent(telemetryEvent, TelemetryContract.Method.CONTEXT_MENU, telemetryExtra);
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
final BrowserDB db = BrowserDB.from(context);
final TelemetryContract.Event telemetryEvent;
final String telemetryExtra;
if (isBookmarked) {
db.removeBookmarksWithURL(context.getContentResolver(), url);
SavedReaderViewHelper rch = SavedReaderViewHelper.getSavedReaderViewHelper(context);
final boolean isReaderViewPage = rch.isURLCached(url);
telemetryEvent = TelemetryContract.Event.UNSAVE;
if (isReaderViewPage) {
telemetryExtra = "as_bookmark_reader";
} else {
telemetryExtra = "as_bookmark";
}
} else {
// We only store raw URLs in history (and bookmarks), hence we won't ever show about:reader
// URLs in AS topsites or highlights. Therefore we don't need to do any special about:reader handling here.
db.addBookmark(context.getContentResolver(), title, url);
telemetryEvent = TelemetryContract.Event.SAVE;
telemetryExtra = "as_bookmark";
}
Telemetry.sendUIEvent(telemetryEvent, TelemetryContract.Method.CONTEXT_MENU, telemetryExtra);
}
});
break;
case R.id.pin:
// While isPinned is nullable, behaviour of postInit - disabling 'pin' item
// until we know value of isPinned - guarantees that it will be set when we get here.
if (isPinned) {
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_UNPIN);
} else {
telemetryExtraBuilder.set(ActivityStreamTelemetry.Contract.ITEM, ActivityStreamTelemetry.Contract.ITEM_PIN);
}
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
@ -236,6 +263,7 @@ public abstract class ActivityStreamContextMenu
}
}
});
break;
case R.id.copy_url:
Clipboard.setText(url);
@ -243,20 +271,14 @@ public abstract class ActivityStreamContextMenu
case R.id.add_homescreen:
GeckoAppShell.createShortcut(title, url);
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.CONTEXT_MENU, "as_add_to_launcher");
break;
case R.id.open_new_tab:
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.noneOf(HomePager.OnUrlOpenInBackgroundListener.Flags.class));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU, "as_new_tab");
break;
case R.id.open_new_private_tab:
onUrlOpenInBackgroundListener.onUrlOpenInBackground(url, EnumSet.of(HomePager.OnUrlOpenInBackgroundListener.Flags.PRIVATE));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU, "as_private_tab");
break;
case R.id.dismiss:
@ -285,6 +307,12 @@ public abstract class ActivityStreamContextMenu
throw new IllegalArgumentException("Menu item with ID=" + item.getItemId() + " not handled");
}
Telemetry.sendUIEvent(
TelemetryContract.Event.ACTION,
TelemetryContract.Method.CONTEXT_MENU,
telemetryExtraBuilder.build()
);
dismiss();
return true;
}
@ -292,7 +320,7 @@ public abstract class ActivityStreamContextMenu
@RobocopTarget
public static ActivityStreamContextMenu show(Context context,
View anchor,
View anchor, ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
final MenuMode menuMode,
final String title, @NonNull final String url,
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
@ -303,14 +331,14 @@ public abstract class ActivityStreamContextMenu
if (!HardwareUtils.isTablet()) {
menu = new BottomSheetContextMenu(context,
menuMode,
telemetryExtraBuilder, menuMode,
title, url, isBookmarked, isPinned,
onUrlOpenListener, onUrlOpenInBackgroundListener,
tilesWidth, tilesHeight);
} else {
menu = new PopupContextMenu(context,
anchor,
menuMode,
telemetryExtraBuilder, menuMode,
title, url, isBookmarked, isPinned,
onUrlOpenListener, onUrlOpenInBackgroundListener);
}

View File

@ -7,7 +7,6 @@ package org.mozilla.gecko.home.activitystream.menu;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.NavigationView;
import android.view.LayoutInflater;
@ -18,6 +17,7 @@ import android.widget.TextView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.icons.IconCallback;
import org.mozilla.gecko.icons.IconResponse;
@ -35,6 +35,7 @@ import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
private final NavigationView navigationView;
public BottomSheetContextMenu(final Context context,
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
final MenuMode mode,
final String title, @NonNull final String url,
@Nullable final Boolean isBookmarked, @Nullable final Boolean isPinned,
@ -43,6 +44,7 @@ import static org.mozilla.gecko.activitystream.ActivityStream.extractLabel;
final int tilesWidth, final int tilesHeight) {
super(context,
telemetryExtraBuilder,
mode,
title,
url,

View File

@ -16,6 +16,8 @@ import android.view.View;
import android.widget.PopupWindow;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.home.HomePager;
/* package-private */ class PopupContextMenu
@ -28,6 +30,7 @@ import org.mozilla.gecko.home.HomePager;
public PopupContextMenu(final Context context,
View anchor,
final ActivityStreamTelemetry.Extras.Builder telemetryExtraBuilder,
final MenuMode mode,
final String title,
@NonNull final String url,
@ -36,6 +39,7 @@ import org.mozilla.gecko.home.HomePager;
HomePager.OnUrlOpenListener onUrlOpenListener,
HomePager.OnUrlOpenInBackgroundListener onUrlOpenInBackgroundListener) {
super(context,
telemetryExtraBuilder,
mode,
title,
url,

View File

@ -17,6 +17,7 @@ import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
@ -103,13 +104,22 @@ class TopSitesCard extends RecyclerView.ViewHolder
@Override
public void onClick(View clickedView) {
ActivityStreamTelemetry.Extras.Builder extras = ActivityStreamTelemetry.Extras.builder()
.set(ActivityStreamTelemetry.Contract.SOURCE_TYPE, ActivityStreamTelemetry.Contract.TYPE_TOPSITES)
.forTopSiteType(type);
if (clickedView == itemView) {
onUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(HomePager.OnUrlOpenListener.Flags.class));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM, "as_top_sites");
Telemetry.sendUIEvent(
TelemetryContract.Event.LOAD_URL,
TelemetryContract.Method.LIST_ITEM,
extras.build()
);
} else if (clickedView == menuButton) {
ActivityStreamContextMenu.show(clickedView.getContext(),
menuButton,
extras,
ActivityStreamContextMenu.MenuMode.TOPSITE,
title.getText().toString(), url,
@ -118,11 +128,15 @@ class TopSitesCard extends RecyclerView.ViewHolder
onUrlOpenListener, onUrlOpenInBackgroundListener,
faviconView.getWidth(), faviconView.getHeight());
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.CONTEXT_MENU, "as_top_sites");
Telemetry.sendUIEvent(
TelemetryContract.Event.SHOW,
TelemetryContract.Method.CONTEXT_MENU,
extras.build()
);
}
}
private static boolean isPinned(int type) {
private boolean isPinned(int type) {
return type == BrowserContract.TopSites.TYPE_PINNED;
}
}

View File

@ -335,6 +335,8 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'ActionModeCompatView.java',
'ActivityHandlerHelper.java',
'activitystream/ActivityStream.java',
'activitystream/ActivityStreamTelemetry.java',
'activitystream/Utils.java',
'adjust/AdjustBrowserAppDelegate.java',
'animation/AnimationUtils.java',
'animation/HeightChangeAnimation.java',

View File

@ -0,0 +1,147 @@
.. -*- Mode: rst; fill-column: 80; -*-
==============
Activity Stream UI Telemetry
==============
Building on top of UI Telemetry, Activity Stream records additional information about events and user context in which they occur.
The ``extras`` field is used for that purpose; additional information is structured as JSON blobs.
Session
=======
Activity Stream events are recorded as part of the "activitystream.1" session.
Global extras
=============
A concept of a "global" extra is meant to support recording certain context information with every event that is being sent, regardless of its type.
``fx_account_present``, values: true, false
Indicates if Firefox Account is currently enabled.
Extra information available for various event types
===================================================
Top Site interactions
---------------------
Two event types are recorded:
1) User clicked on a Top Site: event="loadurl.1", method="listitem"
2) User clicked on the menu button: event="show.1", method="contextmenu"
For each event, in addition to global extras, the following information is recorded:
extras: {
...
"source_type": "topsites",
"source_subtype": "pinned"/"suggested"/"top"
}
Subtype indicates a reason an item which is being interacted with appeared in the Top Sites:
- "pinned": a pinned top site, specifically a non-positioned "Activity Stream pinned" site
- "suggested": a suggested top site, one of the default ones displayed when there's not enough browsing history available
- "top": a frecency-based top site, based on browsing history. Neither "pinned" nor "suggested".
Highlight interactions
----------------------
Two event types are recorded:
1) User clicked on a Highlight: event="loadurl.1", method="listitem"
2) User clicked on the menu button: event="show.1", method="contextmenu"
For both event types, in addition to global extras, the following information is recorded:
extras: {
...
"source_type": "highlights",
"source_subtype": "visited"/"bookmarked"
}
Subtype indicates reason an item being which is being interacted with appeared in the Highlights:
- "visited": a website has been visited recently
- "bookmarked": a website has been bookmarked recently
For "loadurl.1" event, the following extra information is also recorded:
extras: {
...
"action_position": number, /* 0-based index of a highlight being interacted with */
"count": number, /* total number of highlights displayed */
}
Context Menu interactions
-------------------------
Every interaction with a context menu item is recorded using: event="action.1", method="contextmenu"
For all interactions, in addition to global extras, the following information is recorded:
extras: {
...
"item": string, /* name of a menu item */
"source_type": "topsites"/"highlights",
"source_subtype": string, /* depending on type, one of: "pinned", "suggested", "top", "visited", "bookmarked" */
}
Possible values for "item" key (names of menu items), in no particular order:
- "share"
- "add_bookmark"
- "remove_bookmark"
- "pin"
- "unpin"
- "copy"
- "homescreen"
- "newtab" (private tab actions are collapsed into "newtab" telemetry due to our privacy guidelines)
- "dismiss"
- "delete"
Full Examples
=============
Following examples of events are here to provide a better feel for the overall shape of telemetry data being recorded.
1) User with an active Firefox Account clicked on a menu item for a "visited highlight":
``
session="activitystream.1"
event="show.1"
method="contextmenu"
extras="{
'fx_account_present': true,
'source_type': 'highlights',
'source_subtype': 'visited'
}"
``
2) User with no active Firefox Account clicked on a second highlight (recent bookmark), with total of 7 highlights being displayed:
``
session="activitystream.1"
event="loadurl.1"
method="listitem"
extras="{
'fx_account_present': false,
'source_type': 'highlights',
'source_subtype': 'bookmarked'
'action_position': 1,
'count': 7
}"
``
3) User with an active Firefox Account clicked on a pinned top site:
``
session="activitystream.1"
event="loadurl.1"
method="listitem"
extras="{
'fx_account_present': true,
'source_type': 'topsites',
'source_subtype': 'pinned'
}"
``
4) User with an active Firefox Account clicked on a "share" context menu item, which was displayed for a regular top site:
``
session="activitystream.1"
event="action.1"
method="contextmenu"
extras="{
'fx_account_present': true,
'source_type': 'topsites',
'source_subtype': 'top',
'item': 'share'
}"
``

View File

@ -10,6 +10,8 @@ import android.view.View;
import com.robotium.solo.Condition;
import org.mozilla.gecko.R;
import org.mozilla.gecko.activitystream.ActivityStream;
import org.mozilla.gecko.activitystream.ActivityStreamTelemetry;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.home.activitystream.menu.ActivityStreamContextMenu;
@ -61,7 +63,8 @@ public class testActivityStreamContextMenu extends BaseTest {
private void testMenuForUrl(final String url, final Boolean isBookmarkedKnownState, final boolean isBookmarked, final Boolean isPinnedKnownState, final boolean isPinned, final boolean isVisited) {
final View anchor = new View(getActivity());
final ActivityStreamContextMenu menu = ActivityStreamContextMenu.show(getActivity(), anchor, ActivityStreamContextMenu.MenuMode.HIGHLIGHT, "foobar", url, isBookmarkedKnownState, isPinnedKnownState, null, null, 100, 100);
final ActivityStreamContextMenu menu = ActivityStreamContextMenu.show(
getActivity(), anchor, ActivityStreamTelemetry.Extras.builder(), ActivityStreamContextMenu.MenuMode.HIGHLIGHT, "foobar", url, isBookmarkedKnownState, isPinnedKnownState, null, null, 100, 100);
final int expectedBookmarkString;
if (isBookmarked) {

View File

@ -2161,8 +2161,10 @@ NS_IsSrcdocChannel(nsIChannel *aChannel)
}
nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel);
if (vsc) {
vsc->GetIsSrcdocChannel(&isSrcdoc);
return isSrcdoc;
nsresult rv = vsc->GetIsSrcdocChannel(&isSrcdoc);
if (NS_SUCCEEDED(rv)) {
return isSrcdoc;
}
}
return false;
}

View File

@ -18,12 +18,12 @@ interface nsIViewSourceChannel : nsIChannel
* However, callers interested in finding out or setting the
* actual content type can utilize this attribute.
*/
attribute ACString originalContentType;
[must_use] attribute ACString originalContentType;
/**
* Whether the channel was created to view the source of a srcdoc document.
*/
readonly attribute boolean isSrcdocChannel;
[must_use] readonly attribute boolean isSrcdocChannel;
/**
* Set to indicate the base URI. If this channel is a srcdoc channel, it
@ -32,7 +32,7 @@ interface nsIViewSourceChannel : nsIChannel
* otherwise recoverable. Returns null when it isn't set and isn't a
* srcdoc channel.
*/
attribute nsIURI baseURI;
[must_use] attribute nsIURI baseURI;
};

View File

@ -48,12 +48,12 @@ public:
: mIsDocument(false)
, mOpened(false) {}
nsresult Init(nsIURI* uri);
MOZ_MUST_USE nsresult Init(nsIURI* uri);
nsresult InitSrcdoc(nsIURI* aURI,
nsIURI* aBaseURI,
const nsAString &aSrcdoc,
nsILoadInfo* aLoadInfo);
MOZ_MUST_USE nsresult InitSrcdoc(nsIURI* aURI,
nsIURI* aBaseURI,
const nsAString &aSrcdoc,
nsILoadInfo* aLoadInfo);
protected:
~nsViewSourceChannel() {}

View File

@ -25,11 +25,11 @@ public:
// Creates a new nsViewSourceChannel to view the source of an about:srcdoc
// URI with contents specified by srcdoc.
nsresult NewSrcdocChannel(nsIURI *aURI,
nsIURI *aBaseURI,
const nsAString &aSrcdoc,
nsILoadInfo *aLoadInfo,
nsIChannel** outChannel);
MOZ_MUST_USE nsresult NewSrcdocChannel(nsIURI *aURI,
nsIURI *aBaseURI,
const nsAString &aSrcdoc,
nsILoadInfo *aLoadInfo,
nsIChannel** outChannel);
static nsViewSourceHandler* GetInstance();

View File

@ -2077,9 +2077,8 @@ if test -n "$MOZ_SYSTEM_NSS"; then
else
NSS_CFLAGS="-I${DIST}/include/nss"
case "${OS_ARCH}" in
# This is to match the conditions in security/generate_mapfile.py,
# plus Windows which doesn't run that script.
WINNT|Darwin|Linux)
# Only few platforms have been tested with GYP
WINNT|Darwin|Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
;;
*)
AC_MSG_ERROR([building in-tree NSS is not supported on this platform. Use --with-system-nss])

View File

@ -20,18 +20,18 @@ RUSTUP_URL_BASE = 'https://static-rust-lang-org.s3.amazonaws.com/rustup'
RUSTUP_MANIFEST = os.path.join(RUSTUP_URL_BASE, 'release-stable.toml')
# We bake in a known version number so we can verify a checksum.
RUSTUP_VERSION = '0.6.5'
RUSTUP_VERSION = '1.0.0'
# SHA-256 checksums of the installers, per platform.
RUSTUP_HASHES = {
'x86_64-apple-darwin':
'6404ab0a92c1559bac279a20d31be9166c91434f8e7ff8d1a97bcbe4dbd3cadc',
'x86_64-pc-windows-msvc':
'772579edcbc9a480a61fb19ace49527839e7f919e1041bcc2dee2a4ff82d3ca2',
'x86_64-unknown-linux-gnu':
'e901e23ee48c3a24470d997c4376d8835cecca51bf2636dcd419821d4056d823',
'x86_64-unknown-freebsd':
'63b7c0f35a811993c94af85b96abdd3dcca847d260af284f888e91c2ffdb374e',
'706c2c8a49498b722baad5e8dadaa16a3505e2a9f46b7ee3f41d4dce56163155',
'x86_64-apple-darwin':
'2da68a13feb9a691ef3b59d0d6d53af617962ab5ba4673eaf3818778ccd00bec',
'x86_64-unknown-linux-gnu':
'4cda09438c08eab55cfe4a98325a5722c4ec66865d07da07d38ddc6c36893692',
'x86_64-pc-windows-msvc':
'e3bba8fbb24aed412757d1ea07d6ed1e952ca3f6293b3551e44649601dbe830f',
}
NO_PLATFORM = '''

View File

@ -1044,7 +1044,8 @@ class Artifacts(object):
'revision': revision},
'Will only accept artifacts from a pushhead at {revision} '
'(matched revset "{revset}").')
pushheads = [(list(CANDIDATE_TREES), revision)]
# Include try in our search to allow pulling from a specific push.
pushheads = [(list(CANDIDATE_TREES) + ['try'], revision)]
return self._install_from_hg_pushheads(pushheads, distdir)
def install_from(self, source, distdir):

View File

@ -17,12 +17,7 @@ import buildconfig
def main(output, input):
# There's a check in old-configure.in under the system-nss handling
# that should match this.
if buildconfig.substs['OS_ARCH'] not in ('Linux', 'Darwin'):
print "Error: unhandled OS_ARCH %s" % buildconfig.substs['OS_ARCH']
return 1
is_linux = buildconfig.substs['OS_ARCH'] == 'Linux'
is_darwin = buildconfig.substs['OS_ARCH'] == 'Darwin'
with open(input, 'rb') as f:
for line in f:
@ -30,8 +25,8 @@ def main(output, input):
# Remove all lines containing ';-'
if ';-' in line:
continue
# On non-Linux, remove all lines containing ';+'
if not is_linux and ';+' in line:
# On OS X, remove all lines containing ';+'
if is_darwin and ';+' in line:
continue
# Remove the string ' DATA '.
line = line.replace(' DATA ', '')
@ -40,15 +35,15 @@ def main(output, input):
# Remove the string ';;'
line = line.replace(';;', '')
# If a ';' is present, remove everything after it,
# and on non-Linux, remove it as well.
# and on OS X, remove it as well.
i = line.find(';')
if i != -1:
if is_linux:
line = line[:i+1]
else:
if is_darwin:
line = line[:i]
# On non-Linux, symbols get an underscore in front.
if line and not is_linux:
else:
line = line[:i+1]
# On OS X, symbols get an underscore in front.
if line and is_darwin:
output.write('_')
output.write(line)
output.write('\n')

View File

@ -1149,4 +1149,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1490884654448000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1490970376665000);

View File

@ -43,6 +43,7 @@
7kovrikov.ru: did not receive HSTS header
808.lv: could not connect to host
83i.net: could not connect to host
88.to: could not connect to host
8ack.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
911911.pw: could not connect to host
922.be: could not connect to host
@ -59,6 +60,7 @@ abecodes.net: could not connect to host
abeestrada.com: did not receive HSTS header
abilitylist.org: did not receive HSTS header
abioniere.de: could not connect to host
abnarnro.com: could not connect to host
about.ge: could not connect to host
aboutmyip.info: did not receive HSTS header
aboutmyproperty.ca: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
@ -167,7 +169,6 @@ altfire.ca: could not connect to host
altmv.com: max-age too low: 7776000
alwaysmine.fi: did not receive HSTS header
amaforums.org: could not connect to host
amdouglas.com: could not connect to host
american-truck-simulator.de: could not connect to host
american-truck-simulator.net: could not connect to host
americanworkwear.nl: did not receive HSTS header
@ -214,13 +215,13 @@ ant.land: could not connect to host
anthenor.co.uk: could not connect to host
antimine.kr: could not connect to host
antocom.com: did not receive HSTS header
antoinedeschenes.com: could not connect to host
antoniomarques.eu: did not receive HSTS header
antoniorequena.com.ve: could not connect to host
antscript.com: did not receive HSTS header
any.pm: could not connect to host
anycoin.me: could not connect to host
aojiao.org: did not receive HSTS header
aosc.io: did not receive HSTS header
apachelounge.com: did not receive HSTS header
apeasternpower.com: max-age too low: 0
api.mega.co.nz: could not connect to host
@ -250,6 +251,7 @@ arbu.eu: max-age too low: 2419200
argh.io: could not connect to host
arlen.se: could not connect to host
armingrodon.de: did not receive HSTS header
arminpech.de: could not connect to host
armory.consulting: could not connect to host
armory.supplies: could not connect to host
armytricka.cz: did not receive HSTS header
@ -284,6 +286,7 @@ atavio.at: could not connect to host
atavio.ch: could not connect to host
atavio.de: did not receive HSTS header
atbeckett.com: did not receive HSTS header
atelierdesflammesnoires.fr: could not connect to host
athaliasoft.com: did not receive HSTS header
athenelive.com: could not connect to host
athul.xyz: did not receive HSTS header
@ -321,7 +324,6 @@ axado.com.br: did not receive HSTS header
axeny.com: did not receive HSTS header
az.search.yahoo.com: did not receive HSTS header
azprep.us: could not connect to host
azuxul.fr: could not connect to host
b3orion.com: max-age too low: 0
baby-click.de: did not receive HSTS header
babybic.hu: did not receive HSTS header
@ -347,6 +349,7 @@ basicsolutionsus.com: did not receive HSTS header
basilisk.io: could not connect to host
basnieuwenhuizen.nl: could not connect to host
bassh.net: did not receive HSTS header
baud.ninja: could not connect to host
baumstark.ca: did not receive HSTS header
bazarstupava.sk: could not connect to host
bcbsmagentprofile.com: could not connect to host
@ -378,6 +381,7 @@ beneffy.com: did not receive HSTS header
benk.press: could not connect to host
benny003.de: did not receive HSTS header
benzkosmetik.de: could not connect to host
berasavocate.com: could not connect to host
bergenhave.nl: did not receive HSTS header
bermytraq.bm: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
berr.yt: could not connect to host
@ -416,7 +420,6 @@ binderapp.net: could not connect to host
biofam.ru: did not receive HSTS header
bionicspirit.com: could not connect to host
biophysik-ssl.de: did not receive HSTS header
bioshome.de: could not connect to host
birkman.com: did not receive HSTS header
bismarck.moe: did not receive HSTS header
bitchan.it: could not connect to host
@ -430,8 +433,6 @@ bitheus.com: could not connect to host
bithosting.io: did not receive HSTS header
bitnet.io: did not receive HSTS header
bitsafe.systems: could not connect to host
bitstorm.nl: could not connect to host
bitstorm.org: could not connect to host
bitvigor.com: could not connect to host
bivsi.com: could not connect to host
bizcms.com: did not receive HSTS header
@ -444,14 +445,12 @@ bl4ckb0x.net: did not receive HSTS header
bl4ckb0x.org: did not receive HSTS header
black-armada.com.pl: could not connect to host
black-armada.pl: could not connect to host
black-khat.com: could not connect to host
blackburn.link: did not receive HSTS header
blacklane.com: did not receive HSTS header
blackly.uk: could not connect to host
blackpayment.ru: could not connect to host
blackunicorn.wtf: could not connect to host
blantik.net: could not connect to host
blaudev.es: could not connect to host
blenheimchalcot.com: did not receive HSTS header
blha303.com.au: could not connect to host
blindsexdate.nl: could not connect to host
@ -508,6 +507,7 @@ brandspray.com: did not receive HSTS header
brianmwaters.net: could not connect to host
brickoo.com: could not connect to host
brideandgroomdirect.ie: did not receive HSTS header
brivadois.ovh: could not connect to host
brks.xyz: could not connect to host
broken-oak.com: could not connect to host
brokenhands.io: did not receive HSTS header
@ -551,6 +551,7 @@ bypro.xyz: could not connect to host
bysymphony.com: max-age too low: 0
byte.wtf: did not receive HSTS header
bytepark.de: did not receive HSTS header
bytesunlimited.com: could not connect to host
c1yd3i.me: could not connect to host
c3b.info: could not connect to host
cabarave.com: could not connect to host
@ -564,6 +565,7 @@ cajapopcorn.com: did not receive HSTS header
cake.care: could not connect to host
calgaryconstructionjobs.com: could not connect to host
calix.com: max-age too low: 0
callsigns.ca: could not connect to host
calltrackingreports.com: could not connect to host
calvin.me: max-age too low: 2592000
calvinallen.net: did not receive HSTS header
@ -632,7 +634,6 @@ championsofregnum.com: did not receive HSTS header
chandlerredding.com: did not receive HSTS header
changelab.cc: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
chaos.fail: did not receive HSTS header
chaoslab.org: could not connect to host
chargejuice.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
charnleyhouse.co.uk: max-age too low: 604800
chartpen.com: did not receive HSTS header
@ -715,6 +716,7 @@ cmscafe.ru: did not receive HSTS header
cn.search.yahoo.com: did not receive HSTS header
cni-certing.it: max-age too low: 0
co50.com: did not receive HSTS header
coam.co: did not receive HSTS header
cocaine-import.agency: could not connect to host
codabix.com: did not receive HSTS header
codabix.de: could not connect to host
@ -731,7 +733,6 @@ coiffeurschnittstelle.ch: did not receive HSTS header
coindam.com: could not connect to host
coldfff.com: could not connect to host
coldlostsick.net: could not connect to host
colinwolff.com: could not connect to host
colisfrais.com: did not receive HSTS header
collies.eu: did not receive HSTS header
collins.kg: did not receive HSTS header
@ -767,6 +768,7 @@ core4system.de: could not connect to host
corenetworking.de: could not connect to host
cormilu.com.br: did not receive HSTS header
cornodo.com: could not connect to host
coronelpicanha.com.br: could not connect to host
correctpaardbatterijnietje.nl: did not receive HSTS header
corruption-mc.net: could not connect to host
corruption-rsps.net: could not connect to host
@ -780,7 +782,7 @@ coverduck.ru: could not connect to host
cr.search.yahoo.com: did not receive HSTS header
cracking.org: did not receive HSTS header
craftbeerbarn.co.uk: could not connect to host
craftedge.xyz: could not connect to host
craftedge.xyz: did not receive HSTS header
craftmine.cz: did not receive HSTS header
crate.io: did not receive HSTS header
cravelyrics.com: did not receive HSTS header
@ -830,6 +832,7 @@ cupidmentor.com: did not receive HSTS header
curroapp.com: could not connect to host
custe.rs: could not connect to host
cuvva.insure: did not receive HSTS header
cvjm-memmingen.de: could not connect to host
cyanogenmod.xxx: could not connect to host
cyberpunk.ca: could not connect to host
cybershambles.com: could not connect to host
@ -867,6 +870,7 @@ databutlr.net: could not connect to host
datahove.no: did not receive HSTS header
datarank.com: max-age too low: 0
dataretention.solutions: could not connect to host
datasnitch.co.uk: could not connect to host
datatekniikka.com: could not connect to host
datenkeks.de: did not receive HSTS header
dateno1.com: max-age too low: 2592000
@ -918,6 +922,7 @@ depijl-mz.nl: did not receive HSTS header
depixion.agency: could not connect to host
dequehablamos.es: could not connect to host
derevtsov.com: did not receive HSTS header
dergeilstestammderwelt.de: could not connect to host
derhil.de: did not receive HSTS header
derwolfe.net: did not receive HSTS header
desiccantpackets.com: did not receive HSTS header
@ -981,7 +986,6 @@ doridian.net: did not receive HSTS header
doridian.org: could not connect to host
dossplumbing.co.za: did not receive HSTS header
dotadata.me: could not connect to host
dougferris.id.au: could not connect to host
dovetailnow.com: could not connect to host
download.jitsi.org: did not receive HSTS header
downsouthweddings.com.au: did not receive HSTS header
@ -1000,7 +1004,6 @@ dreaming.solutions: did not receive HSTS header
drishti.guru: could not connect to host
drive.google.com: did not receive HSTS header (error ignored - included regardless)
driving-lessons.co.uk: did not receive HSTS header
drjuanitacollier.com: could not connect to host
droidboss.com: could not connect to host
dropcam.com: did not receive HSTS header
drtroyhendrickson.com: could not connect to host
@ -1012,6 +1015,7 @@ duch.cloud: could not connect to host
duesee.org: could not connect to host
dullsir.com: did not receive HSTS header
duria.de: max-age too low: 3600
dutchrank.com: could not connect to host
dwhd.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
dxa.io: could not connect to host
dycontrol.de: could not connect to host
@ -1050,6 +1054,7 @@ edk.com.tr: did not receive HSTS header
edmodo.com: did not receive HSTS header
edp-collaborative.com: max-age too low: 2500
eduvance.in: did not receive HSTS header
edwards.me.uk: could not connect to host
eenhoorn.ga: did not receive HSTS header
eeqj.com: could not connect to host
efficienthealth.com: did not receive HSTS header
@ -1089,7 +1094,6 @@ email.lookout.com: could not connect to host
emanatepixels.com: could not connect to host
emeldi-commerce.com: max-age too low: 0
emjainteractive.com: did not receive HSTS header
emjimadhu.com: could not connect to host
emmable.com: could not connect to host
emnitech.com: could not connect to host
empleosentorreon.mx: could not connect to host
@ -1124,7 +1128,7 @@ equatetechnologies.com.au: max-age too low: 3600
equilibre-yoga-jennifer-will.com: could not connect to host
erawanarifnugroho.com: did not receive HSTS header
eressea.xyz: could not connect to host
ericyl.com: did not receive HSTS header
ericyl.com: could not connect to host
ernesto.at: could not connect to host
eromixx.com: did not receive HSTS header
erotalia.es: could not connect to host
@ -1261,6 +1265,7 @@ flamingkeys.com.au: could not connect to host
flawcheck.com: did not receive HSTS header
fliexer.com: did not receive HSTS header
floless.co.uk: did not receive HSTS header
florent-tatard.fr: could not connect to host
florian-lillpopp.de: max-age too low: 10
florianlillpopp.de: max-age too low: 10
floridaescapes.co.uk: did not receive HSTS header
@ -1270,7 +1275,6 @@ flowersandclouds.com: could not connect to host
flukethoughts.com: could not connect to host
flushstudios.com: did not receive HSTS header
flyaces.com: did not receive HSTS header
flyss.net: did not receive HSTS header
fm83.nl: could not connect to host
fndout.com: did not receive HSTS header
fnvsecurity.com: could not connect to host
@ -1324,7 +1328,6 @@ fuckgfw233.org: could not connect to host
fugle.de: could not connect to host
fukushima-web.com: did not receive HSTS header
funkyweddingideas.com.au: could not connect to host
funnyang.com: could not connect to host
funrun.com: did not receive HSTS header
furiffic.com: did not receive HSTS header
furry.be: max-age too low: 86400
@ -1375,6 +1378,7 @@ genuu.com: could not connect to host
genuxation.com: could not connect to host
genyaa.com: could not connect to host
gerencianet.com.br: did not receive HSTS header
gersting.net: could not connect to host
get.zenpayroll.com: did not receive HSTS header
getable.com: did not receive HSTS header
getblys.com.au: did not receive HSTS header
@ -1463,6 +1467,7 @@ gparent.org: did not receive HSTS header
gpsfix.cz: could not connect to host
gpstuner.com: did not receive HSTS header
gracesofgrief.com: max-age too low: 86400
graffen.dk: did not receive HSTS header
grandmascookieblog.com: did not receive HSTS header
graph.no: did not receive HSTS header
gravity-net.de: could not connect to host
@ -1472,7 +1477,6 @@ greenvines.com.tw: did not receive HSTS header
gregorytlee.me: could not connect to host
gremots.com: did not receive HSTS header
greplin.com: could not connect to host
gribani.com: could not connect to host
grigalanzsoftware.com: could not connect to host
grossmann.gr: could not connect to host
groups.google.com: did not receive HSTS header (error ignored - included regardless)
@ -1486,7 +1490,6 @@ gtlfsonlinepay.com: did not receive HSTS header
gtraxapp.com: could not connect to host
guava.studio: did not receive HSTS header
guilde-vindicta.fr: did not receive HSTS header
gulenet.com: did not receive HSTS header
gurusupe.com: could not connect to host
gussi.is: could not connect to host
gvt2.com: could not connect to host (error ignored - included regardless)
@ -1604,7 +1607,6 @@ horosho.in: could not connect to host
horseboners.xxx: did not receive HSTS header
hortifarm.ro: did not receive HSTS header
hosted-service.com: did not receive HSTS header
hosted4u.de: could not connect to host
hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
hostgarou.com: did not receive HSTS header
hostinaus.com.au: could not connect to host
@ -1624,6 +1626,7 @@ http418.xyz: could not connect to host
httpstatuscode418.xyz: could not connect to host
hu.search.yahoo.com: did not receive HSTS header
huarongdao.com: did not receive HSTS header
huffduffer.com: could not connect to host
hugosleep.com.au: did not receive HSTS header
humblefinances.com: could not connect to host
humeurs.net: could not connect to host
@ -1689,6 +1692,7 @@ immunicity.press: could not connect to host
immunicity.top: could not connect to host
imolug.org: did not receive HSTS header
imouto.my: max-age too low: 5184000
imouyang.com: could not connect to host
imperialwebsolutions.com: did not receive HSTS header
imu.li: did not receive HSTS header
imusic.dk: did not receive HSTS header
@ -1697,7 +1701,6 @@ inbox.li: did not receive HSTS header
incendiary-arts.com: could not connect to host
inchomatic.com: did not receive HSTS header
indoorskiassen.nl: did not receive HSTS header
indredouglas.me: could not connect to host
indust.me: did not receive HSTS header
infcof.com: max-age too low: 0
infinitude.xyz: could not connect to host
@ -1713,6 +1716,7 @@ inkstory.gr: did not receive HSTS header
inksupply.com: did not receive HSTS header
inleaked.com: could not connect to host
inmyarea.com: max-age too low: 0
innophate-security.com: could not connect to host
innophate-security.nl: could not connect to host
ins1gn1a.com: did not receive HSTS header
insane.zone: could not connect to host
@ -1726,7 +1730,6 @@ intel.li: could not connect to host
intelldynamics.com: could not connect to host
interference.io: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
interlun.com: could not connect to host
internect.co.za: did not receive HSTS header
internetcasinos.de: did not receive HSTS header
internetcensus.org: could not connect to host
interserved.com: did not receive HSTS header
@ -1803,6 +1806,7 @@ jannyrijneveld.nl: did not receive HSTS header
janus-engineering.de: did not receive HSTS header
japlex.com: could not connect to host
jaqen.ch: could not connect to host
jardins-utopie.net: could not connect to host
jaredeberle.org: did not receive HSTS header
jaroslavtrsek.cz: did not receive HSTS header
jartza.org: could not connect to host
@ -1815,7 +1819,6 @@ jayblock.com: did not receive HSTS header
jayschulman.com: could not connect to host
jayscoaching.com: could not connect to host
jayshao.com: did not receive HSTS header
jayxon.com: could not connect to host
jazzinutrecht.info: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
jazzncheese.com: could not connect to host
jbbd.fr: could not connect to host
@ -1893,6 +1896,7 @@ juwairen.cn: could not connect to host
jvoice.net: could not connect to host
jwilsson.me: could not connect to host
jxm.in: could not connect to host
jym.fit: did not receive HSTS header
k-dev.de: could not connect to host
ka-clan.com: could not connect to host
kabuabc.com: did not receive HSTS header
@ -1902,6 +1906,7 @@ kahopoon.net: could not connect to host
kaisers.de: did not receive HSTS header
kalami.nl: did not receive HSTS header
kamikano.com: could not connect to host
kaniklani.co.za: could not connect to host
kaplatz.is: could not connect to host
kapucini.si: max-age too low: 0
karaoketonight.com: could not connect to host
@ -1923,6 +1928,7 @@ keeley.ml: could not connect to host
keeleysam.me: could not connect to host
keepclean.me: could not connect to host
ken.fm: did not receive HSTS header
kennethlim.me: could not connect to host
kentacademiestrust.org.uk: could not connect to host
kerangalam.com: could not connect to host
kerksanders.nl: did not receive HSTS header
@ -1953,6 +1959,7 @@ kisa.io: could not connect to host
kisalt.im: did not receive HSTS header
kissart.net: could not connect to host
kissflow.com: did not receive HSTS header
kisstyle.ru: could not connect to host
kisun.co.jp: could not connect to host
kitakemon.com: could not connect to host
kitchenpunx.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
@ -1989,7 +1996,6 @@ kotovstyle.ru: could not connect to host
kr.search.yahoo.com: did not receive HSTS header
kredite.sale: could not connect to host
kriegt.es: could not connect to host
kristikala.nl: could not connect to host
krmela.com: could not connect to host
kroetenfuchs.de: could not connect to host
kropkait.pl: could not connect to host
@ -2022,6 +2028,7 @@ labs.moscow: did not receive HSTS header
lachlankidson.net: did not receive HSTS header
lacledeslan.ninja: could not connect to host
ladbroke.net: did not receive HSTS header
laextra.mx: could not connect to host
laf.in.net: did not receive HSTS header
lagalerievirtuelle.fr: did not receive HSTS header
lagoza.name: could not connect to host
@ -2037,7 +2044,7 @@ lask.in: did not receive HSTS header
latus.xyz: could not connect to host
lavabit.no: could not connect to host
lavval.com: could not connect to host
lawformt.com: did not receive HSTS header
lawformt.com: could not connect to host
laxatus.com: did not receive HSTS header
laxiongames.es: could not connect to host
lbrt.xyz: could not connect to host
@ -2119,7 +2126,6 @@ livedemo.io: could not connect to host
livej.am: could not connect to host
livi.co: did not receive HSTS header
lnoldan.com: could not connect to host
lntu.org: could not connect to host
loadingdeck.com: did not receive HSTS header
loafbox.com: could not connect to host
lobosdomain.no-ip.info: could not connect to host
@ -2260,7 +2266,6 @@ mca2017.org: did not receive HSTS header
mcc.re: could not connect to host
mcdonalds.ru: did not receive HSTS header
mclab.su: could not connect to host
md5hashing.net: did not receive HSTS header
mdewendt.de: could not connect to host
mdfnet.se: did not receive HSTS header
mdscomp.net: did not receive HSTS header
@ -2346,7 +2351,7 @@ mironized.com: did not receive HSTS header
mirrorx.com: did not receive HSTS header
missrain.tw: could not connect to host
mister.hosting: could not connect to host
misterl.net: did not receive HSTS header
misterl.net: could not connect to host
mitchellrenouf.ca: could not connect to host
mittenhacks.com: could not connect to host
mivcon.net: could not connect to host
@ -2371,7 +2376,7 @@ modemagazines.co.uk: could not connect to host
moebel-nagel.de: did not receive HSTS header
moelord.org: could not connect to host
moen.io: did not receive HSTS header
mogry.net: did not receive HSTS header
mogry.net: could not connect to host
mona.lu: did not receive HSTS header
monarca.systems: could not connect to host
monasterialis.eu: could not connect to host
@ -2402,6 +2407,7 @@ moula.com.au: did not receive HSTS header
mountainmusicpromotions.com: did not receive HSTS header
moviesabout.net: could not connect to host
moy.cat: could not connect to host
mozoa.net: did not receive HSTS header
mp3juices.is: could not connect to host
mqas.net: could not connect to host
mrettich.org: could not connect to host
@ -2434,6 +2440,7 @@ my.alfresco.com: did not receive HSTS header
my.swedbank.se: did not receive HSTS header
my.usa.gov: did not receive HSTS header
myairshop.gr: could not connect to host
myartsjournal.com: did not receive HSTS header
mybon.at: could not connect to host
mybudget.xyz: could not connect to host
mycollab.net: could not connect to host
@ -2468,7 +2475,7 @@ nanogeneinc.com: could not connect to host
nanto.eu: could not connect to host
narada.com.ua: could not connect to host
nargileh.nl: could not connect to host
nascher.org: could not connect to host
nascher.org: max-age too low: 7884000
natalia.io: could not connect to host
natalt.org: did not receive HSTS header
nathanmfarrugia.com: did not receive HSTS header
@ -2487,6 +2494,7 @@ nct.org.uk: max-age too low: 1
nctx.co.uk: did not receive HSTS header
near.st: did not receive HSTS header
neftaly.com: did not receive HSTS header
negai.moe: could not connect to host
negativecurvature.net: could not connect to host
neko-life.com: did not receive HSTS header
neko-system.com: did not receive HSTS header
@ -2540,6 +2548,7 @@ nikksno.io: did not receive HSTS header
nikomo.fi: could not connect to host
ninchisho-online.com: did not receive HSTS header
ninhs.org: could not connect to host
ninux.ch: did not receive HSTS header
nippler.org: did not receive HSTS header
nippombashi.net: did not receive HSTS header
nipponcareers.com: did not receive HSTS header
@ -2628,7 +2637,7 @@ okok-rent.com: could not connect to host
okok.rent: could not connect to host
okutama.in.th: could not connect to host
olafnorge.de: could not connect to host
oliver-pietsch.de: did not receive HSTS header
oliveraiedelabastideblanche.fr: could not connect to host
oliverdunk.com: did not receive HSTS header
ollehbizev.co.kr: could not connect to host
ollie.io: did not receive HSTS header
@ -2637,7 +2646,6 @@ ominto.com: max-age too low: 0
omniasl.com: could not connect to host
omniti.com: max-age too low: 1
omquote.gq: could not connect to host
omskit.ru: could not connect to host
oneb4nk.com: could not connect to host
onefour.co: could not connect to host
oneminute.io: did not receive HSTS header
@ -2719,7 +2727,6 @@ owncloud.help: could not connect to host
ownmovies.fr: could not connect to host
oxygenabsorbers.com: did not receive HSTS header
oxynux.fr: could not connect to host
p-s-b.com: could not connect to host
p.linode.com: could not connect to host
p8r.de: did not receive HSTS header
pa.search.yahoo.com: did not receive HSTS header
@ -2737,6 +2744,7 @@ panaceallc.net: could not connect to host
pantsu.cat: did not receive HSTS header
papeda.net: did not receive HSTS header
papercard.co.uk: did not receive HSTS header
paperwork.co.za: could not connect to host
papierniak.net: could not connect to host
papygeek.com: could not connect to host
parent5446.us: could not connect to host
@ -2809,6 +2817,7 @@ pharmgkb.org: could not connect to host
philpropertygroup.com: could not connect to host
phonenumberinfo.co.uk: could not connect to host
phongmay24h.com: could not connect to host
photoancestry.com: did not receive HSTS header
phpfashion.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
phurl.de: could not connect to host
picallo.es: could not connect to host
@ -2823,7 +2832,7 @@ pinesandneedles.com: did not receive HSTS header
pippen.io: could not connect to host
piratedb.com: could not connect to host
piratedot.com: could not connect to host
piratelist.online: could not connect to host
piratelist.online: did not receive HSTS header
piratenlogin.de: could not connect to host
pirati.cz: max-age too low: 604800
pirlitu.com: did not receive HSTS header
@ -2849,7 +2858,7 @@ playnation.io: did not receive HSTS header
pleier-it.de: did not receive HSTS header
pleier.it: did not receive HSTS header
plhdb.org: did not receive HSTS header
plixer.com: could not connect to host
plixer.com: did not receive HSTS header
plogable.co: could not connect to host
plothost.com: did not receive HSTS header
ploup.net: could not connect to host
@ -2874,7 +2883,6 @@ postcodewise.co.uk: did not receive HSTS header
posterspy.com: did not receive HSTS header
postscheduler.org: could not connect to host
posylka.de: did not receive HSTS header
potatofrom.space: could not connect to host
poussinooz.fr: could not connect to host
povitria.net: could not connect to host
power-of-interest.com: did not receive HSTS header
@ -2890,9 +2898,11 @@ prego-shop.de: did not receive HSTS header
preissler.co.uk: could not connect to host
prelist.org: did not receive HSTS header
pressfreedomfoundation.org: did not receive HSTS header
pretzlaff.info: could not connect to host
preworkout.me: could not connect to host
prezola.com: did not receive HSTS header
princesparktouch.com: could not connect to host
printexpress.cloud: did not receive HSTS header
printfn.com: could not connect to host
priolkar.com: did not receive HSTS header
priva.si: could not connect to host
@ -2919,7 +2929,8 @@ proximato.com: could not connect to host
proxybay.al: could not connect to host
proxybay.club: could not connect to host
proxybay.info: did not receive HSTS header
prxio.site: could not connect to host
prxio.date: could not connect to host
prxio.site: did not receive HSTS header
prytkov.com: did not receive HSTS header
psw.academy: did not receive HSTS header
psw.consulting: did not receive HSTS header
@ -2929,7 +2940,6 @@ puhe.se: could not connect to host
puiterwijk.org: could not connect to host
pumpgames.net: could not connect to host
punchr-kamikazee.rhcloud.com: did not receive HSTS header
pupboss.com: could not connect to host
purewebmasters.com: could not connect to host
purplemoon.mobi: did not receive HSTS header
purplestar.mobi: did not receive HSTS header
@ -2994,7 +3004,7 @@ realmic.net: could not connect to host
realmofespionage.com: could not connect to host
reardenporn.com: could not connect to host
recommended.reviews: could not connect to host
redar.xyz: could not connect to host
redar.xyz: did not receive HSTS header
reddiseals.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
reddit.com: did not receive HSTS header
rede.ca: did not receive HSTS header
@ -3010,7 +3020,6 @@ reggae-cdmx.com: did not receive HSTS header
reic.me: could not connect to host
rejo.in: could not connect to host
rejuvemedspa.com: did not receive HSTS header
relayawards.com: did not receive HSTS header
relisten.nl: did not receive HSTS header
rem.pe: could not connect to host
remitatm.com: could not connect to host
@ -3046,6 +3055,7 @@ richiemail.net: did not receive HSTS header
richmondsunlight.com: did not receive HSTS header
rid-wan.com: could not connect to host
rideworks.com: did not receive HSTS header
riesenweber.id.au: did not receive HSTS header
right2.org: could not connect to host
righttoknow.ie: did not receive HSTS header
rijndael.xyz: could not connect to host
@ -3061,7 +3071,6 @@ rme.li: did not receive HSTS header
roan24.pl: did not receive HSTS header
robertglastra.com: could not connect to host
robigalia.org: did not receive HSTS header
robohash.org: could not connect to host
robtex.com: did not receive HSTS header
robtex.net: did not receive HSTS header
robtex.org: did not receive HSTS header
@ -3072,6 +3081,7 @@ rodney.id.au: did not receive HSTS header
rodosto.com: did not receive HSTS header
roeper.party: could not connect to host
roesemann.email: could not connect to host
roessner-network-solutions.com: could not connect to host
rohlik.cz: could not connect to host
rolemaster.net: could not connect to host
romans-place.me.uk: did not receive HSTS header
@ -3185,7 +3195,6 @@ search-one.de: did not receive HSTS header
sebastian-lutsch.de: could not connect to host
sebster.com: did not receive HSTS header
secandtech.com: could not connect to host
secondpay.nl: did not receive HSTS header
secpatrol.de: could not connect to host
sectia22.ro: could not connect to host
sectun.com: did not receive HSTS header
@ -3200,6 +3209,7 @@ securityinet.net: did not receive HSTS header
securityinet.org.il: did not receive HSTS header
securitysoapbox.com: could not connect to host
securiviera.ch: did not receive HSTS header
sedrubal.de: could not connect to host
seedbox.fr: did not receive HSTS header
seele.ca: could not connect to host
segulink.com: could not connect to host
@ -3273,7 +3283,6 @@ sifls.com: could not connect to host
silentcircle.org: could not connect to host
silicagelpackets.ca: did not receive HSTS header
silver-drachenkrieger.de: did not receive HSTS header
silverhome.ninja: could not connect to host
silverpvp.com: could not connect to host
silverwind.io: did not receive HSTS header
simbast.com: could not connect to host
@ -3289,6 +3298,7 @@ simply-premium.com: max-age too low: 0
sincron.org: could not connect to host
siriad.com: did not receive HSTS header
sirius-lee.net: could not connect to host
sitennisclub.com: did not receive HSTS header
sites.google.com: did not receive HSTS header (error ignored - included regardless)
sitesten.com: did not receive HSTS header
sitsy.ru: did not receive HSTS header
@ -3340,7 +3350,7 @@ sobotkama.eu: did not receive HSTS header
soccergif.com: could not connect to host
soci.ml: did not receive HSTS header
socialbillboard.com: could not connect to host
socialdevelop.biz: could not connect to host
socialdevelop.biz: did not receive HSTS header
socialhams.net: did not receive HSTS header
socialhead.io: could not connect to host
socialspirit.com.br: did not receive HSTS header
@ -3466,6 +3476,7 @@ stugb.de: did not receive HSTS header
stw-group.at: could not connect to host
subbing.work: could not connect to host
subdimension.org: could not connect to host
subeesu.com: could not connect to host
subrosa.io: could not connect to host
subtitle.rip: could not connect to host
sudo.li: did not receive HSTS header
@ -3475,9 +3486,9 @@ suksit.com: could not connect to host
sumoatm.com: did not receive HSTS header
sumoscout.de: did not receive HSTS header
suncountrymarine.com: did not receive HSTS header
sunflyer.cn: did not receive HSTS header
sunnyfruit.ru: did not receive HSTS header
sunshinepress.org: could not connect to host
sunyanzi.tk: could not connect to host
superbabysitting.ch: could not connect to host
superbike.tw: could not connect to host
supereight.net: did not receive HSTS header
@ -3508,7 +3519,6 @@ synackr.com: could not connect to host
syncer.jp: did not receive HSTS header
syncserve.net: did not receive HSTS header
syneic.com: did not receive HSTS header
synfin.org: could not connect to host
syno.gq: could not connect to host
syntheticmotoroil.org: did not receive HSTS header
syso.name: could not connect to host
@ -3556,7 +3566,6 @@ tcp.expert: did not receive HSTS header
teachforcanada.ca: did not receive HSTS header
team-pancake.eu: could not connect to host
teamsocial.co: did not receive HSTS header
teamx-gaming.de: could not connect to host
teamzeus.cz: could not connect to host
techassist.io: did not receive HSTS header
techhipster.net: could not connect to host
@ -3567,6 +3576,7 @@ techmatehq.com: could not connect to host
technosavvyport.com: did not receive HSTS header
techpointed.com: could not connect to host
techvalue.gr: did not receive HSTS header
tedovo.com: could not connect to host
tegelsensanitaironline.nl: did not receive HSTS header
tekshrek.com: did not receive HSTS header
telefonnummer.online: could not connect to host
@ -3592,6 +3602,7 @@ tfl.lu: did not receive HSTS header
tgr.re: could not connect to host
th-bl.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
thai.land: could not connect to host
thaianthro.com: did not receive HSTS header
the-construct.com: could not connect to host
the-sky-of-valkyries.com: could not connect to host
theamateurs.net: did not receive HSTS header
@ -3681,6 +3692,7 @@ tokyopopline.com: did not receive HSTS header
tollmanz.com: did not receive HSTS header
tom.horse: did not receive HSTS header
tomberek.info: could not connect to host
tomcort.com: could not connect to host
tomeara.net: could not connect to host
tomharling.co.uk: max-age too low: 86400
tomharling.uk: max-age too low: 86400
@ -3713,7 +3725,6 @@ translate.googleapis.com: did not receive HSTS header (error ignored - included
transportal.sk: did not receive HSTS header
treeby.net: could not connect to host
trendberry.ru: could not connect to host
trik.es: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
trinityaffirmations.com: max-age too low: 0
trinitycore.org: max-age too low: 2592000
tripdelta.com: did not receive HSTS header
@ -3766,6 +3777,7 @@ ubuntuhot.com: did not receive HSTS header
uega.net: did not receive HSTS header
ufgaming.com: did not receive HSTS header
ufotable.uk: max-age too low: 0
uhm.io: did not receive HSTS header
ui8.net: max-age too low: 86400
ukas.com: did not receive HSTS header
ukdropshipment.co.uk: did not receive HSTS header
@ -3880,7 +3892,6 @@ vlora.city: could not connect to host
vm0.eu: did not receive HSTS header
vmrdev.com: could not connect to host
voceinveste.com: did not receive HSTS header
vogler.name: could not connect to host
voicesuk.co.uk: did not receive HSTS header
volcrado.com: could not connect to host
voliere-info.nl: did not receive HSTS header
@ -3922,7 +3933,6 @@ wealthfactory.com: [Exception... "Component returned failure code: 0x80004005 (N
wear2work.nl: did not receive HSTS header
wearandcare.net: could not connect to host
weaverhairextensions.nl: could not connect to host
web-vision.de: could not connect to host
web4all.fr: max-age too low: 0
web4pro.fr: max-age too low: 0
webandwords.com.au: could not connect to host
@ -4105,6 +4115,7 @@ yabrt.cn: could not connect to host
yamaken.jp: did not receive HSTS header
yamamo10.com: could not connect to host
yanaduday.com: could not connect to host
yanwh.xyz: could not connect to host
yaporn.tv: did not receive HSTS header
yard-fu.com: could not connect to host
yasinaydin.net: max-age too low: 2592000
@ -4133,7 +4144,6 @@ youcontrol.ru: could not connect to host
youngandunited.nl: did not receive HSTS header
yourstrongbox.com: could not connect to host
yout.com: max-age too low: 60000
ypid.de: could not connect to host
ytec.ca: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121" data: no]
yu.gg: did not receive HSTS header
yuan.ga: did not receive HSTS header
@ -4154,7 +4164,6 @@ zadieheimlich.com: did not receive HSTS header
zamorano.edu: could not connect to host
zap.yt: could not connect to host
zarooba.com: did not receive HSTS header
zberger.com: could not connect to host
zbigniewgalucki.eu: did not receive HSTS header
zbp.at: did not receive HSTS header
zebrababy.cn: did not receive HSTS header
@ -4171,6 +4180,7 @@ zera.com.au: could not connect to host
zett4.me: could not connect to host
zeytin.pro: could not connect to host
zh.search.yahoo.com: did not receive HSTS header
zhaochen.xyz: could not connect to host
zhaojin97.cn: did not receive HSTS header
zhendingresources.com: max-age too low: 0
zicklam.com: could not connect to host

File diff suppressed because it is too large Load Diff

View File

@ -325,10 +325,9 @@ static const char contentSandboxRules[] =
"\n"
" (allow-shared-list \"org.mozilla.plugincontainer\")\n"
"\n"
"; the following 2 rules should be removed when microphone and camera access\n"
"; are brokered through the content process\n"
"; the following rule should be removed when microphone access\n"
"; is brokered through the content process\n"
" (allow device-microphone)\n"
" (allow device-camera)\n"
"\n"
" (allow file* (var-folders2-regex \"/com\\.apple\\.IntlDataCache\\.le$\"))\n"
" (allow file-read*\n"

View File

@ -19,7 +19,7 @@ scopes:
# Bug 1269443: cache scopes, etc. must be listed explicitly
- "docker-worker:cache:tooltool-cache"
- "secrets:get:project/taskcluster/gecko/hgfingerprint"
- "assume:repo:hg.mozilla.org/{{project}}:*"
- {{repo_scope}}
routes:
- "tc-treeherder.v2.{{project}}.{{head_rev}}.{{pushlog_id}}"

View File

@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals
import os
import json
import logging
import re
import time
import yaml
@ -178,10 +179,17 @@ def write_artifact(filename, data):
def get_action_yml(parameters):
templates = Templates(os.path.join(GECKO, "taskcluster/taskgraph"))
action_parameters = parameters.copy()
match = re.match(r'https://(hg.mozilla.org)/(.*?)/?$', action_parameters['head_repository'])
if not match:
raise Exception('Unrecognized head_repository')
repo_scope = 'assume:repo:{}/{}:*'.format(
match.group(1), match.group(2))
action_parameters.update({
"action": "{{action}}",
"action_args": "{{action_args}}",
"project": parameters["project"],
"repo_scope": repo_scope,
"from_now": json_time_from_now,
"now": current_json_time()
})

View File

@ -75,6 +75,24 @@ def validate_schema(schema, obj, msg_prefix):
raise Exception('\n'.join(msg) + '\n' + pprint.pformat(obj))
def optionally_keyed_by(*arguments):
"""
Mark a schema value as optionally keyed by any of a number of fields. The
schema is the last argument, and the remaining fields are taken to be the
field names. For example:
'some-value': optionally_keyed_by(
'test-platform', 'build-platform',
Any('a', 'b', 'c'))
"""
subschema = arguments[-1]
fields = arguments[:-1]
options = [subschema]
for field in fields:
options.append({'by-' + field: {basestring: subschema}})
return voluptuous.Any(*options)
def get_keyed_by(item, field, item_name, subfield=None):
"""
For values which can either accept a literal value, or be keyed by some

View File

@ -40,3 +40,11 @@ def set_treeherder_machine_platform(config, tests):
build_platform = test['build-platform']
test['treeherder-machine-platform'] = translation.get(build_platform, build_platform)
yield test
@transforms.add
def set_e10s_attr(config, tests):
"""Set the e10s attribute to false"""
for test in tests:
test.setdefault('attributes', {})['e10s'] = False
yield test

View File

@ -95,9 +95,9 @@ def split_e10s(config, tests):
def allow_software_gl_layers(config, tests):
for test in tests:
# since this value defaults to true, but is not applicable on windows,
# since this value defaults to true, but is not applicable on non-linux,
# it's overriden for that platform here.
allow = not test['test-platform'].startswith('win') \
allow = test['test-platform'].startswith('linux') \
and get_keyed_by(item=test, field='allow-software-gl-layers',
item_name=test['test-name'])
if allow:

View File

@ -9,7 +9,7 @@ transforms do not generate invalid tests.
from __future__ import absolute_import, print_function, unicode_literals
from taskgraph.transforms.base import validate_schema
from taskgraph.transforms.base import validate_schema, optionally_keyed_by
from voluptuous import (
Any,
Optional,
@ -32,10 +32,7 @@ test_description_schema = Schema({
'description': basestring,
# test suite name, or <suite>/<flavor>
Required('suite'): Any(
basestring,
{'by-test-platform': {basestring: basestring}},
),
Required('suite'): optionally_keyed_by('test-platform', basestring),
# the name by which this test suite is addressed in try syntax; defaults to
# the test-name
@ -60,10 +57,9 @@ test_description_schema = Schema({
# The `run_on_projects` attribute, defaulting to "all". This dictates the
# projects on which this task should be included in the target task set.
# See the attributes documentation for details.
Optional('run-on-projects', default=['all']): Any(
[basestring],
{'by-test-platform': {basestring: [basestring]}},
),
Optional('run-on-projects', default=['all']): optionally_keyed_by(
'test-platform',
[basestring]),
# the sheriffing tier for this task (default: set based on test platform)
Optional('tier'): Any(
@ -74,10 +70,7 @@ test_description_schema = Schema({
# number of chunks to create for this task. This can be keyed by test
# platform by passing a dictionary in the `by-test-platform` key. If the
# test platform is not found, the key 'default' will be tried.
Required('chunks', default=1): Any(
int,
{'by-test-platform': {basestring: int}},
),
Required('chunks', default=1): optionally_keyed_by('test-platform', int),
# the time (with unit) after which this task is deleted; default depends on
# the branch (see below)
@ -87,16 +80,14 @@ test_description_schema = Schema({
# without e10s; if true, run with e10s; if 'both', run one task with and
# one task without e10s. E10s tasks have "-e10s" appended to the test name
# and treeherder group.
Required('e10s', default='both'): Any(
bool, 'both',
{'by-test-platform': {basestring: Any(bool, 'both')}},
),
Required('e10s', default='both'): optionally_keyed_by(
'test-platform',
Any(bool, 'both')),
# The EC2 instance size to run these tests on.
Required('instance-size', default='default'): Any(
Any('default', 'large', 'xlarge', 'legacy'),
{'by-test-platform': {basestring: Any('default', 'large', 'xlarge', 'legacy')}},
),
Required('instance-size', default='default'): optionally_keyed_by(
'test-platform',
Any('default', 'large', 'xlarge', 'legacy')),
# Whether the task requires loopback audio or video (whatever that may mean
# on the platform)
@ -132,10 +123,7 @@ test_description_schema = Schema({
# seconds of runtime after which the task will be killed. Like 'chunks',
# this can be keyed by test pltaform.
Required('max-run-time', default=3600): Any(
int,
{'by-test-platform': {basestring: int}},
),
Required('max-run-time', default=3600): optionally_keyed_by('test-platform', int),
# the exit status code that indicates the task should be retried
Optional('retry-exit-status'): int,
@ -149,20 +137,16 @@ test_description_schema = Schema({
Required('script'): basestring,
# the config files required for the task
Required('config'): Any(
[basestring],
{'by-test-platform': {basestring: [basestring]}},
),
Required('config'): optionally_keyed_by('test-platform', [basestring]),
# any additional actions to pass to the mozharness command
Optional('actions'): [basestring],
# additional command-line options for mozharness, beyond those
# automatically added
Required('extra-options', default=[]): Any(
[basestring],
{'by-test-platform': {basestring: [basestring]}},
),
Required('extra-options', default=[]): optionally_keyed_by(
'test-platform',
[basestring]),
# the artifact name (including path) to test on the build task; this is
# generally set in a per-kind transformation
@ -211,11 +195,9 @@ test_description_schema = Schema({
# os user groups for test task workers; required scopes, will be
# added automatically
Optional('os-groups', default=[]): Any(
[basestring],
# todo: create a dedicated elevated worker group and name here
{'by-test-platform': {basestring: [basestring]}},
),
Optional('os-groups', default=[]): optionally_keyed_by(
'test-platform',
[basestring]),
# -- values supplied by the task-generation infrastructure

View File

@ -59,7 +59,7 @@
#include <shlwapi.h>
PRLogModuleInfo* gWindowsLog = nullptr;
mozilla::LazyLogModule gWindowsLog("Widget");
using namespace mozilla::gfx;
@ -462,9 +462,6 @@ static NtTestAlertPtr sNtTestAlert = nullptr;
void
WinUtils::Initialize()
{
if (!gWindowsLog) {
gWindowsLog = PR_NewLogModule("Widget");
}
if (!sDwmDll && IsVistaOrLater()) {
sDwmDll = ::LoadLibraryW(kDwmLibraryName);

View File

@ -6,6 +6,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/gfx/PrintTargetPDF.h"
#include "mozilla/gfx/PrintTargetWindows.h"
#include "mozilla/Logging.h"
#include "mozilla/RefPtr.h"
#include "nsDeviceContextSpecWin.h"
@ -34,7 +35,7 @@
#include "mozilla/gfx/Logging.h"
#include "mozilla/Logging.h"
PRLogModuleInfo * kWidgetPrintingLogMod = PR_NewLogModule("printing-widget");
static mozilla::LazyLogModule kWidgetPrintingLogMod("printing-widget");
#define PR_PL(_p1) MOZ_LOG(kWidgetPrintingLogMod, mozilla::LogLevel::Debug, _p1)
using namespace mozilla;

View File

@ -6,6 +6,7 @@
#include "nsNativeThemeWin.h"
#include "mozilla/EventStates.h"
#include "mozilla/Logging.h"
#include "mozilla/WindowsVersion.h"
#include "nsDeviceContext.h"
#include "nsRenderingContext.h"
@ -42,7 +43,7 @@ using mozilla::IsVistaOrLater;
using namespace mozilla;
using namespace mozilla::widget;
extern PRLogModuleInfo* gWindowsLog;
extern mozilla::LazyLogModule gWindowsLog;
NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeWin, nsNativeTheme, nsITheme)

View File

@ -12,6 +12,7 @@
#include "nsUXThemeData.h"
#include "nsIDOMSimpleGestureEvent.h"
#include "nsIDOMWheelEvent.h"
#include "mozilla/Logging.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/TouchEvents.h"
@ -21,7 +22,7 @@
using namespace mozilla;
using namespace mozilla::widget;
extern PRLogModuleInfo* gWindowsLog;
extern mozilla::LazyLogModule gWindowsLog;
const wchar_t nsWinGesture::kGestureLibraryName[] = L"user32.dll";
HMODULE nsWinGesture::sLibraryHandle = nullptr;

View File

@ -58,6 +58,7 @@
#include "gfxEnv.h"
#include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "mozilla/Logging.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/MouseEvents.h"
@ -453,7 +454,7 @@ StaticAutoPtr<TIPMessageHandler> TIPMessageHandler::sInstance;
static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
extern PRLogModuleInfo* gWindowsLog;
extern mozilla::LazyLogModule gWindowsLog;
// Global used in Show window enumerations.
static bool gWindowsVisible = false;

View File

@ -7,12 +7,13 @@
* nsWindowDbg - Debug related utilities for nsWindow.
*/
#include "mozilla/Logging.h"
#include "nsWindowDbg.h"
#include "WinUtils.h"
using namespace mozilla::widget;
extern PRLogModuleInfo* gWindowsLog;
extern mozilla::LazyLogModule gWindowsLog;
#if defined(POPUP_ROLLUP_DEBUG_OUTPUT)
MSGFEventMsgInfo gMSGFEvents[] = {