Merge m-c to m-i, a=release to defeat a buggy hook

This commit is contained in:
Phil Ringnalda 2015-04-04 11:16:18 -07:00
commit 34d760eb72
155 changed files with 4712 additions and 2679 deletions

View File

@ -166,7 +166,8 @@ ProcessGlobal.prototype = {
let args = message.arguments;
let stackTrace = '';
if (message.level == 'assert' || message.level == 'error' || message.level == 'trace') {
if (message.stacktrace &&
(message.level == 'assert' || message.level == 'error' || message.level == 'trace')) {
stackTrace = Array.map(message.stacktrace, formatStackFrame).join('\n');
} else {
stackTrace = formatStackFrame(message);

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "16383ec2bf3ed46f893b15b3fab2892e9fadc4e7",
"git_revision": "e370e6beecd28785beef8c7ff299cf788693f0cc",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "2b1fea55c45ae4b59eb077840bfe5361ecd48d54",
"revision": "e4abf3a2e6a68bafbeec52cdc2a388ff7b9adf3d",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1b1d86462d3150dceacff927536ded9fcc168419"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="16383ec2bf3ed46f893b15b3fab2892e9fadc4e7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e370e6beecd28785beef8c7ff299cf788693f0cc"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -2982,6 +2982,14 @@
<gfxBlacklistEntry blockID="g511"> <os>WINNT 5.1</os> <vendor>0x8086</vendor> <feature>DIRECT3D_9_LAYERS, WEBGL_ANGLE</feature> <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus> <driverVersion>6.14.10.5218</driverVersion> <driverVersionComparator>LESS_THAN</driverVersionComparator> </gfxBlacklistEntry>
</gfxItems>
<certItems>
<certItem issuerName="MIGQMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDE2MDQGA1UEAxMtQ09NT0RPIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB">
<serialNumber>D9UltDPl4XVfSSqQOvdiwQ==</serialNumber>
</certItem>
<certItem issuerName="MDIxCzAJBgNVBAYTAkNOMQ4wDAYDVQQKEwVDTk5JQzETMBEGA1UEAxMKQ05OSUMgUk9PVA==">
<serialNumber>STMAjg==</serialNumber>
</certItem>
</certItems>
</blocklist>

View File

@ -258,7 +258,7 @@ const gXPInstallObserver = {
label: gNavigatorBundle.getString("addonInstallRestartButton"),
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
callback: function() {
Application.restart();
BrowserUtils.restartApplication();
}
};
}
@ -374,7 +374,7 @@ var LightWeightThemeWebInstaller = {
label: gNavigatorBundle.getString("lwthemeNeedsRestart.button"),
accessKey: gNavigatorBundle.getString("lwthemeNeedsRestart.accesskey"),
callback: function () {
Application.restart();
BrowserUtils.restartApplication();
}
};

View File

@ -104,6 +104,7 @@ let ReadingListUI = {
}
document.getElementById(READINGLIST_COMMAND_ID).setAttribute("hidden", !enabled);
document.getElementById(READINGLIST_COMMAND_ID).setAttribute("disabled", !enabled);
},
/**

View File

@ -149,7 +149,7 @@
sidebarurl="chrome://browser/content/history/history-panel.xul"
oncommand="SidebarUI.toggle('viewHistorySidebar');"/>
<broadcaster id="readingListSidebar" hidden="true" autoCheck="false"
<broadcaster id="readingListSidebar" hidden="true" autoCheck="false" disabled="true"
sidebartitle="&readingList.label;" type="checkbox" group="sidebar"
sidebarurl="chrome://browser/content/readinglist/sidebar.xhtml"
oncommand="SidebarUI.toggle('readingListSidebar');"/>

View File

@ -2558,11 +2558,7 @@ let gMenuButtonUpdateBadge = {
// If the update is successfully applied, or if the updater has fallen back
// to non-staged updates, add a badge to the hamburger menu to indicate an
// update will be applied once the browser restarts.
let badge = document.getAnonymousElementByAttribute(PanelUI.menuButton,
"class",
"toolbarbutton-badge");
badge.style.backgroundColor = '#74BF43';
PanelUI.menuButton.setAttribute("badge", "\u2B06");
PanelUI.menuButton.setAttribute("update-status", "succeeded");
let brandBundle = document.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
@ -2580,6 +2576,7 @@ let gMenuButtonUpdateBadge = {
case STATE_FAILED:
// Background update has failed, let's show the UI responsible for
// prompting the user to update manually.
PanelUI.menuButton.setAttribute("update-status", "failed");
PanelUI.menuButton.setAttribute("badge", "!");
stringId = "appmenu.updateFailed.description";

View File

@ -3924,8 +3924,8 @@
<!-- Deprecated stuff, implemented for backwards compatibility. -->
<method name="enterTabbedMode">
<body>
Application.console.log("enterTabbedMode is an obsolete method and " +
"will be removed in a future release.");
Services.console.logStringMessage("enterTabbedMode is an obsolete method and " +
"will be removed in a future release.");
</body>
</method>
<field name="mTabbedMode" readonly="true">true</field>

View File

@ -68,11 +68,6 @@ ServerClient.prototype = {
},
_removeToken(token) {
// XXX - remove this check once tokencaching landsin FxA.
if (!this.fxa.removeCachedOAuthToken) {
dump("XXX - token caching support is yet to land - can't remove token!");
return;
}
return this.fxa.removeCachedOAuthToken({token});
},

View File

@ -106,9 +106,12 @@ let AnimationsController = {
"setCurrentTime");
this.hasMutationEvents = yield target.actorHasMethod("animations",
"stopAnimationPlayerUpdates");
this.hasSetPlaybackRate = yield target.actorHasMethod("animationplayer",
"setPlaybackRate");
this.onPanelVisibilityChange = this.onPanelVisibilityChange.bind(this);
this.onNewNodeFront = this.onNewNodeFront.bind(this);
this.onAnimationMutations = this.onAnimationMutations.bind(this);
this.startListeners();
@ -151,6 +154,9 @@ let AnimationsController = {
gInspector.selection.off("new-node-front", this.onNewNodeFront);
gInspector.sidebar.off("select", this.onPanelVisibilityChange);
gToolbox.off("select", this.onPanelVisibilityChange);
if (this.isListeningToMutations) {
this.animationsFront.off("mutations", this.onAnimationMutations);
}
},
isPanelVisible: function() {
@ -213,6 +219,34 @@ let AnimationsController = {
this.animationPlayers = yield this.animationsFront.getAnimationPlayersForNode(nodeFront);
this.startAllAutoRefresh();
// Start listening for animation mutations only after the first method call
// otherwise events won't be sent.
if (!this.isListeningToMutations && this.hasMutationEvents) {
this.animationsFront.on("mutations", this.onAnimationMutations);
this.isListeningToMutations = true;
}
}),
onAnimationMutations: Task.async(function*(changes) {
// Insert new players into this.animationPlayers when new animations are
// added.
for (let {type, player} of changes) {
if (type === "added") {
this.animationPlayers.push(player);
player.startAutoRefresh();
}
if (type === "removed") {
player.stopAutoRefresh();
yield player.release();
let index = this.animationPlayers.indexOf(player);
this.animationPlayers.splice(index, 1);
}
}
// Let the UI know the list has been updated.
this.emit(this.PLAYERS_UPDATED_EVENT, this.animationPlayers);
}),
startAllAutoRefresh: function() {

View File

@ -19,7 +19,7 @@
<span class="label">&allAnimations;</span>
<button id="toggle-all" standalone="true" class="devtools-button"></button>
</div>
<div id="players" class="theme-toolbar"></div>
<div id="players"></div>
<div id="error-message">
<p>&invalidElement;</p>
<p>&selectElement;</p>

View File

@ -187,8 +187,12 @@ function PlayerWidget(player, containerEl) {
this.onRewindBtnClick = this.onRewindBtnClick.bind(this);
this.onFastForwardBtnClick = this.onFastForwardBtnClick.bind(this);
this.onCurrentTimeChanged = this.onCurrentTimeChanged.bind(this);
this.onPlaybackRateChanged = this.onPlaybackRateChanged.bind(this);
this.metaDataComponent = new PlayerMetaDataHeader();
if (AnimationsController.hasSetPlaybackRate) {
this.rateComponent = new PlaybackRateSelector();
}
}
PlayerWidget.prototype = {
@ -211,6 +215,9 @@ PlayerWidget.prototype = {
this.stopTimelineAnimation();
this.stopListeners();
this.metaDataComponent.destroy();
if (this.rateComponent) {
this.rateComponent.destroy();
}
this.el.remove();
this.playPauseBtnEl = this.rewindBtnEl = this.fastForwardBtnEl = null;
@ -226,6 +233,9 @@ PlayerWidget.prototype = {
this.fastForwardBtnEl.addEventListener("click", this.onFastForwardBtnClick);
this.currentTimeEl.addEventListener("input", this.onCurrentTimeChanged);
}
if (this.rateComponent) {
this.rateComponent.on("rate-changed", this.onPlaybackRateChanged);
}
},
stopListeners: function() {
@ -236,6 +246,9 @@ PlayerWidget.prototype = {
this.fastForwardBtnEl.removeEventListener("click", this.onFastForwardBtnClick);
this.currentTimeEl.removeEventListener("input", this.onCurrentTimeChanged);
}
if (this.rateComponent) {
this.rateComponent.off("rate-changed", this.onPlaybackRateChanged);
}
},
createMarkup: function() {
@ -247,7 +260,7 @@ PlayerWidget.prototype = {
}
});
this.metaDataComponent.createMarkup(this.el);
this.metaDataComponent.init(this.el);
this.metaDataComponent.render(state);
// Timeline widget.
@ -293,6 +306,11 @@ PlayerWidget.prototype = {
});
}
if (this.rateComponent) {
this.rateComponent.init(playbackControlsEl);
this.rateComponent.render(state);
}
// Sliders container.
let slidersContainerEl = createNode({
parent: timelineEl,
@ -378,19 +396,30 @@ PlayerWidget.prototype = {
this.setCurrentTime(parseFloat(time), true);
},
/**
* Executed when the playback rate dropdown value changes in the playbackrate
* component.
*/
onPlaybackRateChanged: function(e, rate) {
this.setPlaybackRate(rate);
},
/**
* Whenever a player state update is received.
*/
onStateChanged: function() {
let state = this.player.state;
this.updateWidgetState(state);
this.metaDataComponent.render(state);
if (this.rateComponent) {
this.rateComponent.render(state);
}
switch (state.playState) {
case "finished":
this.stopTimelineAnimation();
this.displayTime(this.player.state.duration);
this.stopListeners();
this.displayTime(this.player.state.currentTime);
break;
case "running":
this.startTimelineAnimation();
@ -399,6 +428,10 @@ PlayerWidget.prototype = {
this.stopTimelineAnimation();
this.displayTime(this.player.state.currentTime);
break;
case "idle":
this.stopTimelineAnimation();
this.displayTime(0);
break;
}
},
@ -429,16 +462,25 @@ PlayerWidget.prototype = {
yield this.player.setCurrentTime(time);
}),
/**
* Set the playback rate of the animation.
* @param {Number} rate.
* @return {Promise} Resolves when the rate has been set.
*/
setPlaybackRate: function(rate) {
if (!AnimationsController.hasSetPlaybackRate) {
throw new Error("This server version doesn't support setting animations' playbackRate");
}
return this.player.setPlaybackRate(rate);
},
/**
* Pause the animation player via this widget.
* @return {Promise} Resolves when the player is paused, the button is
* switched to the right state, and the timeline animation is stopped.
*/
pause: function() {
if (this.player.state.playState === "finished") {
return;
}
// Switch to the right className on the element right away to avoid waiting
// for the next state update to change the playPause icon.
this.updateWidgetState({playState: "paused"});
@ -452,10 +494,6 @@ PlayerWidget.prototype = {
* switched to the right state, and the timeline animation is started.
*/
play: function() {
if (this.player.state.playState === "finished") {
return;
}
// Switch to the right className on the element right away to avoid waiting
// for the next state update to change the playPause icon.
this.updateWidgetState({playState: "running"});
@ -479,7 +517,8 @@ PlayerWidget.prototype = {
let start = performance.now();
let loop = () => {
this.rafID = requestAnimationFrame(loop);
let now = state.currentTime + performance.now() - start;
let delta = (performance.now() - start) * state.playbackRate;
let now = state.currentTime + delta;
this.displayTime(now);
};
@ -540,7 +579,7 @@ function PlayerMetaDataHeader() {
}
PlayerMetaDataHeader.prototype = {
createMarkup: function(containerEl) {
init: function(containerEl) {
// The main title element.
this.el = createNode({
parent: containerEl,
@ -683,6 +722,87 @@ PlayerMetaDataHeader.prototype = {
}
};
/**
* UI component responsible for displaying the playback rate drop-down in each
* player widget, updating it when the state changes, and emitting events when
* the user selects a new value.
* The parent UI component for this should drive its updates by calling
* render(state) whenever it wants the component to update.
*/
function PlaybackRateSelector() {
this.currentRate = null;
this.onSelectionChanged = this.onSelectionChanged.bind(this);
EventEmitter.decorate(this);
}
PlaybackRateSelector.prototype = {
PRESETS: [.1, .5, 1, 2, 5, 10],
init: function(containerEl) {
// This component is simple enough that we can re-create the markup every
// time it's rendered. So here we only store the parentEl.
this.parentEl = containerEl;
},
destroy: function() {
this.removeSelect();
this.parentEl = this.el = null;
},
removeSelect: function() {
if (this.el) {
this.el.removeEventListener("change", this.onSelectionChanged);
this.el.remove();
}
},
/**
* Get the ordered list of presets, including the current playbackRate if
* different from the existing presets.
*/
getCurrentPresets: function({playbackRate}) {
return [...new Set([...this.PRESETS, playbackRate])].sort((a,b) => a > b);
},
render: function(state) {
if (state.playbackRate === this.currentRate) {
return;
}
this.removeSelect();
this.el = createNode({
parent: this.parentEl,
nodeType: "select",
attributes: {
"class": "rate devtools-button"
}
});
for (let preset of this.getCurrentPresets(state)) {
let option = createNode({
parent: this.el,
nodeType: "option",
attributes: {
value: preset,
}
});
option.textContent = L10N.getFormatStr("player.playbackRateLabel", preset);
if (preset === state.playbackRate) {
option.setAttribute("selected", "");
}
}
this.el.addEventListener("change", this.onSelectionChanged);
this.currentRate = state.playbackRate;
},
onSelectionChanged: function(e) {
this.emit("rate-changed", parseFloat(this.el.value));
}
};
/**
* DOM node creation helper function.
* @param {Object} Options to customize the node to be created.

View File

@ -18,9 +18,13 @@ support-files =
[browser_animation_playerWidgets_have_control_buttons.js]
[browser_animation_playerWidgets_meta_data.js]
[browser_animation_playerWidgets_state_after_pause.js]
[browser_animation_rate_select_shows_presets.js]
[browser_animation_refresh_on_added_animation.js]
[browser_animation_refresh_on_removed_animation.js]
[browser_animation_refresh_when_active.js]
[browser_animation_same_nb_of_playerWidgets_and_playerFronts.js]
[browser_animation_setting_currentTime_works_and_pauses.js]
[browser_animation_setting_playbackRate_works.js]
[browser_animation_shows_player_on_valid_node.js]
[browser_animation_timeline_animates.js]
[browser_animation_timeline_is_enabled.js]
@ -31,4 +35,5 @@ support-files =
[browser_animation_toolbar_exists.js]
[browser_animation_ui_updates_when_animation_changes.js]
[browser_animation_ui_updates_when_animation_data_changes.js]
[browser_animation_ui_updates_when_animation_rate_changes.js]
[browser_animation_ui_updates_when_animation_time_changes.js]

View File

@ -25,15 +25,7 @@ add_task(function*() {
info("Wait for both animations to end");
let promises = controller.animationPlayers.map(front => {
let def = promise.defer();
let onStateChanged = () => {
if (front.state.playState === "finished") {
front.off(front.AUTO_REFRESH_EVENT, onStateChanged);
def.resolve();
}
};
front.on(front.AUTO_REFRESH_EVENT, onStateChanged);
return def.promise;
return waitForPlayState(front, "finished");
});
yield promise.all(promises);

View File

@ -28,15 +28,7 @@ add_task(function*() {
let widget = panel.playerWidgets[0];
let front = widget.player;
let def = promise.defer();
let onStateChanged = () => {
if (front.state.playState === "finished") {
front.off(front.AUTO_REFRESH_EVENT, onStateChanged);
def.resolve();
}
};
front.on(front.AUTO_REFRESH_EVENT, onStateChanged);
yield def.promise;
yield waitForPlayState(front, "finished");
is(widget.currentTimeEl.value, front.state.duration,
"The timeline slider has the right value");

View File

@ -25,6 +25,8 @@ add_task(function*() {
"The second button is the rewind button");
ok(container.children[2].classList.contains("ff"),
"The third button is the fast-forward button");
ok(container.querySelector("select"),
"The container contains the playback rate select");
info("Faking an older server version by setting " +
"AnimationsController.hasSetCurrentTime to false");
@ -46,4 +48,23 @@ add_task(function*() {
yield selectNode("body", inspector);
controller.hasSetCurrentTime = true;
info("Faking an older server version by setting " +
"AnimationsController.hasSetPlaybackRate to false");
yield selectNode("body", inspector);
controller.hasSetPlaybackRate = false;
info("Selecting the animated node again");
yield selectNode(".animated", inspector);
widget = panel.playerWidgets[0];
container = widget.el.querySelector(".playback-controls");
ok(container, "The control buttons container still exists");
ok(!container.querySelector("select"),
"The playback rate select does not exist");
yield selectNode("body", inspector);
controller.hasSetPlaybackRate = true;
});

View File

@ -0,0 +1,49 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the playbackRate select element contains a list of presets and
// and that if the animation has a current rate that is not part of this list,
// it is added.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {inspector, panel} = yield openAnimationInspector();
info("Selecting the test node");
yield selectNode(".animated", inspector);
info("Get the playback rate UI component");
let widget = panel.playerWidgets[0];
let rateComponent = widget.rateComponent;
let options = rateComponent.el.querySelectorAll("option");
is(options.length, rateComponent.PRESETS.length,
"The playback rate select contains the right number of options");
for (let i = 0; i < rateComponent.PRESETS.length; i ++) {
is(options[i].value, rateComponent.PRESETS[i] + "",
"The playback rate option " + i + " has the right preset value " +
rateComponent.PRESETS[i]);
}
info("Set a custom rate (not part of the presets) via the DOM");
let onRateChanged = waitForStateCondition(widget.player, state => {
return state.playbackRate === 3.6
});
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
selector: ".animated",
animationIndex: 0,
playbackRate: 3.6
});
yield onRateChanged;
options = rateComponent.el.querySelectorAll("option");
is(options.length, rateComponent.PRESETS.length + 1,
"The playback rate select contains the right number of options (presets + 1)");
ok([...options].find(option => option.value === "3.6"),
"The custom rate is part of the select");
});

View File

@ -0,0 +1,34 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the panel content refreshes when new animations are added.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {toolbox, inspector, panel} = yield openAnimationInspector();
info("Select a non animated node");
yield selectNode(".still", inspector);
is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
"There are no player widgets in the panel");
info("Listen to the next UI update event");
let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
info("Start an animation on the node");
yield executeInContent("devtools:test:setAttribute", {
selector: ".still",
attributeName: "class",
attributeValue: "ball animated"
});
yield onPanelUpdated;
ok(true, "The panel update event was fired");
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
"There is one player widget in the panel");
});

View File

@ -0,0 +1,62 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the panel content refreshes when animations are removed.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {toolbox, inspector, panel} = yield openAnimationInspector();
info("Select a animated node");
yield selectNode(".animated", inspector);
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
"There is one player widget in the panel");
info("Listen to the next UI update event");
let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
info("Remove the animation on the node by removing the class");
yield executeInContent("devtools:test:setAttribute", {
selector: ".animated",
attributeName: "class",
attributeValue: "ball still test-node"
});
yield onPanelUpdated;
ok(true, "The panel update event was fired");
is(panel.playersEl.querySelectorAll(".player-widget").length, 0,
"There are no player widgets in the panel anymore");
info("Add an finite animation on the node again, and wait for it to appear");
onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
yield executeInContent("devtools:test:setAttribute", {
selector: ".test-node",
attributeName: "class",
attributeValue: "ball short"
});
yield onPanelUpdated;
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
"There is one player widget in the panel again");
info("Now wait until the animation finishes");
let widget = panel.playerWidgets[0];
yield waitForPlayState(widget.player, "finished")
is(panel.playersEl.querySelectorAll(".player-widget").length, 1,
"There is still a player widget in the panel after the animation finished");
info("Checking that the animation's currentTime can still be set");
info("Click at the center of the slider input");
let onPaused = waitForPlayState(widget.player, "paused");
let input = widget.currentTimeEl;
let win = input.ownerDocument.defaultView;
EventUtils.synthesizeMouseAtCenter(input, {type: "mousedown"}, win);
yield onPaused;
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
});

View File

@ -41,23 +41,3 @@ add_task(function*() {
yield checkPausedAt(widget, 2000);
});
function* checkPausedAt(widget, time) {
info("Wait for the next auto-update");
let onPaused = promise.defer();
widget.player.on(widget.player.AUTO_REFRESH_EVENT, function onRefresh() {
info("Still waiting for the player to pause");
if (widget.player.state.playState === "paused") {
ok(true, "The player's playState is paused");
widget.player.off(widget.player.AUTO_REFRESH_EVENT, onRefresh);
onPaused.resolve();
}
});
yield onPaused.promise;
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
is(widget.player.state.currentTime, time,
"The player front's currentTime was set to " + time);
is(widget.currentTimeEl.value, time, "The input's value was set to " + time);
}

View File

@ -0,0 +1,34 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that setting an animation's playback rate by selecting a rate in the
// presets drop-down sets the rate accordingly.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {toolbox, inspector, panel} = yield openAnimationInspector();
info("Select an animated node");
yield selectNode(".animated", inspector);
info("Get the player widget for this node");
let widget = panel.playerWidgets[0];
let select = widget.rateComponent.el;
let win = select.ownerDocument.defaultView;
info("Click on the rate drop-down");
EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"}, win);
info("Click on a rate option");
let option = select.options[select.options.length - 1];
EventUtils.synthesizeMouseAtCenter(option, {type: "mouseup"}, win);
let selectedRate = parseFloat(option.value);
info("Check that the rate was changed on the player at the next update");
yield waitForStateCondition(widget.player, ({playbackRate}) => playbackRate === selectedRate);
is(widget.player.state.playbackRate, selectedRate,
"The rate was changed successfully");
});

View File

@ -14,22 +14,25 @@ add_task(function*() {
info("Select an animated node");
yield selectNode(".animated", inspector);
let widget = panel.playerWidgets[0];
let player = widget.player;
info("Click the toggle button to pause all animations");
let onRefresh = onceNextPlayerRefresh(widget.player);
info("Listen to animation state changes and click the toggle button to " +
"pause all animations");
let onPaused = waitForPlayState(player, "paused");
yield panel.toggleAll();
yield onRefresh;
yield onPaused;
info("Checking the selected node's animation player widget's state");
is(widget.player.state.playState, "paused", "The player front's state is paused");
is(player.state.playState, "paused", "The player front's state is paused");
ok(widget.el.classList.contains("paused"), "The widget's UI is in paused state");
info("Click the toggle button to play all animations");
onRefresh = onceNextPlayerRefresh(widget.player);
info("Listen to animation state changes and click the toggle button to " +
"play all animations");
let onRunning = waitForPlayState(player, "running");
yield panel.toggleAll();
yield onRefresh;
yield onRunning;
info("Checking the selected node's animation player widget's state again");
is(widget.player.state.playState, "running", "The player front's state is running");
is(player.state.playState, "running", "The player front's state is running");
ok(widget.el.classList.contains("running"), "The widget's UI is in running state");
});

View File

@ -16,6 +16,10 @@ add_task(function*() {
info("Get the player widget");
let widget = panel.playerWidgets[0];
let player = widget.player;
info("Wait for paused playState");
let onPaused = waitForPlayState(player, "paused");
info("Pause the animation via the content DOM");
yield executeInContent("Test:ToggleAnimationPlayer", {
@ -24,13 +28,15 @@ add_task(function*() {
pause: true
});
info("Wait for the next state update");
yield onceNextPlayerRefresh(widget.player);
yield onPaused;
is(widget.player.state.playState, "paused", "The AnimationPlayerFront is paused");
is(player.state.playState, "paused", "The AnimationPlayerFront is paused");
ok(widget.el.classList.contains("paused"), "The button's state has changed");
ok(!widget.rafID, "The smooth timeline animation has been stopped");
info("Wait for running playState");
let onRunning = waitForPlayState(player, "running");
info("Play the animation via the content DOM");
yield executeInContent("Test:ToggleAnimationPlayer", {
selector: ".animated",
@ -38,10 +44,9 @@ add_task(function*() {
pause: false
});
info("Wait for the next state update");
yield onceNextPlayerRefresh(widget.player);
yield onRunning;
is(widget.player.state.playState, "running", "The AnimationPlayerFront is running");
is(player.state.playState, "running", "The AnimationPlayerFront is running");
ok(widget.el.classList.contains("running"), "The button's state has changed");
ok(widget.rafID, "The smooth timeline animation has been started");
});

View File

@ -0,0 +1,47 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that setting an animation's playbackRate via the WebAnimations API (from
// content), actually changes the rate in the corresponding widget too.
add_task(function*() {
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
let {inspector, panel} = yield openAnimationInspector();
info("Selecting the test node");
yield selectNode(".animated", inspector);
info("Get the player widget");
let widget = panel.playerWidgets[0];
info("Change the animation's playbackRate via the content DOM");
let onRateChanged = waitForStateCondition(widget.player, state => {
return state.playbackRate === 2;
}, "playbackRate === 2");
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
selector: ".animated",
animationIndex: 0,
playbackRate: 2
});
yield onRateChanged;
is(widget.rateComponent.el.value, "2",
"The playbackRate select value was changed");
info("Change the animation's playbackRate again via the content DOM");
onRateChanged = waitForStateCondition(widget.player, state => {
return state.playbackRate === 0.3;
}, "playbackRate === 0.3");
yield executeInContent("Test:SetAnimationPlayerPlaybackRate", {
selector: ".animated",
animationIndex: 0,
playbackRate: 0.3
});
yield onRateChanged;
is(widget.rateComponent.el.value, "0.3",
"The playbackRate select value was changed again");
});

View File

@ -52,6 +52,27 @@ addMessageListener("Test:SetAnimationPlayerCurrentTime", function(msg) {
sendAsyncMessage("Test:SetAnimationPlayerCurrentTime");
});
/**
* Change the playbackRate of one of the animation players of a given node.
* @param {Object} data
* - {String} selector The CSS selector to get the node (can be a "super"
* selector).
* - {Number} animationIndex The index of the node's animationPlayers to change.
* - {Number} playbackRate The rate to set.
*/
addMessageListener("Test:SetAnimationPlayerPlaybackRate", function(msg) {
let {selector, animationIndex, playbackRate} = msg.data;
let node = superQuerySelector(selector);
if (!node) {
return;
}
let player = node.getAnimations()[animationIndex];
player.playbackRate = playbackRate;
sendAsyncMessage("Test:SetAnimationPlayerPlaybackRate");
});
/**
* Get the current playState of an animation player on a given node.
* @param {Object} data

View File

@ -284,10 +284,8 @@ let togglePlayPauseButton = Task.async(function*(widget) {
yield onClicked;
// Wait for the next sate change event to make sure the state is updated
yield waitForStateCondition(widget.player, state => {
return state.playState === nextState;
}, "after clicking the toggle button");
// Wait until the state changes.
yield waitForPlayState(widget.player, nextState);
});
/**
@ -317,6 +315,37 @@ let waitForStateCondition = Task.async(function*(player, conditionCheck, desc=""
return def.promise;
});
/**
* Wait for a player's auto-refresh events and stop when the playState is the
* provided string.
* @param {AnimationPlayerFront} player
* @param {String} playState The playState to expect.
* @return {Promise} Resolves when the playState has changed to the expected value.
*/
function waitForPlayState(player, playState) {
return waitForStateCondition(player, state => {
return state.playState === playState;
}, "Waiting for animation to be " + playState);
}
/**
* Wait for the player's auto-refresh events until the animation is paused.
* When done, check its currentTime.
* @param {PlayerWidget} widget.
* @param {Numer} time.
* @return {Promise} Resolves when the animation is paused and tests have ran.
*/
let checkPausedAt = Task.async(function*(widget, time) {
info("Wait for the next auto-refresh");
yield waitForPlayState(widget.player, "paused");
ok(widget.el.classList.contains("paused"), "The widget is in paused mode");
is(widget.player.state.currentTime, time,
"The player front's currentTime was set to " + time);
is(widget.currentTimeEl.value, time, "The input's value was set to " + time);
});
/**
* Get the current playState of an animation player on a given node.
*/

View File

@ -83,7 +83,7 @@ function testSetBreakpointBlankLine() {
ok(!aResponse.error,
"Should be able to set a breakpoint in a coffee source file on a blank line.");
ok(aResponse.actualLocation,
"Because 3 is empty, we should have an actualLocation.");
"Because 7 is empty, we should have an actualLocation.");
is(aResponse.actualLocation.source.url, COFFEE_URL,
"actualLocation.actor should be source mapped to the coffee file.");
is(aResponse.actualLocation.line, 8,

View File

@ -8,5 +8,5 @@ support-files =
templates.json
[browser_tabs.js]
skip-if = os == 'win' || e10s # Bug 1149289 - Intermittent on Windows, Bug 1072167 - browser_tabs.js test fails under e10s
skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s
[browser_widget.js]

View File

@ -28,6 +28,9 @@ function test() {
yield selectTabProject(win);
ok(win.UI.toolboxPromise, "Toolbox promise exists");
yield win.UI.toolboxPromise;
let project = win.AppManager.selectedProject;
is(project.location, TEST_URI, "Location is correct");
is(project.name, "example.com: Test Tab", "Name is correct");
@ -61,6 +64,8 @@ function selectTabProject(win) {
yield waitForUpdate(win, "runtime-targets");
let tabsNode = win.document.querySelector("#project-panel-tabs");
let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
let project = waitForUpdate(win, "project");
tabNode.click();
yield project;
});
}

View File

@ -6,6 +6,8 @@ const Ci = Components.interfaces;
const Cc = Components.classes;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
"resource://gre/modules/Deprecated.jsm");
const APPLICATION_CID = Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66");
const APPLICATION_CONTRACTID = "@mozilla.org/fuel/application;1";
@ -734,6 +736,9 @@ var ApplicationFactory = {
//=================================================
// Application constructor
function Application() {
Deprecated.warning("FUEL is deprecated, you should use the add-on SDK instead.",
"https://developer.mozilla.org/Add-ons/SDK/");
this.initToolkitHelpers();
}

View File

@ -46,3 +46,9 @@ player.infiniteIterationCount=&#8734;
# how long (in seconds) the animation lasts, or what is the animation's current
# time (in seconds too);
player.timeLabel=%Ss
# LOCALIZATION NOTE (player.playbackRateLabel):
# This string is displayed in each animation player widget, as the label of
# drop-down list items that can be used to change the rate at which the
# animation runs (1x being the default, 2x being twice as fast).
player.playbackRateLabel=%Sx

View File

@ -1132,26 +1132,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
margin-top: 5px;
}
.popup-notification-icon {
width: 64px;
height: 64px;
-moz-margin-end: 10px;
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
%include ../shared/notification-icons.inc.css
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
@ -1163,92 +1144,13 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
font-weight: bold;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}
.popup-notification-icon[popupid="password"] {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
}
.popup-notification-icon[popupid="webapps-install-progress"],
.popup-notification-icon[popupid="webapps-install"] {
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
}
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
}
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
}
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
}
/* Notification icon box */
#notification-popup-box {
position: relative;
background-color: #fff;
background-clip: padding-box;
padding-left: 3px;
border-radius: 2.5px 0 0 2.5px;
border-width: 0 8px 0 0;
border-style: solid;
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
-moz-margin-end: -8px;
margin-top: -1px;
margin-bottom: -1px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
padding-left: 7px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
#notification-popup-box:-moz-locale-dir(rtl),
.notification-anchor-icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.notification-anchor-icon {
width: 16px;
height: 16px;
margin: 0 2px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
}
@ -1258,123 +1160,11 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
list-style-image: url(moz-icon://stock/gtk-dialog-info?size=16);
}
.identity-notification-icon,
#identity-notification-icon {
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
}
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(moz-icon://stock/gtk-dialog-question?size=16);
}
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
}
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
}
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
#notification-popup-box[hidden] {
/* Override display:none to make the pluginBlockedNotification animation work
when showing the notification repeatedly. */
display: -moz-box;
visibility: collapse;
}
#plugins-notification-icon.plugin-blocked[showing] {
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
}
@keyframes pluginBlockedNotification {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.bad-content-blocked-notification-icon,
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
}
.bad-content-unblocked-notification-icon,
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
}
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
}
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
}
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
}
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
}
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
}
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
}
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16.png);
}
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
}
#pointerLock-cancel {
margin: 0px;
}
@ -1453,18 +1243,6 @@ notification[value="translation"] menulist > .menulist-dropmarker {
display: block;
}
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
/* Loop/ Hello browser styles */
notification[value="loop-sharing-notification"] .button-menubutton-button {
@ -2106,12 +1884,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
/* Social toolbar item */
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
#social-undoactivation-button {
-moz-margin-start: 0; /* override default label margin to match description margin */
}
@ -2188,28 +1960,6 @@ chatbox {
border-top-right-radius: 2.5px;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
#eme-notification-icon[firstplay=true] {
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
}
@keyframes emeTeachingMoment {
0% {transform: translateX(0); }
25% {transform: translateX(3px) }
75% {transform: translateX(-3px) }
100% { transform: translateX(0); }
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css

View File

@ -86,6 +86,7 @@ browser.jar:
skin/classic/browser/Toolbar-inverted.png
skin/classic/browser/Toolbar-small.png
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/session-restore.svg (../shared/incontent-icons/session-restore.svg)
skin/classic/browser/tab-crashed.svg (../shared/incontent-icons/tab-crashed.svg)

View File

@ -3657,37 +3657,10 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
margin-top: 5px;
}
%include ../shared/notification-icons.inc.css
#notification-popup-box {
position: relative;
background-color: #fff;
background-clip: padding-box;
padding-left: 3px;
border-radius: 2px 0 0 2px;
border-width: 0 8px 0 0;
border-style: solid;
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
-moz-margin-end: -8px;
}
@media (min-resolution: 2dppx) {
#notification-popup-box {
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
}
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
padding-left: 7px;
}
#notification-popup-box:-moz-locale-dir(rtl),
.notification-anchor-icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.notification-anchor-icon {
width: 16px;
height: 16px;
margin: 0 2px;
}
.notification-anchor-icon:-moz-focusring {
@ -3699,278 +3672,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
height: 16px;
}
.default-notification-icon,
#default-notification-icon {
list-style-image: url(chrome://global/skin/icons/information-16.png);
}
@media (min-resolution: 2dppx) {
.default-notification-icon,
#default-notification-icon {
list-style-image: url(chrome://global/skin/icons/information-32.png);
}
}
.identity-notification-icon,
#identity-notification-icon {
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
}
/* XXX: need HiDPI version */
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}
@media (min-resolution: 2dppx) {
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
}
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-16.png);
}
@media (min-resolution: 2dppx) {
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-32.png);
}
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
}
@media (min-resolution: 2dppx) {
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
}
}
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
}
@media (min-resolution: 2dppx) {
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16@2x.png);
}
}
.webapps-notification-icon,
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
}
@media (min-resolution: 2dppx) {
.webapps-notification-icon,
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16@2x.png);
}
}
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
@media (min-resolution: 2dppx) {
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 32px, 32px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 64px, 32px, 32px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 96px, 32px, 64px);
}
}
#notification-popup-box[hidden] {
/* Override display:none to make the pluginBlockedNotification animation work
when showing the notification repeatedly. */
display: -moz-box;
visibility: collapse;
}
#plugins-notification-icon.plugin-blocked[showing] {
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
}
@keyframes pluginBlockedNotification {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
}
@media (min-resolution: 2dppx) {
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
}
}
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
}
@media (min-resolution: 2dppx) {
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
}
}
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16@2x.png);
}
}
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16@2x.png);
}
}
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16@2x.png);
}
}
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16@2x.png);
}
}
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16@2x.png);
}
}
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
}
@media (min-resolution: 2dppx) {
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16@2x.png);
}
}
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16.png);
}
@media (min-resolution: 2dppx) {
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16@2x.png);
}
}
.pointerLock-notification-icon,
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
}
@media (min-resolution: 2dppx) {
.pointerLock-notification-icon,
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
}
}
/* Translation */
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
@media (min-resolution: 2dppx) {
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
-moz-image-region: rect(0px, 32px, 32px, 0px);
}
}
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
@media (min-resolution: 2dppx) {
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
-moz-image-region: rect(0px, 64px, 32px, 32px);
}
}
%include ../shared/translation/infobar.inc.css
notification[value="translation"] {
@ -4123,42 +3826,6 @@ notification[value="loop-sharing-notification"] .messageImage {
}
}
.popup-notification-icon {
width: 64px;
height: 64px;
-moz-margin-end: 10px;
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
}
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
}
}
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
width: 27em;
@ -4177,91 +3844,10 @@ notification[value="loop-sharing-notification"] .messageImage {
-moz-margin-start: 0 !important; /* override default label margin to match description margin */
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}
.popup-notification-icon[popupid="password"] {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
}
.popup-notification-icon[popupid="webapps-install-progress"],
.popup-notification-icon[popupid="webapps-install"] {
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
}
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
}
}
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
}
}
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
}
}
#pointerLock-cancel {
margin: 0px;
}
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png);
}
}
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64@2x.png);
}
}
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64@2x.png);
}
}
/* Popup Buttons */
#identity-popup-more-info-button {
@hudButton@
@ -4482,22 +4068,6 @@ notification[value="loop-sharing-notification"] .messageImage {
border-radius: 1px;
}
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
@media (min-resolution: 2dppx) {
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
}
}
#social-undoactivation-button {
-moz-margin-start: 0; /* override default label margin to match description margin */
}
@ -4619,28 +4189,6 @@ window > chatbox {
border-bottom-right-radius: @toolbarbuttonCornerRadius@;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
#eme-notification-icon[firstplay=true] {
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
}
@keyframes emeTeachingMoment {
0% {transform: translateX(0); }
25% {transform: translateX(3px) }
75% {transform: translateX(-3px) }
100% { transform: translateX(0); }
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css

View File

@ -131,6 +131,7 @@ browser.jar:
skin/classic/browser/toolbarbutton-dropmarker.png
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
skin/classic/browser/undoCloseTab@2x.png (../shared/undoCloseTab@2x.png)
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
skin/classic/browser/urlbar-history-dropmarker.png
skin/classic/browser/urlbar-history-dropmarker@2x.png
skin/classic/browser/urlbar-arrow.png

View File

@ -106,6 +106,12 @@
background-position: 100% 0, calc(100% - 1px) 0, calc(100% - 2px) 0;
}
#PanelUI-menu-button[update-status="succeeded"] .toolbarbutton-badge::after {
content: url(chrome://browser/skin/update-badge.svg);
background-color: #74BF43;
height: 10px;
}
.panel-subviews {
padding: 4px;
background-clip: padding-box;

View File

@ -28,7 +28,7 @@ body {
}
#toggle-all {
border-width: 0px 1px;
border-width: 0 0 0 1px;
min-height: 20px;
}
@ -99,13 +99,6 @@ body {
}
}
/* Disabled playerWidget when the animation has ended */
.finished {
pointer-events: none;
opacity: .5;
}
/* Animation title gutter, contains the name, duration, iteration */
.animation-title {
@ -182,6 +175,12 @@ body {
}
}
.timeline .rate {
-moz-appearance: none;
text-align: center;
border-right: 1px solid var(--theme-splitter-color);
}
/* Slider (input type range) container */
.timeline .sliders-container {

View File

@ -0,0 +1,439 @@
%if 0
/* 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/. */
%endif
.popup-notification-icon {
width: 64px;
height: 64px;
-moz-margin-end: 10px;
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}
.popup-notification-icon[popupid="password"] {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
}
.popup-notification-icon[popupid="webapps-install-progress"],
.popup-notification-icon[popupid="webapps-install"] {
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
}
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
}
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
}
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
}
/* Notification icon box */
#notification-popup-box {
position: relative;
background-color: #fff;
background-clip: padding-box;
padding-left: 3px;
border-width: 0 8px 0 0;
border-style: solid;
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
-moz-margin-end: -8px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
padding-left: 7px;
}
#notification-popup-box:-moz-locale-dir(rtl),
.notification-anchor-icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.notification-anchor-icon {
width: 16px;
height: 16px;
margin: 0 2px;
}
.default-notification-icon,
#default-notification-icon {
list-style-image: url(chrome://global/skin/icons/information-16.png);
}
.identity-notification-icon,
#identity-notification-icon {
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
/* XXX: need HiDPI version */
}
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-16.png);
}
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
}
.webapps-notification-icon,
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
}
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
#notification-popup-box[hidden] {
/* Override display:none to make the pluginBlockedNotification animation work
when showing the notification repeatedly. */
display: -moz-box;
visibility: collapse;
}
#plugins-notification-icon.plugin-blocked[showing] {
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
}
@keyframes pluginBlockedNotification {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.bad-content-blocked-notification-icon,
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
}
.bad-content-unblocked-notification-icon,
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
}
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
}
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
}
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
}
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
}
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
}
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
}
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16.png);
}
.pointerLock-notification-icon,
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
}
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
#eme-notification-icon[firstplay=true] {
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
}
@keyframes emeTeachingMoment {
0% {transform: translateX(0); }
25% {transform: translateX(3px) }
75% {transform: translateX(-3px) }
100% { transform: translateX(0); }
}
%ifdef XP_MACOSX
/* HiDPI notification icons */
@media (min-resolution: 2dppx) {
#notification-popup-box {
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
}
.default-notification-icon,
#default-notification-icon {
list-style-image: url(chrome://global/skin/icons/information-32.png);
}
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-32.png);
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
}
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16@2x.png);
}
.webapps-notification-icon,
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16@2x.png);
}
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 32px, 32px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 64px, 32px, 32px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 96px, 32px, 64px);
}
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
}
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
}
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16@2x.png);
}
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16@2x.png);
}
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16@2x.png);
}
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16@2x.png);
}
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16@2x.png);
}
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16@2x.png);
}
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16@2x.png);
}
.pointerLock-notification-icon,
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
}
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
-moz-image-region: rect(0px, 32px, 32px, 0px);
}
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
-moz-image-region: rect(0px, 64px, 32px, 32px);
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
}
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
}
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
}
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
}
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png);
}
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64@2x.png);
}
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64@2x.png);
}
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
}
}
%endif

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10px" height="10px">
<polygon points="4,9 4,5 2,5 5,1 8,5 6,5 6,9" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 138 B

View File

@ -2,15 +2,9 @@
* 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/. */
%define WINDOWS_AERO
%include browser.css
%undef WINDOWS_AERO
%define glassActiveBorderColor rgb(37, 44, 51)
%define glassInactiveBorderColor rgb(102, 102, 102)
%include downloads/indicator-aero.css
@media not all and (-moz-windows-classic) {
#main-window[sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar {
margin-top: 1px;

View File

@ -112,10 +112,8 @@
transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
}
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-compositor),
not all and (-moz-windows-default-theme) {
%endif
#main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar:not(:-moz-lwtheme),
#main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
color: CaptionText;
@ -129,13 +127,9 @@
#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
color: inherit;
}
%ifdef WINDOWS_AERO
}
%endif
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-compositor) {
%endif
#main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
visibility: hidden;
}
@ -144,9 +138,7 @@
-moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
visibility: visible;
}
%ifdef WINDOWS_AERO
}
%endif
/**
* In the classic themes, the titlebar has a horizontal gradient, which is
@ -313,15 +305,11 @@
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
}
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-compositor) {
%endif
#TabsToolbar[collapsed="true"] + #nav-bar {
border-top-style: none !important;
}
%ifdef WINDOWS_AERO
}
%endif
#personal-bookmarks {
min-height: 24px;
@ -335,13 +323,11 @@
background-color: -moz-dialog;
}
%ifndef WINDOWS_AERO
@media (-moz-windows-default-theme) {
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
#main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar {
margin-top: 4px;
}
}
%endif
/* ::::: titlebar ::::: */
@ -370,11 +356,13 @@
}
.titlebar-placeholder[type="caption-buttons"] {
%ifdef WINDOWS_AERO
margin-left: 22px; /* additional space for Aero Snap */
%else
margin-left: 10px;
%endif
margin-left: 22px; /* space needed for Aero Snap */
}
@media (-moz-os-version: windows-xp) {
.titlebar-placeholder[type="caption-buttons"] {
margin-left: 10px; /* less space needed on XP because there's no Aero Snap */
}
}
/* titlebar command buttons */
@ -589,7 +577,6 @@ menuitem.bookmark-item {
%include ../shared/toolbarbuttons.inc.css
%include ../shared/menupanel.inc.css
%ifndef WINDOWS_AERO
@media (-moz-windows-theme: luna-silver) {
:-moz-any(@primaryToolbarButtons@),
#bookmarks-menu-button.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
@ -600,7 +587,6 @@ menuitem.bookmark-item {
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
}
}
%endif
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
@ -682,10 +668,9 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
transition-duration: 150ms;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
/* < Win8 */
:root {
--toolbarbutton-hover-background: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
@ -723,9 +708,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
transition-property: background-color, border-color, box-shadow;
transition-duration: 150ms;
}
%ifdef WINDOWS_AERO
}
%endif
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
@ -803,10 +786,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
box-shadow: var(--toolbarbutton-hover-boxshadow);
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
/* < Win8 */
#nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before {
@ -834,9 +816,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
box-shadow: 0 0 1px hsla(210,54%,20%,.03),
0 0 2px hsla(210,54%,20%,.1);
}
%ifdef WINDOWS_AERO
}
%endif
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
@ -850,10 +830,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
transition-duration: 10ms;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
/* < Win8 */
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
@ -873,9 +852,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
background-color: var(--toolbarbutton-checkedhover-backgroundcolor);
transition: background-color .4s;
}
%ifdef WINDOWS_AERO
}
%endif
#TabsToolbar .toolbarbutton-1,
#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
@ -984,10 +961,9 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
0 1px 0 0 hsla(210,80%,20%,.1) inset !important;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
#back-button > .toolbarbutton-icon {
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important;
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
@ -1020,9 +996,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
0 1px 0 hsla(210,54%,20%,.65) !important;
transition: none;
}
%ifdef WINDOWS_AERO
}
%endif
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
@ -1140,18 +1114,14 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
border: 1px solid ThreeDShadow;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
/* < Win8 */
#urlbar,
.searchbar-textbox {
border-radius: 2px;
}
%ifdef WINDOWS_AERO
}
%endif
#urlbar {
-moz-padding-end: 2px;
@ -1421,17 +1391,14 @@ richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-si
height: 16px;
}
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-default-theme) {
%endif
@media (-moz-os-version: windows-xp),
not all and (-moz-windows-default-theme) {
.ac-result-type-keyword[selected="true"],
.autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected),
richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-title-box > .ac-site-icon {
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
}
%ifdef WINDOWS_AERO
}
%endif
.ac-result-type-tag,
.autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
@ -1454,14 +1421,12 @@ richlistitem[type~="action"][actiontype="searchengine"] > .ac-title-box > .ac-si
color: -moz-nativehyperlinktext;
}
%ifndef WINDOWS_AERO
@media (-moz-windows-default-theme) {
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
.ac-url-text:not([selected="true"]),
.ac-action-text:not([selected="true"]) {
color: #008800;
}
}
%endif
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
@ -1469,9 +1434,8 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
padding: 0 3px;
}
%ifdef WINDOWS_AERO
@media not all and (-moz-windows-default-theme) {
%endif
@media (-moz-os-version: windows-xp),
not all and (-moz-windows-default-theme) {
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(11px, 16px, 22px, 0);
}
@ -1481,9 +1445,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
.ac-action-text[selected="true"] {
color: inherit !important;
}
%ifdef WINDOWS_AERO
}
%endif
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
color: GrayText;
@ -1808,14 +1770,12 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
margin-bottom: calc(-1 * var(--tab-toolbar-navbar-overlap)); /* overlap the nav-bar's top border */
}
%ifndef WINDOWS_AERO
@media (-moz-windows-default-theme) {
@media (-moz-os-version: windows-xp) and (-moz-windows-default-theme) {
#main-window[sizemode=normal] #TabsToolbar {
padding-left: 2px;
padding-right: 2px;
}
}
%endif
%include ../shared/tabs.inc.css
@ -1852,7 +1812,6 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
}
}
%ifndef WINDOWS_AERO
/* Use lighter colors of buttons and text in the titlebar on luna-blue */
@media (-moz-windows-theme: luna-blue) {
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
@ -1861,7 +1820,6 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png");
}
}
%endif
#TabsToolbar[brighttext] .tab-close-button:not(:hover):not([visuallyselected="true"]) {
-moz-image-region: rect(0, 64px, 16px, 48px) !important;
@ -2146,26 +2104,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
margin-top: 5px;
}
.popup-notification-icon {
width: 64px;
height: 64px;
-moz-margin-end: 10px;
}
.popup-notification-icon[popupid="geolocation"] {
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
}
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
%include ../shared/notification-icons.inc.css
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
@ -2177,212 +2116,15 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
font-weight: bold;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.popup-notification-icon[popupid="web-notifications"] {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {
list-style-image: url(chrome://global/skin/icons/question-64.png);
}
.popup-notification-icon[popupid="password"] {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
}
.popup-notification-icon[popupid="webapps-install-progress"],
.popup-notification-icon[popupid="webapps-install"] {
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
}
.popup-notification-icon[popupid="bad-content"] {
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
}
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingDevices"],
.popup-notification-icon[popupid="webRTC-shareDevices"] {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
}
.popup-notification-icon[popupid="webRTC-sharingScreen"],
.popup-notification-icon[popupid="webRTC-shareScreen"] {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
}
.popup-notification-icon[popupid="pointerLock"] {
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
}
/* Notification icon box */
#notification-popup-box {
position: relative;
background-color: #fff;
background-clip: padding-box;
padding-left: 3px;
border-radius: 2.5px 0 0 2.5px;
border-width: 0 8px 0 0;
border-style: solid;
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
-moz-margin-end: -8px;
}
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
padding-left: 7px;
}
#notification-popup-box:-moz-locale-dir(rtl),
.notification-anchor-icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
.notification-anchor-icon {
width: 16px;
height: 16px;
margin: 0 2px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
}
.default-notification-icon,
#default-notification-icon {
list-style-image: url(chrome://global/skin/icons/information-16.png);
}
.identity-notification-icon,
#identity-notification-icon {
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
}
.geo-notification-icon,
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}
#addons-notification-icon {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
}
.indexedDB-notification-icon,
#indexedDB-notification-icon {
list-style-image: url(chrome://global/skin/icons/question-16.png);
}
#password-notification-icon {
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
}
#webapps-notification-icon {
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
}
#plugins-notification-icon {
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
}
#plugins-notification-icon.plugin-hidden {
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
}
#plugins-notification-icon.plugin-blocked {
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
}
#plugins-notification-icon {
-moz-image-region: rect(0, 16px, 16px, 0);
}
#plugins-notification-icon:hover {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#plugins-notification-icon:active {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
#notification-popup-box[hidden] {
/* Override display:none to make the pluginBlockedNotification animation work
when showing the notification repeatedly. */
display: -moz-box;
visibility: collapse;
}
#plugins-notification-icon.plugin-blocked[showing] {
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
}
@keyframes pluginBlockedNotification {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.bad-content-blocked-notification-icon,
#bad-content-blocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
}
.bad-content-unblocked-notification-icon,
#bad-content-unblocked-notification-icon {
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
}
.webRTC-shareDevices-notification-icon,
#webRTC-shareDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
}
.webRTC-sharingDevices-notification-icon,
#webRTC-sharingDevices-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
}
.webRTC-shareMicrophone-notification-icon,
#webRTC-shareMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
}
.webRTC-sharingMicrophone-notification-icon,
#webRTC-sharingMicrophone-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
}
.webRTC-shareScreen-notification-icon,
#webRTC-shareScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
}
.webRTC-sharingScreen-notification-icon,
#webRTC-sharingScreen-notification-icon {
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
}
.web-notifications-notification-icon,
#web-notifications-notification-icon {
list-style-image: url(chrome://browser/skin/notification-16.png);
}
#pointerLock-notification-icon {
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
}
#pointerLock-cancel {
margin: 0px;
}
@ -2464,18 +2206,6 @@ notification[value="translation"] {
}
}
.translate-notification-icon,
#translate-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
.translated-notification-icon,
#translated-notification-icon {
list-style-image: url(chrome://browser/skin/translation-16.png);
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
.translation-menupopup {
-moz-appearance: none;
}
@ -2702,12 +2432,6 @@ toolbarpaletteitem[place="palette"] > #switch-to-metro-button {
list-style-image: url(chrome://browser/skin/Metro_Glyph-menuPanel.png);
}
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64.png);
}
#servicesInstall-notification-icon {
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
#social-undoactivation-button {
-moz-margin-start: 0; /* override default label margin to match description margin */
}
@ -2811,28 +2535,6 @@ chatbox {
border-top-right-radius: 2.5px;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
#eme-notification-icon[firstplay=true] {
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
}
@keyframes emeTeachingMoment {
0% {transform: translateX(0); }
25% {transform: translateX(3px) }
75% {transform: translateX(-3px) }
100% { transform: translateX(0); }
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css
@ -2936,32 +2638,32 @@ chatbox {
position: relative;
}
%ifndef WINDOWS_AERO
#TabsToolbar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-tabstrip-XPVista7.png");
}
@media not all and (-moz-windows-classic) {
#private-browsing-indicator-titlebar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7-tall.png");
height: 28px;
@media (-moz-os-version: windows-xp) {
#TabsToolbar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-tabstrip-XPVista7.png");
}
/* We're intentionally using the titlebar asset here for fullscreen mode.
* See bug 1008183.
*/
#main-window[inFullscreen] #TabsToolbar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7.png");
}
@media not all and (-moz-windows-classic) {
#private-browsing-indicator-titlebar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7-tall.png");
height: 28px;
}
#main-window[sizemode="maximized"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
top: -5px;
}
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
top: -1px;
/* We're intentionally using the titlebar asset here for fullscreen mode.
* See bug 1008183.
*/
#main-window[inFullscreen] #TabsToolbar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7.png");
}
#main-window[sizemode="maximized"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
top: -5px;
}
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
top: -1px;
}
}
}
%endif
@media (-moz-windows-classic) {
/* We're intentionally using the titlebar asset here for fullscreen mode.
@ -3000,3 +2702,8 @@ chatbox {
-moz-margin-start: -28px;
margin-top: -4px;
}
@media not all and (-moz-os-version: windows-xp) {
%include browser-aero.css
}

View File

@ -1,7 +0,0 @@
/* 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/. */
%define WINDOWS_AERO
%include panelUIOverlay.css
%undef WINDOWS_AERO

View File

@ -129,24 +129,24 @@ menu.subviewbutton > .menu-right:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
%ifdef WINDOWS_AERO
/* Win8 and beyond. */
@media not all and (-moz-os-version: windows-vista) {
@media not all and (-moz-os-version: windows-win7) {
panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox,
#edit-controls@inAnyPanel@,
#zoom-controls@inAnyPanel@,
#edit-controls@inAnyPanel@ > toolbarbutton,
#zoom-controls@inAnyPanel@ > toolbarbutton {
border-radius: 0;
@media not all and (-moz-os-version: windows-xp) {
@media not all and (-moz-os-version: windows-vista) {
@media not all and (-moz-os-version: windows-win7) {
panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
#BMB_bookmarksPopup menupopup[placespopup=true] > hbox,
#edit-controls@inAnyPanel@,
#zoom-controls@inAnyPanel@,
#edit-controls@inAnyPanel@ > toolbarbutton,
#zoom-controls@inAnyPanel@ > toolbarbutton {
border-radius: 0;
}
}
}
}
%endif
@media not all and (-moz-windows-default-theme) {
#edit-controls@inAnyPanel@ > #copy-button,

View File

@ -1,7 +0,0 @@
% 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/.
%define WINDOWS_AERO
%include devedition.css
%undef WINDOWS_AERO

View File

@ -1,35 +0,0 @@
/* 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/. */
%define WINDOWS_AERO
%include allDownloadsViewOverlay.css
%undef WINDOWS_AERO
@media (-moz-windows-default-theme) {
/*
-moz-appearance: menuitem is almost right, but the hover effect is not
transparent and is lighter than desired.
Copied from the autocomplete richlistbox styling in
toolkit/themes/windows/global/autocomplete.css
This styling should be kept in sync with the style from the above file.
*/
#downloadsRichListBox > richlistitem.download[selected] {
color: inherit;
background-color: transparent;
/* four gradients for the bevel highlights on each edge, one for blue background */
background-image:
linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
background-clip: content-box;
border-radius: 6px;
outline: 1px solid rgb(124,163,206);
-moz-outline-radius: 3px;
outline-offset: -2px;
}
}

View File

@ -10,21 +10,27 @@
#downloadsRichListBox > richlistitem.download {
height: 6em;
%ifndef WINDOWS_AERO
padding: 5px 8px;
%endif
}
@media (-moz-os-version: windows-xp) {
#downloadsRichListBox > richlistitem.download {
padding: 5px 8px;
}
}
.downloadTypeIcon {
-moz-margin-end: 8px;
%ifdef WINDOWS_AERO
-moz-margin-start: 8px;
%endif
/* explicitly size the icon, so size doesn't vary on hidpi systems */
height: 32px;
width: 32px;
}
@media not all and (-moz-os-version: windows-xp) {
.downloadTypeIcon {
-moz-margin-start: 8px;
}
}
.blockedIcon {
list-style-image: url("chrome://global/skin/icons/Error.png");
}
@ -105,56 +111,86 @@ richlistitem.download:hover > .downloadButton.downloadRetry:active {
-moz-image-region: rect(32px, 64px, 48px, 48px);
}
%ifndef WINDOWS_AERO
richlistitem.download[selected] > .downloadButton.downloadConfirmBlock,
richlistitem.download[selected] > .downloadButton.downloadCancel {
-moz-image-region: rect(0px, 80px, 16px, 64px);
@media (-moz-os-version: windows-xp) {
richlistitem.download[selected] > .downloadButton.downloadConfirmBlock,
richlistitem.download[selected] > .downloadButton.downloadCancel {
-moz-image-region: rect(0px, 80px, 16px, 64px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel {
-moz-image-region: rect(0px, 96px, 16px, 80px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:hover,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:hover {
-moz-image-region: rect(0px, 112px, 16px, 96px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:active,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:active {
-moz-image-region: rect(0px, 128px, 16px, 112px);
}
richlistitem.download[selected] > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 80px, 32px, 64px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 96px, 32px, 80px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 112px, 32px, 96px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 128px, 32px, 112px);
}
richlistitem.download[selected] > .downloadButton.downloadRetry {
-moz-image-region: rect(32px, 80px, 48px, 64px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry {
-moz-image-region: rect(32px, 96px, 48px, 80px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:hover {
-moz-image-region: rect(32px, 112px, 48px, 96px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:active {
-moz-image-region: rect(32px, 128px, 48px, 112px);
}
}
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel {
-moz-image-region: rect(0px, 96px, 16px, 80px);
}
@media not all and (-moz-os-version: windows-xp) {
@media (-moz-windows-default-theme) {
/*
-moz-appearance: menuitem is almost right, but the hover effect is not
transparent and is lighter than desired.
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:hover,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:hover {
-moz-image-region: rect(0px, 112px, 16px, 96px);
}
Copied from the autocomplete richlistbox styling in
toolkit/themes/windows/global/autocomplete.css
richlistitem.download[selected]:hover > .downloadButton.downloadConfirmBlock:active,
richlistitem.download[selected]:hover > .downloadButton.downloadCancel:active {
-moz-image-region: rect(0px, 128px, 16px, 112px);
This styling should be kept in sync with the style from the above file.
*/
#downloadsRichListBox > richlistitem.download[selected] {
color: inherit;
background-color: transparent;
/* four gradients for the bevel highlights on each edge, one for blue background */
background-image:
linear-gradient(to bottom, rgba(255,255,255,0.9) 3px, transparent 3px),
linear-gradient(to right, rgba(255,255,255,0.5) 3px, transparent 3px),
linear-gradient(to left, rgba(255,255,255,0.5) 3px, transparent 3px),
linear-gradient(to top, rgba(255,255,255,0.4) 3px, transparent 3px),
linear-gradient(to bottom, rgba(163,196,247,0.3), rgba(122,180,246,0.3));
background-clip: content-box;
border-radius: 6px;
outline: 1px solid rgb(124,163,206);
-moz-outline-radius: 3px;
outline-offset: -2px;
}
}
}
richlistitem.download[selected] > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 80px, 32px, 64px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 96px, 32px, 80px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 112px, 32px, 96px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 128px, 32px, 112px);
}
richlistitem.download[selected] > .downloadButton.downloadRetry {
-moz-image-region: rect(32px, 80px, 48px, 64px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry {
-moz-image-region: rect(32px, 96px, 48px, 80px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:hover {
-moz-image-region: rect(32px, 112px, 48px, 96px);
}
richlistitem.download[selected]:hover > .downloadButton.downloadRetry:active {
-moz-image-region: rect(32px, 128px, 48px, 112px);
}
%endif

View File

@ -1,23 +0,0 @@
/* 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/. */
%define WINDOWS_AERO
%include downloads.css
%undef WINDOWS_AERO
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
richlistitem[type="download"] {
border: 1px solid transparent;
border-bottom: 1px solid hsl(213,40%,90%);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border: 1px solid hsl(213,45%,65%);
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.3) inset;
background-image: linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
color: black;
}
}

View File

@ -32,16 +32,13 @@
cursor: pointer;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
#downloadsHistory {
color: -moz-nativehyperlinktext;
#downloadsHistory {
color: -moz-nativehyperlinktext;
}
}
%ifdef WINDOWS_AERO
}
%endif
#downloadsPanel[keyfocus] > #downloadsFooter > #downloadsHistory:focus {
outline: 1px -moz-dialogtext dotted;
@ -69,31 +66,32 @@
box-shadow: 0 2px 0 0 hsla(210,4%,10%,.1) inset;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
@media (-moz-windows-default-theme) {
#downloadsFooter {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
transition-duration: 0s;
}
@media (-moz-windows-default-theme) {
#downloadsFooter {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
transition-duration: 0s;
}
#downloadsFooter,
#downloadsFooter:hover,
#downloadsFooter:hover:active {
%ifdef WINDOWS_AERO
background-color: #f1f5fb;
%else
background-color: hsla(216,45%,88%,.98);
%endif
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
#downloadsFooter,
#downloadsFooter:hover,
#downloadsFooter:hover:active {
background-color: #f1f5fb;
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
}
@media (-moz-os-version: windows-xp) {
#downloadsFooter,
#downloadsFooter:hover,
#downloadsFooter:hover:active {
background-color: hsla(216,45%,88%,.98);
}
}
}
}
%ifdef WINDOWS_AERO
}
%endif
/*** Downloads Summary and List items ***/
@ -131,6 +129,14 @@ richlistitem[type="download"] {
padding: 8px;
}
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
richlistitem[type="download"] {
border: 1px solid transparent;
border-bottom: 1px solid hsl(213,40%,90%);
}
}
richlistitem[type="download"]:first-child {
border-top: 1px solid transparent;
}
@ -227,27 +233,35 @@ richlistitem[type="download"]:first-child {
box-shadow: 0 1px 0 0 hsla(210,4%,10%,.05) inset;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
@media (-moz-os-version: windows-xp),
(-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border-radius: 3px;
outline: 0;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background-color: Highlight;
color: HighlightText;
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border-radius: 3px;
outline: 0;
border-top: 1px solid hsla(0,0%,100%,.2);
border-bottom: 1px solid hsla(0,0%,0%,.2);
background-color: Highlight;
color: HighlightText;
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover:active {
background-color: Highlight;
outline: 0;
box-shadow: none;
}
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover:active {
background-color: Highlight;
outline: 0;
box-shadow: none;
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"][exists]:hover {
border: 1px solid hsl(213,45%,65%);
box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
0 1px 0 hsla(0,0%,100%,.3) inset;
background-image: linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
color: black;
}
}
%ifdef WINDOWS_AERO
}
%endif
/*** Button icons ***/
@ -280,26 +294,26 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadShow:hover
richlistitem[type="download"]:hover > stack > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 64px, 32px, 48px);
}
%ifndef WINDOWS_AERO
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 32px, 32px, 16px);
@media (-moz-os-version: windows-xp) {
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 32px, 32px, 16px);
}
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 48px, 32px, 32px);
}
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 64px, 32px, 48px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 96px, 32px, 80px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 112px, 32px, 96px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 128px, 32px, 112px);
}
}
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 48px, 32px, 32px);
}
#downloadsPanel[keyfocus] > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 64px, 32px, 48px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow {
-moz-image-region: rect(16px, 96px, 32px, 80px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:hover {
-moz-image-region: rect(16px, 112px, 32px, 96px);
}
#downloadsPanel:not([keyfocus]) > #downloadsListBox > richlistitem[type="download"][state="1"]:hover > stack > .downloadButton.downloadShow:active {
-moz-image-region: rect(16px, 128px, 32px, 112px);
}
%endif
.downloadButton.downloadRetry {
-moz-image-region: rect(32px, 16px, 48px, 0px);

View File

@ -1,8 +0,0 @@
/* 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/. */
#downloads-indicator-counter {
/* Bug 812345 added this... */
margin-bottom: -1px;
}

View File

@ -133,6 +133,13 @@ toolbar[brighttext] #downloads-button:not([counter])[attention] > #downloads-ind
text-align: center;
}
@media not all and (-moz-os-version: windows-xp) {
#downloads-indicator-counter {
/* Bug 812345 added this... */
margin-bottom: -1px;
}
}
toolbar[brighttext] #downloads-indicator-counter {
color: white;
text-shadow: 0 0 1px rgba(0,0,0,.7),

View File

@ -23,9 +23,7 @@ browser.jar:
skin/classic/browser/aboutTabCrashed.css (../shared/aboutTabCrashed.css)
skin/classic/browser/actionicon-tab.png
* skin/classic/browser/browser.css
* skin/classic/browser/browser-aero.css
* skin/classic/browser/devedition.css
* skin/classic/browser/devedition-aero.css
* skin/classic/browser/browser-lightweightTheme.css
skin/classic/browser/click-to-play-warning-stripes.png
skin/classic/browser/content-contextmenu.svg
@ -119,6 +117,7 @@ browser.jar:
skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
skin/classic/browser/undoCloseTab.png (../shared/undoCloseTab.png)
skin/classic/browser/undoCloseTab@2x.png (../shared/undoCloseTab@2x.png)
skin/classic/browser/update-badge.svg (../shared/update-badge.svg)
skin/classic/browser/urlbar-arrow.png
skin/classic/browser/urlbar-popup-blocked.png
skin/classic/browser/urlbar-history-dropmarker.png
@ -165,15 +164,13 @@ browser.jar:
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
skin/classic/browser/customizableui/panelarrow-customizeTip.png (../shared/customizableui/panelarrow-customizeTip.png)
* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
* skin/classic/browser/customizableui/panelUIOverlay-aero.css (customizableui/panelUIOverlay-aero.css)
skin/classic/browser/customizableui/subView-arrow-back-inverted.png (../shared/customizableui/subView-arrow-back-inverted.png)
skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
skin/classic/browser/customizableui/whimsy.png (../shared/customizableui/whimsy.png)
skin/classic/browser/customizableui/whimsy@2x.png (../shared/customizableui/whimsy@2x.png)
skin/classic/browser/customizableui/whimsy-bw.png (../shared/customizableui/whimsy-bw.png)
skin/classic/browser/customizableui/whimsy-bw@2x.png (../shared/customizableui/whimsy-bw@2x.png)
* skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
* skin/classic/browser/downloads/allDownloadsViewOverlay-aero.css (downloads/allDownloadsViewOverlay-aero.css)
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/buttons-aero.png (downloads/buttons-aero.png)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@ -181,8 +178,7 @@ browser.jar:
skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)
skin/classic/browser/downloads/download-notification-start.png (downloads/download-notification-start.png)
skin/classic/browser/downloads/download-summary.png (downloads/download-summary.png)
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
* skin/classic/browser/downloads/downloads-aero.css (downloads/downloads-aero.css)
skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/feedIcon-aero.png (feeds/feedIcon-aero.png)
@ -195,9 +191,7 @@ browser.jar:
skin/classic/browser/panic-panel/header-small.png (../shared/panic-panel/header-small.png)
skin/classic/browser/panic-panel/icons.png (../shared/panic-panel/icons.png)
skin/classic/browser/places/places.css (places/places.css)
* skin/classic/browser/places/places-aero.css (places/places-aero.css)
* skin/classic/browser/places/organizer.css (places/organizer.css)
* skin/classic/browser/places/organizer-aero.css (places/organizer-aero.css)
skin/classic/browser/places/bookmark.png (places/bookmark.png)
skin/classic/browser/places/bookmark-aero.png (places/bookmark-aero.png)
skin/classic/browser/places/query.png (places/query.png)
@ -529,8 +523,6 @@ browser.jar:
% override chrome://browser/skin/aboutSessionRestore-window-icon.png chrome://browser/skin/preferences/application.png os=WINNT osversion<6
% override chrome://browser/skin/aboutSessionRestore-window-icon.png chrome://browser/skin/aboutSessionRestore-window-icon-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/browser.css chrome://browser/skin/browser-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/devedition.css chrome://browser/skin/devedition-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/Info.png chrome://browser/skin/Info-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/identity.png chrome://browser/skin/identity-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/livemark-folder.png chrome://browser/skin/livemark-folder-aero.png os=WINNT osversion>=6
@ -541,14 +533,9 @@ browser.jar:
% override chrome://browser/skin/Privacy-32.png chrome://browser/skin/Privacy-32-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/searchbar-dropdown-arrow.png chrome://browser/skin/searchbar-dropdown-arrow-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/Secure24.png chrome://browser/skin/Secure24-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/customizableui/panelUIOverlay.css chrome://browser/skin/customizableui/panelUIOverlay-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/downloads/allDownloadsViewOverlay.css chrome://browser/skin/downloads/allDownloadsViewOverlay-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/downloads/buttons.png chrome://browser/skin/downloads/buttons-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/downloads/downloads.css chrome://browser/skin/downloads/downloads-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/feeds/feedIcon.png chrome://browser/skin/feeds/feedIcon-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/feeds/feedIcon16.png chrome://browser/skin/feeds/feedIcon16-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/places/places.css chrome://browser/skin/places/places-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/places/organizer.css chrome://browser/skin/places/organizer-aero.css os=WINNT osversion>=6
% override chrome://browser/skin/places/bookmark.png chrome://browser/skin/places/bookmark-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/places/query.png chrome://browser/skin/places/query-aero.png os=WINNT osversion>=6
% override chrome://browser/skin/places/bookmarksMenu.png chrome://browser/skin/places/bookmarksMenu-aero.png os=WINNT osversion>=6

View File

@ -1,77 +0,0 @@
/* 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/. */
%define WINDOWS_AERO
%include ../windowsShared.inc
%include organizer.css
%undef WINDOWS_AERO
%filter substitution
#placesView {
border-top: none;
}
@media not all and (-moz-windows-classic) {
#placesToolbox {
-moz-appearance: none;
background-color: transparent;
}
#placesToolbar {
-moz-appearance: none;
background-color: -moz-Dialog;
color: -moz-dialogText;
}
}
@media (-moz-windows-compositor) {
#placesToolbox {
border-top: none;
}
#placesToolbar {
background-image: linear-gradient(@toolbarHighlight@, transparent);
}
}
@media (-moz-windows-default-theme) {
#placesView > splitter {
border: 0;
-moz-border-end: 1px solid #A9B7C9;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-start: -3px;
position: relative;
}
}
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
#placesView,
#infoPane,
#placesList,
#placeContent {
background-color: #EEF3FA;
}
#placesToolbar {
background-color: @customToolbarColor@;
color: black;
}
#detailsDeck {
border-top-color: #A9B7C9;
}
#searchFilter {
-moz-appearance: none;
padding: 2px;
-moz-padding-start: 4px;
background-clip: padding-box;
border: 1px solid rgba(0,0,0,.32);
border-radius: 2px;
}
}

View File

@ -2,6 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include ../windowsShared.inc
%filter substitution
/* Toolbar */
#placesToolbar {
padding: 3px;
@ -17,14 +20,12 @@
list-style-image: url("chrome://browser/skin/Toolbar.png");
}
%ifndef WINDOWS_AERO
@media (-moz-windows-theme: luna-silver) {
#back-button,
#forward-button {
list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
}
}
%endif
#back-button {
-moz-image-region: rect(0, 54px, 18px, 36px);
@ -149,3 +150,73 @@
-moz-padding-start: 9px;
-moz-padding-end: 9px;
}
@media not all and (-moz-os-version: windows-xp) {
#placesView {
border-top: none;
}
@media not all and (-moz-windows-classic) {
#placesToolbox {
-moz-appearance: none;
background-color: transparent;
}
#placesToolbar {
-moz-appearance: none;
background-color: -moz-Dialog;
color: -moz-dialogText;
}
}
@media (-moz-windows-default-theme) {
#placesView > splitter {
border: 0;
-moz-border-end: 1px solid #A9B7C9;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-start: -3px;
position: relative;
}
}
}
@media (-moz-windows-compositor) {
#placesToolbox {
border-top: none;
}
#placesToolbar {
background-image: linear-gradient(@toolbarHighlight@, transparent);
}
}
@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
(-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
#placesView,
#infoPane,
#placesList,
#placeContent {
background-color: #EEF3FA;
}
#placesToolbar {
background-color: @customToolbarColor@;
color: black;
}
#detailsDeck {
border-top-color: #A9B7C9;
}
#searchFilter {
-moz-appearance: none;
padding: 2px;
-moz-padding-start: 4px;
background-clip: padding-box;
border: 1px solid rgba(0,0,0,.32);
border-radius: 2px;
}
}

View File

@ -1,22 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%include places.css
/* Style Places sidebars as Vista media collection */
@media (-moz-windows-default-theme) {
#bookmarksPanel,
#history-panel {
background-color: #EEF3FA;
}
.sidebar-placesTree {
background-color: transparent;
border-top: none;
}
.sidebar-placesTreechildren::-moz-tree-cell-text(leaf, hover) {
text-decoration: none;
}
}

View File

@ -24,6 +24,25 @@
cursor: default;
}
/* Style Places sidebars as Vista media collection */
@media not all and (-moz-os-version: windows-xp) {
@media (-moz-windows-default-theme) {
#bookmarksPanel,
#history-panel {
background-color: #EEF3FA;
}
.sidebar-placesTree {
background-color: transparent;
border-top: none;
}
.sidebar-placesTreechildren::-moz-tree-cell-text(leaf, hover) {
text-decoration: none;
}
}
}
/* Trees */
treechildren::-moz-tree-image(title) {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");

View File

@ -54,6 +54,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_signed_pkg_install.html]
[test_uninstall_errors.html]
[test_theme_role.html]
[test_third_party_homescreen.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
[test_web_app_install.html]
[test_widget.html]
skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app

View File

@ -0,0 +1,203 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}
-->
<head>
<title>Test for Bug {1097468}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}">Mozilla Bug {1097468}</a>
<script class="testbody" type="application/javascript;version=1.7">
var gManifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
var gGenerator = runTest();
const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm', {});
function runApp(aApp, aCallback) {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', aApp.manifestURL);
ifr.src = Services.io.newURI(aApp.manifestURL, null, null)
.resolve(aApp.manifest.launch_path);
ifr.addEventListener('mozbrowsershowmodalprompt', function onAlert(e) {
var message = e.detail.message;
info("Got message " + message);
if (message.startsWith("OK: ")) {
ok(true, message.substring(4, message.length));
} else if (message.startsWith("ERROR: ")) {
ok(false, message.substring(7, message.length));
} else if (message == "DONE") {
ifr.removeEventListener('mozbrowsershowmodalprompt', onAlert, false);
loadFrameScript(mm);
}
}, false);
document.body.appendChild(ifr);
var mm = SpecialPowers.getBrowserFrameMessageManager(ifr);
ok(mm, "mm is not null");
mm.addMessageListener('OK', function(msg) {
ok(true, "Message from app: " + SpecialPowers.wrap(msg).json);
});
mm.addMessageListener('KO', function(msg) {
ok(false, "Message from app: " + SpecialPowers.wrap(msg).json);
});
mm.addMessageListener('DONE', function() {
ok(true, "Message from app: complete");
document.body.removeChild(ifr);
aCallback();
});
// Test permission |homescreen-webapps-manage|
function frameScript()
{
function ok(p, msg) {
if (p) {
sendAsyncMessage("OK", msg);
} else {
sendAsyncMessage("KO", msg);
}
}
function is(a, b, msg) {
if (a == b) {
sendAsyncMessage("OK", a + " == " + b + " - " + msg);
} else {
sendAsyncMessage("KO", a + " != " + b + " - " + msg);
}
}
function finish() {
sendAsyncMessage("DONE", "");
}
if ('mgmt' in content.window.navigator.mozApps) {
ok(true, "get mgmt");
var mgmt = content.window.navigator.mozApps.mgmt;
is(typeof mgmt.getAll, "function", "get getAll");
is(typeof mgmt.uninstall, "function", "get uninstall");
is(typeof mgmt.oninstall, "object", "get oninstall");
is(typeof mgmt.onuninstall, "object", "get onuninstall");
is(typeof mgmt.onenabledstatechange, "object", "get onenabledstatechange");
[
"getNotInstalled",
"applyDownload",
"import",
"extractManifest",
"setEnabled"
].forEach(function(func) {
is(typeof mgmt[func], "undefined", "shouldn't get" + func);
});
} else {
ok(false, "can not get mgmt");
}
finish();
}
function loadFrameScript(mm) {
var script = "data:,(" + frameScript.toString() + ")();";
mm.loadFrameScript(script, /* allowDelayedLoad = */ false);
}
}
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document },
{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document }],
function() {
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
["dom.mozApps.homescreenURL",
gManifestURL]]}, continueTest)});
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
function finish() {
SimpleTest.finish();
}
function cbError(aEvent) {
ok(false, "Error callback invoked " +
aEvent.target.error.name + " " + aEvent.target.error.message);
finish();
}
SimpleTest.waitForExplicitFinish();
/**
* Test third-party homescreen (permission |homescreen-webapps-manage|)
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
// Install a app.
var request = navigator.mozApps.install(gManifestURL, { });
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var app = request.result;
ok(app, "App is non-null");
is(app.manifestURL, gManifestURL, "App manifest url is correct.");
var context = {"manifestURL": app.manifestURL, "isInBrowserElement": false};
SpecialPowers.pushPermissions([{"type": "homescreen-webapps-manage",
"allow": 1,
"context": context}], continueTest);
yield undefined;
// Launch the app.
info("Running " + app.manifestURL);
runApp(app, continueTest);
yield undefined;
SpecialPowers.popPermissions(continueTest);
yield undefined;
// Uninstall the app to cleanup after ourself.
navigator.mozApps.mgmt.onuninstall = function(event) {
var app = event.application;
is(app.manifestURL, gManifestURL, "App uninstall event ok.");
is(app.manifest.name, "Really Rapid Release (hosted)",
"App uninstall manifest ok.");
continueTest();
}
request = navigator.mozApps.mgmt.uninstall(app);
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
yield undefined;
is(request.result, gManifestURL, "App uninstalled.");
navigator.mozApps.mgmt.onuninstall = null;
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -176,6 +176,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
bool isInvalid = IS_INVALID_COD(mTarget.cod);
// The value of CoD is invalid. Since the device didn't declare its class of
// device properly, we assume the device may support all of these profiles.
if (isInvalid) {
AddProfile(BluetoothHfpManager::Get());
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothHidManager::Get());
return;
}
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);

View File

@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
// Pointing device: sub-field of minor device class (Bit 7)
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
/**
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
*
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
* CoD (class of device) is 3 bytes. The two least significant bits are used to
* indicate 'format type'. The following 22 bits are used to indicate category
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
*/
#define IS_INVALID_COD(cod) (cod >> 24)
class BluetoothProfileManagerBase;
class BluetoothReplyRunnable;
typedef void (*BluetoothProfileControllerCallback)();

View File

@ -173,6 +173,16 @@ BluetoothProfileController::SetupProfiles(bool aAssignServiceClass)
bool isRemoteControl = IS_REMOTE_CONTROL(mTarget.cod);
bool isKeyboard = IS_KEYBOARD(mTarget.cod);
bool isPointingDevice = IS_POINTING_DEVICE(mTarget.cod);
bool isInvalid = IS_INVALID_COD(mTarget.cod);
// The value of CoD is invalid. Since the device didn't declare its class of
// device properly, we assume the device may support all of these profiles.
if (isInvalid) {
AddProfile(BluetoothHfpManager::Get());
AddProfile(BluetoothA2dpManager::Get());
AddProfile(BluetoothHidManager::Get());
return;
}
NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);

View File

@ -53,6 +53,17 @@ BEGIN_BLUETOOTH_NAMESPACE
// Pointing device: sub-field of minor device class (Bit 7)
#define IS_POINTING_DEVICE(cod) ((GET_MINOR_DEVICE_CLASS(cod) & 0x20) >> 5)
/**
* Check whether the value of CoD is invalid. (i.e. Bit 31 ~ Bit 24 != 0x0)
*
* According to Bluetooth core spec v4.1. Vol 2, Sec. 7.3, the data length of
* CoD (class of device) is 3 bytes. The two least significant bits are used to
* indicate 'format type'. The following 22 bits are used to indicate category
* of service class and device type. The remaining 8 bits (Bit 31 ~ Bit 24)
* should be unassigned bits, since BlueDroid uses uint32_t to store CoD.
*/
#define IS_INVALID_COD(cod) (cod >> 24)
class BluetoothProfileManagerBase;
class BluetoothReplyRunnable;
typedef void (*BluetoothProfileControllerCallback)();

View File

@ -172,6 +172,11 @@ BrowserElementChild.prototype = {
/* useCapture = */ true,
/* wantsUntrusted = */ false);
addEventListener('click',
this._ClickHandler.bind(this),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
// This listens to unload events from our message manager, but /not/ from
// the |content| window. That's because the window's unload event doesn't
// bubble, and we're not using a capturing listener. If we'd used
@ -579,6 +584,18 @@ BrowserElementChild.prototype = {
sendAsyncMsg('scrollviewchange', detail);
},
_ClickHandler: function(e) {
let elem = e.target;
if (elem instanceof Ci.nsIDOMHTMLAnchorElement && elem.href) {
// Open in a new tab if middle click or ctrl/cmd-click.
if ((Services.appinfo.OS == 'Darwin' && e.metaKey) ||
(Services.appinfo.OS != 'Darwin' && e.ctrlKey) ||
e.button == 1) {
sendAsyncMsg('opentab', {url: elem.href});
}
}
},
_selectionStateChangedHandler: function(e) {
e.stopPropagation();
@ -1085,7 +1102,7 @@ BrowserElementChild.prototype = {
_updateVisibility: function() {
var visible = this._forcedVisible && this._ownerVisible;
if (docShell.isActive !== visible) {
if (docShell && docShell.isActive !== visible) {
docShell.isActive = visible;
sendAsyncMsg('visibilitychange', {visible: visible});
}

View File

@ -214,7 +214,8 @@ BrowserElementParent.prototype = {
"metachange": this._fireEventFromMsg,
"resize": this._fireEventFromMsg,
"activitydone": this._fireEventFromMsg,
"scroll": this._fireEventFromMsg
"scroll": this._fireEventFromMsg,
"opentab": this._fireEventFromMsg
};
this._mm.addMessageListener('browser-element-api:call', function(aMsg) {

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 1144015 - test middle/ctrl/cmd-click on a link.
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
function runTest() {
let iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
document.body.appendChild(iframe);
let x = 2;
let y = 2;
// First we force a reflow so that getChildProcessOffset actually returns
// meaningful data.
iframe.getBoundingClientRect();
// We need to make sure the event coordinates are actually inside the iframe,
// relative to the chome window.
let tabParent = SpecialPowers.wrap(iframe)
.QueryInterface(SpecialPowers.Ci.nsIFrameLoaderOwner)
.frameLoader.tabParent;
if (tabParent) {
let offsetX = {};
let offsetY = {};
tabParent.getChildProcessOffset(offsetX, offsetY);
x -= offsetX.value;
y -= offsetY.value;
}
let sendCtrlClick = () => {
let nsIDOMWindowUtils = SpecialPowers.Ci.nsIDOMWindowUtils;
let mod = nsIDOMWindowUtils.MODIFIER_META |
nsIDOMWindowUtils.MODIFIER_CONTROL;
iframe.sendMouseEvent('mousedown', x, y, 0, 1, mod);
iframe.sendMouseEvent('mouseup', x, y, 0, 1, mod);
}
let onCtrlClick = e => {
is(e.detail.url, 'http://example.com/', 'URL matches');
iframe.removeEventListener('mozbrowseropentab', onCtrlClick);
iframe.addEventListener('mozbrowseropentab', onMiddleClick);
sendMiddleClick();
}
let sendMiddleClick = () => {
iframe.sendMouseEvent('mousedown', x, y, 1, 1, 0);
iframe.sendMouseEvent('mouseup', x, y, 1, 1, 0);
}
let onMiddleClick= e => {
is(e.detail.url, 'http://example.com/', 'URL matches');
iframe.removeEventListener('mozbrowseropentab', onMiddleClick);
SimpleTest.finish();
}
iframe.addEventListener('mozbrowserloadend', e => {
iframe.addEventListener('mozbrowseropentab', onCtrlClick);
sendCtrlClick();
});
iframe.src = 'data:text/html,<body style="margin:0"><a href="http://example.com">click here</a></body>';
}
addEventListener('testready', runTest);

View File

@ -7,6 +7,7 @@ skip-if = os == "android" || (toolkit == "cocoa" && debug) || buildapp == 'mulet
support-files =
browserElement_OpenMixedProcess.js
file_browserElement_OpenMixedProcess.html
browserElement_OpenTab.js
[test_browserElement_oop_ThemeColor.html]
[test_browserElement_inproc_ErrorSecurity.html]
@ -60,6 +61,8 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_OpenWindowRejected.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_Opensearch.html]
[test_browserElement_oop_OpenTab.html]
skip-if = (toolkit == 'gonk') # Disabled on emulator. See bug 1144015 comment 8
[test_browserElement_oop_PrivateBrowsing.html]
[test_browserElement_oop_PromptCheck.html]
[test_browserElement_oop_PromptConfirm.html]

View File

@ -38,6 +38,7 @@ support-files =
browserElement_Metachange.js
browserElement_NextPaint.js
browserElement_OpenNamed.js
browserElement_OpenTab.js
browserElement_OpenWindow.js
browserElement_OpenWindowDifferentOrigin.js
browserElement_OpenWindowInFrame.js
@ -168,6 +169,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_browserElement_inproc_NextPaint.html]
[test_browserElement_inproc_OpenNamed.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_OpenTab.html]
disabled = won't work as Firefox desktop will intercept ctrl-click
[test_browserElement_inproc_OpenWindow.html]
skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_inproc_OpenWindowDifferentOrigin.html]

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
-->
<head>
<title>Test for Bug 1144015</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
</script>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1144015
-->
<head>
<title>Test for Bug 1144015</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1144015">Mozilla Bug 1144015</a>
<script type="application/javascript;version=1.7" src="browserElement_OpenTab.js">
</script>
</body>
</html>

View File

@ -39,7 +39,7 @@ skip-if(Android||B2G) == 649134-2.html 649134-2-ref.html
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
# The vast majority of the fuzziness comes from Linux and WinXP.)
fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html
skip-if(B2G) fuzzy-if(!B2G,3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
skip-if(B2G||Mulet) fuzzy-if((!B2G&&!Mulet),3,640) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869 # Bug 1150490 disabling on Mulet as on B2G
# Test support for SVG-as-image in <picture> elements.
pref(dom.image.picture.enabled,true) pref(dom.image.srcset.enabled,true) == bug1106522-1.html bug1106522-ref.html

View File

@ -992,14 +992,39 @@ void NetworkUtils::removeDefaultRoute(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
// FIXME: (Bug 1121795) We only remove the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
aCallback(aChain, false, aResult);
return;
}
doCommand(command, aChain, aCallback);
char command[MAX_COMMAND_SIZE];
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
int type = getIpType(autoGateway.get());
snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s %s/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname),
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
CommandChain* aChain,
bool aError,
mozilla::dom::NetworkResultOptions& aResult)
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("removeDefaultRoute's reason: %s", reason.get());
if (aError && !reason.EqualsASCII("removeRoute() failed (No such process)")) {
return aOriginalCallback(aChain, aError, aResult);
}
GET_FIELD(mLoopIndex)++;
return removeDefaultRoute(aChain, aOriginalCallback, aResult);
}
};
CommandCallback wrappedCallback(MyCallback::callback, aCallback);
doCommand(command, aChain, wrappedCallback);
}
void NetworkUtils::setInterfaceDns(CommandChain* aChain,
@ -1147,13 +1172,19 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
CommandCallback aCallback,
NetworkResultOptions& aResult)
{
char command[MAX_COMMAND_SIZE];
if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) {
aCallback(aChain, false, aResult);
return;
}
// FIXME: (Bug 1121795) We only add the first gateway to the default route.
// For dual stack (ipv4/ipv6) device, one of the gateway would
// not be added to the default route.
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s 0.0.0.0/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname), GET_CHAR(mGateways[0]));
char command[MAX_COMMAND_SIZE];
nsTArray<nsString>& gateways = GET_FIELD(mGateways);
NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]);
int type = getIpType(autoGateway.get());
snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s %s/0 %s",
GET_FIELD(mNetId), GET_CHAR(mIfname),
type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get());
struct MyCallback {
static void callback(CommandCallback::CallbackType aOriginalCallback,
@ -1163,11 +1194,12 @@ void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain,
{
NS_ConvertUTF16toUTF8 reason(aResult.mResultReason);
NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get());
if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) {
NU_DBG("Ignore \"File exists\" error when adding host route.");
return aOriginalCallback(aChain, false, aResult);
if (aError && !reason.EqualsASCII("addRoute() failed (File exists)")) {
return aOriginalCallback(aChain, aError, aResult);
}
aOriginalCallback(aChain, aError, aResult);
GET_FIELD(mLoopIndex)++;
return addDefaultRouteToNetwork(aChain, aOriginalCallback, aResult);
}
};
@ -1810,8 +1842,9 @@ CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions)
}
aOptions.mNetId = netIdInfo.mNetId;
aOptions.mLoopIndex = 0;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();
}
@ -1893,6 +1926,7 @@ CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions)
NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname));
aOptions.mNetId = netIdInfo.mNetId;
aOptions.mLoopIndex = 0;
runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler);
return CommandResult::Pending();

View File

@ -146,6 +146,8 @@ public:
COPY_OPT_FIELD(mDns1_long, 0)
COPY_OPT_FIELD(mDns2_long, 0)
mLoopIndex = 0;
#undef COPY_SEQUENCE_FIELD
#undef COPY_OPT_STRING_FIELD
#undef COPY_OPT_FIELD
@ -198,7 +200,8 @@ public:
long mDns2_long;
// Auxiliary information required to carry accros command chain.
int mNetId; // A locally defined id per interface.
int mNetId; // A locally defined id per interface.
uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways.
};
// CommandChain store the necessary information to execute command one by one.

View File

@ -24,7 +24,7 @@ enum LocaleResourceType {
[NoInterfaceObject, NavigatorProperty="mozApps",
JSImplementation="@mozilla.org/webapps;1"]
interface DOMApplicationsRegistry {
[CheckPermissions="webapps-manage"]
[CheckPermissions="webapps-manage homescreen-webapps-manage"]
readonly attribute DOMApplicationsManager mgmt;
DOMRequest install(DOMString url, optional InstallParameters params);
DOMRequest installPackage(DOMString url, optional InstallParameters params);
@ -116,16 +116,22 @@ interface DOMApplication : EventTarget {
[JSImplementation="@mozilla.org/webapps/manager;1",
ChromeOnly,
CheckPermissions="webapps-manage"]
CheckPermissions="webapps-manage homescreen-webapps-manage"]
interface DOMApplicationsManager : EventTarget {
DOMRequest getAll();
[CheckPermissions="webapps-manage"]
DOMRequest getNotInstalled();
[CheckPermissions="webapps-manage"]
void applyDownload(DOMApplication app);
DOMRequest uninstall(DOMApplication app);
[CheckPermissions="webapps-manage"]
Promise<DOMApplication> import(Blob blob);
[CheckPermissions="webapps-manage"]
Promise<any> extractManifest(Blob blob);
[CheckPermissions="webapps-manage"]
void setEnabled(DOMApplication app, boolean state);
Promise<Blob> getIcon(DOMApplication app, DOMString iconID,
optional DOMString entryPoint);

View File

@ -156,6 +156,12 @@ public:
SetLayer(aLayer);
mAttached = true;
mKeepAttached = aFlags & KEEP_ATTACHED;
// If we already have a textureHost before, use that in this moment.
RefPtr<TextureHost> frontBuffer = GetAsTextureHost();
if (frontBuffer) {
UseTextureHost(frontBuffer);
}
}
// Detach this compositable host from its layer.
// If we are used for async video, then it is not safe to blindly detach since

View File

@ -567,11 +567,14 @@ struct AutoStopwatch final
ULARGE_INTEGER userTimeInt;
kernelTimeInt.LowPart = kernelFileTime.dwLowDateTime;
kernelTimeInt.HighPart = kernelFileTime.dwHighDateTime;
*systemTime = kernelTimeInt.QuadPart / 10; // 100 ns to 1 us
// Convert 100 ns to 1 us, make sure that the result is monotonic
*systemTime = runtime_-> stopwatch.systemTimeFix.monotonize(kernelTimeInt.QuadPart / 10);
userTimeInt.LowPart = userFileTime.dwLowDateTime;
userTimeInt.HighPart = userFileTime.dwHighDateTime;
*userTime = userTimeInt.QuadPart / 10; // 100 ns to 1 us
// Convert 100 ns to 1 us, make sure that the result is monotonic
*userTime = runtime_-> stopwatch.userTimeFix.monotonize(userTimeInt.QuadPart / 10);
#endif // defined(XP_UNIX) || defined(XP_WIN)
return true;

View File

@ -1532,6 +1532,28 @@ struct JSRuntime : public JS::shadow::Runtime,
return isActive_;
}
// Some systems have non-monotonic clocks. While we cannot
// improve the precision, we can make sure that our measures
// are monotonic nevertheless. We do this by storing the
// result of the latest call to the clock and making sure
// that the next timestamp is greater or equal.
struct MonotonicTimeStamp {
MonotonicTimeStamp()
: latestGood_(0)
{}
inline uint64_t monotonize(uint64_t stamp)
{
if (stamp <= latestGood_)
return latestGood_;
latestGood_ = stamp;
return stamp;
}
private:
uint64_t latestGood_;
};
MonotonicTimeStamp systemTimeFix;
MonotonicTimeStamp userTimeFix;
private:
/**
* A map used to collapse compartments belonging to the same

View File

@ -28,14 +28,14 @@ fails-if(Android||B2G||Mulet) == disabled-1.html disabled-1-ref.html # Initial m
!= disabled-5.html disabled-5-notref.html
!= disabled-6.html disabled-6-notref.html
fails-if(B2G) == width-auto-size-em-ltr.html width-auto-size-em-ltr-ref.html # Bug 1145672
fails-if(B2G) == width-auto-size-ltr.html width-auto-size-ltr-ref.html # Bug 1145672
fails-if(B2G||Mulet) == width-auto-size-em-ltr.html width-auto-size-em-ltr-ref.html # Bug 1145672 # Bug 1150486
fails-if(B2G||Mulet) == width-auto-size-ltr.html width-auto-size-ltr-ref.html # Bug 1145672 # Bug 1150486
== width-exact-fit-ltr.html width-auto-size-ltr-ref.html
== width-erode-part-focuspadding-ltr.html width-erode-part-focuspadding-ltr-ref.html
== width-erode-all-focuspadding-ltr.html width-erode-all-focuspadding-ltr-ref.html
== width-erode-overflow-focuspadding-ltr.html width-erode-overflow-focuspadding-ltr-ref.html
fails-if(B2G) == width-auto-size-em-rtl.html width-auto-size-em-rtl-ref.html # Bug 1145672
fails-if(B2G) == width-auto-size-rtl.html width-auto-size-rtl-ref.html # Bug 1145672
fails-if(B2G||Mulet) == width-auto-size-em-rtl.html width-auto-size-em-rtl-ref.html # Bug 1145672 # Bug 1150486
fails-if(B2G||Mulet) == width-auto-size-rtl.html width-auto-size-rtl-ref.html # Bug 1145672 # Bug 1150486
== width-exact-fit-rtl.html width-auto-size-rtl-ref.html
== width-erode-part-focuspadding-rtl.html width-erode-part-focuspadding-rtl-ref.html
== width-erode-all-focuspadding-rtl.html width-erode-all-focuspadding-rtl-ref.html

View File

@ -173,9 +173,9 @@ skip-if(B2G) == object-fit-scale-down-svg-002o.html object-fit-scale-down-svg-00
== object-fit-scale-down-svg-006o.html object-fit-scale-down-svg-006-ref.html
== object-fit-scale-down-svg-006p.html object-fit-scale-down-svg-006-ref.html
fails == object-position-png-001c.html object-position-png-001-ref.html # bug 1105150
== object-position-png-001e.html object-position-png-001-ref.html
fuzzy-if(Mulet,2,20) == object-position-png-001e.html object-position-png-001-ref.html # Bug 1150536
== object-position-png-001i.html object-position-png-001-ref.html
== object-position-png-001o.html object-position-png-001-ref.html
fuzzy-if(Mulet,2,20) == object-position-png-001o.html object-position-png-001-ref.html # Bug 1150492
== object-position-png-001p.html object-position-png-001-ref.html
fails == object-position-png-002c.html object-position-png-002-ref.html # bug 1105150
== object-position-png-002e.html object-position-png-002-ref.html

View File

@ -58,11 +58,16 @@ public class AndroidFxAccount {
public static final String ACCOUNT_KEY_PROFILE = "profile";
public static final String ACCOUNT_KEY_IDP_SERVER = "idpServerURI";
// The audience should always be a prefix of the token server URI.
public static final String ACCOUNT_KEY_AUDIENCE = "audience"; // Sync-specific.
public static final String ACCOUNT_KEY_TOKEN_SERVER = "tokenServerURI"; // Sync-specific.
public static final String ACCOUNT_KEY_DESCRIPTOR = "descriptor";
// The set of authorities to sync automatically changes over time. The first
// new authority is the Reading List. This tracks if we've enabled syncing,
// and opted in (or out) of syncing automatically, for the new Reading List
// authority. This happens either on when the account is created or when
// upgrading.
public static final String ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED = "readingListAuthorityInitialized";
public static final int CURRENT_BUNDLE_VERSION = 2;
public static final String BUNDLE_KEY_BUNDLE_VERSION = "version";
public static final String BUNDLE_KEY_STATE_LABEL = "stateLabel";
@ -401,6 +406,10 @@ public class AndroidFxAccount {
userdata.putString(ACCOUNT_KEY_IDP_SERVER, idpServerURI);
userdata.putString(ACCOUNT_KEY_TOKEN_SERVER, tokenServerURI);
userdata.putString(ACCOUNT_KEY_PROFILE, profile);
if (DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.containsKey(BrowserContract.READING_LIST_AUTHORITY)) {
// Have we initialized the Reading List authority?
userdata.putString(ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
}
if (bundle == null) {
bundle = new ExtendedJSONObject();

View File

@ -11,6 +11,7 @@ import java.util.concurrent.Executors;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
@ -19,7 +20,9 @@ import org.mozilla.gecko.fxa.login.State.StateLabel;
import org.mozilla.gecko.sync.Utils;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@ -45,6 +48,7 @@ public class FxAccountUpgradeReceiver extends BroadcastReceiver {
// Recovering accounts that are in the Doghouse should happen *after* we
// unpickle any accounts saved to disk.
runnables.add(new AdvanceFromDoghouseRunnable(context));
runnables.add(new MaybeInitializeReadingListAuthority(context));
return runnables;
}
@ -130,4 +134,68 @@ public class FxAccountUpgradeReceiver extends BroadcastReceiver {
}
}
}
/**
* A Runnable that initializes the Reading List authority (specifically, set
* the sync automatically flag) for existing Firefox Accounts that have not
* yet seen the authority. That is, if a new authority (Reading List) is added
* to the set of defaults, existing Firefox Accounts won't be syncing it
* automatically. This tries to set the sync automatically flag for such
* existing accounts.
*
* Public for testing only.
*/
public static class MaybeInitializeReadingListAuthority implements Runnable {
protected final Context context;
public MaybeInitializeReadingListAuthority(Context context) {
this.context = context;
}
@Override
public void run() {
final String authority = BrowserContract.READING_LIST_AUTHORITY;
Boolean enabledByDefault = AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP.get(authority);
if (enabledByDefault == null || !enabledByDefault.booleanValue()) {
Logger.info(LOG_TAG, "Reading List authority is not enabled by default; not trying to initialize Reading List authority for any accounts.");
}
final AccountManager accountManager = AccountManager.get(context);
final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context);
Logger.info(LOG_TAG, "Trying to initialize Reading List authority for " + accounts.length + " existing Firefox Accounts (if necessary).");
for (Account account : accounts) {
try {
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
// For great debugging.
if (FxAccountUtils.LOG_PERSONAL_INFORMATION) {
fxAccount.dump();
}
final boolean readingListAuthorityInitialized =
"1".equals(accountManager.getUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED));
if (readingListAuthorityInitialized) {
Logger.debug(LOG_TAG, "Reading List authority has already been initialized.");
continue;
}
// The Reading List authority has not been seen. This happens when an
// authority is added after the Firefox Account has been added (and
// the package last upgraded). If Firefox Sync is not syncing
// automatically, Reading List should not start syncing
// automatically: the user has elected not to upload data to Mozilla
// servers; we shouldn't opt them in.
final boolean syncAutomatically = ContentResolver.getSyncAutomatically(account, BrowserContract.AUTHORITY);
Logger.debug(LOG_TAG, "Setting Reading List authority " +
(syncAutomatically ? " to " : " to not ") + "sync automatically.");
ContentResolver.setSyncAutomatically(account, BrowserContract.READING_LIST_AUTHORITY, syncAutomatically);
// Update the account record.
accountManager.setUserData(account, AndroidFxAccount.ACCOUNT_KEY_READING_LIST_AUTHORITY_INITIALIZED, "1");
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception trying to set authoritities to sync automatically for account named like " +
Utils.obfuscateEmail(account.name) + "; ignoring.", e);
}
}
}
}
}

View File

@ -170,7 +170,6 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setWindowAnimations(0);
setContentView(R.layout.overlay_share_dialog);
LocalBroadcastManager.getInstance(this).registerReceiver(uiEventListener,
@ -254,6 +253,11 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
serviceStartupIntent.setAction(OverlayConstants.ACTION_PREPARE_SHARE);
startService(serviceStartupIntent);
// Start the slide-up animation.
getWindow().setWindowAnimations(0);
final Animation anim = AnimationUtils.loadAnimation(this, R.anim.overlay_slide_up);
findViewById(R.id.sharedialog).startAnimation(anim);
// If provided, we use the subject text to give us something nice to display.
// If not, we wing it with the URL.
@ -306,10 +310,6 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
final LocalBrowserDB browserDB = new LocalBrowserDB(getCurrentProfile());
setButtonState(url, browserDB);
// Start the slide-up animation.
final Animation anim = AnimationUtils.loadAnimation(this, R.anim.overlay_slide_up);
findViewById(R.id.sharedialog).startAnimation(anim);
}
@Override

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -10,7 +10,7 @@
android:paddingLeft="4dip"
android:background="@drawable/new_tablet_tabs_count_foreground"
android:textAppearance="@style/TextAppearance.Micro"
android:textColor="@color/text_color_primary_inverse"
android:textColor="@color/toolbar_grey"
android:textStyle="bold"
android:duplicateParentState="true"
android:gravity="center"/>

View File

@ -11,7 +11,7 @@
android:paddingLeft="4dip"
android:background="@drawable/tabs_count_foreground"
android:textAppearance="@style/TextAppearance.Micro"
android:textColor="#FF43484E"
android:textColor="@color/text_and_tabs_tray_grey"
android:textStyle="bold"
android:duplicateParentState="true"
android:gravity="center"/>

View File

@ -5,9 +5,6 @@
package org.mozilla.gecko.toolbar;
import android.graphics.Rect;
import android.view.TouchDelegate;
import android.view.ViewTreeObserver;
import org.mozilla.gecko.R;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
@ -53,27 +50,6 @@ class BrowserToolbarTablet extends BrowserToolbarTabletBase {
setButtonEnabled(forwardButton, true);
updateForwardButtonState(ForwardButtonState.HIDDEN);
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// We do this in an onPreDrawListener because we need the Views
// to be laid out before we can make size calculations.
getViewTreeObserver().removeOnPreDrawListener(this);
final Rect r = new Rect();
r.left = menuButton.getLeft();
r.right = getWidth();
r.top = 0;
r.bottom = getHeight();
// Redirect touch events between the 3-dot menu button
// and the edge of the screen to the right of the button.
setTouchDelegate(new TouchDelegate(r, menuButton));
return true;
}
});
}
private void updateForwardButtonState(final ForwardButtonState state) {

View File

@ -1082,4 +1082,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1436005136747000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1436609916936000);

View File

@ -6,6 +6,7 @@ airbnb.com: did not receive HSTS header
aiticon.de: did not receive HSTS header
altmv.com: max-age too low: 7776000
amigogeek.net: [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 134" data: no]
ankakaak.com: could not connect to host
api.mega.co.nz: could not connect to host
api.recurly.com: did not receive HSTS header
apis.google.com: did not receive HSTS header (error ignored - included regardless)
@ -14,8 +15,8 @@ appengine.google.com: did not receive HSTS header (error ignored - included rega
appseccalifornia.org: did not receive HSTS header
astaxi.net: did not receive HSTS header
at.search.yahoo.com: did not receive HSTS header
atavio.at: could not connect to host
atavio.ch: could not connect to host
atavio.at: did not receive HSTS header
atavio.ch: did not receive HSTS header
atavio.de: did not receive HSTS header
au.search.yahoo.com: did not receive HSTS header
auth.mail.ru: did not receive HSTS header
@ -24,6 +25,7 @@ az.search.yahoo.com: did not receive HSTS header
azprep.us: could not connect to host
baldwinkoo.com: did not receive HSTS header
barcodeberlin.com: did not receive HSTS header
bassh.net: could not connect to host
bccx.com: could not connect to host
bcm.com.au: max-age too low: 0
be.search.yahoo.com: did not receive HSTS header
@ -38,11 +40,14 @@ bizon.sk: did not receive HSTS header
blog.lookout.com: did not receive HSTS header
br.search.yahoo.com: did not receive HSTS header
brainfork.ml: did not receive HSTS header
braintreegateway.com: did not receive HSTS header
braintreepayments.com: did not receive HSTS header
brainvation.de: did not receive HSTS header
browserid.org: did not receive HSTS header
business.medbank.com.mt: could not connect to host
bzv-fr.eu: could not connect to host
ca.search.yahoo.com: did not receive HSTS header
cake.care: could not connect to host
calibreapp.com: did not receive HSTS header
calyxinstitute.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 134" data: no]
carlolly.co.uk: could not connect to host
@ -58,10 +63,12 @@ checkout.google.com: did not receive HSTS header (error ignored - included regar
chfr.search.yahoo.com: did not receive HSTS header
chit.search.yahoo.com: did not receive HSTS header
chm.vn: did not receive HSTS header
chontalpa.pw: did not receive HSTS header
chrome-devtools-frontend.appspot.com: did not receive HSTS header (error ignored - included regardless)
chrome.google.com: did not receive HSTS header (error ignored - included regardless)
cimballa.com: did not receive HSTS header
cl.search.yahoo.com: did not receive HSTS header
climaprecio.es: did not receive HSTS header
cn.search.yahoo.com: did not receive HSTS header
co.search.yahoo.com: did not receive HSTS header
code.google.com: did not receive HSTS header (error ignored - included regardless)
@ -113,7 +120,6 @@ espanol.search.yahoo.com: did not receive HSTS header
espra.com: could not connect to host
ethitter.com: did not receive HSTS header
etsysecure.com: could not connect to host
ezequiel-garzon.com: could not connect to host
fabianfischer.de: did not receive HSTS header
fatzebra.com.au: did not receive HSTS header
fi.search.yahoo.com: did not receive HSTS header
@ -149,6 +155,7 @@ hn.search.yahoo.com: did not receive HSTS header
hoerbuecher-und-hoerspiele.de: did not receive HSTS header
honeytracks.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 134" data: no]
horosho.in: could not connect to host
horseboners.xxx: could not connect to host
hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
howrandom.org: could not connect to host
hstspreload.appspot.com: did not receive HSTS header
@ -164,14 +171,16 @@ iniiter.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERRO
intercom.io: did not receive HSTS header
interserved.com: did not receive HSTS header
iop.intuit.com: max-age too low: 86400
iranianlawschool.com: could not connect to host
irccloud.com: did not receive HSTS header
it.search.yahoo.com: did not receive HSTS header
itshost.ru: could not connect to host
j0s.at: did not receive HSTS header
janoberst.com: did not receive HSTS header
jelmer.co.uk: could not connect to host
jonathan.ir: could not connect to host
jottit.com: could not connect to host
k-dev.de: could not connect to host
kdex.de: did not receive HSTS header
keepclean.me: could not connect to host
keymaster.lookout.com: did not receive HSTS header
kirkforcongress.com: could not connect to host
@ -209,14 +218,15 @@ market.android.com: did not receive HSTS header (error ignored - included regard
marshut.net: could not connect to host
matatall.com: could not connect to host
mattmccutchen.net: could not connect to host
mccrypto.de: could not connect to host
mediacru.sh: could not connect to host
megashur.se: did not receive HSTS header
megaxchange.com: did not receive HSTS header
meinebo.it: could not connect to host
minikneet.nl: did not receive HSTS header
micropple.net: did not receive HSTS header
minikneet.nl: could not connect to host
mirindadomo.ru: did not receive HSTS header
mnemotiv.com: could not connect to host
mnsure.org: could not connect to host
mobilethreat.net: could not connect to host
mobilethreatnetwork.net: could not connect to host
mocloud.eu: [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 134" data: no]
@ -224,7 +234,6 @@ mqas.net: could not connect to host
mt.search.yahoo.com: did not receive HSTS header
mu.search.yahoo.com: did not receive HSTS header
mujadin.se: max-age too low: 86400
munuc.org: could not connect to host
mw.search.yahoo.com: did not receive HSTS header
mx.search.yahoo.com: did not receive HSTS header
my.alfresco.com: did not receive HSTS header
@ -259,6 +268,7 @@ pe.search.yahoo.com: did not receive HSTS header
ph.search.yahoo.com: did not receive HSTS header
piratenlogin.de: could not connect to host
pisidia.de: did not receive HSTS header
pixi.me: could not connect to host
pk.search.yahoo.com: did not receive HSTS header
pl.search.yahoo.com: did not receive HSTS header
platform.lookout.com: could not connect to host
@ -270,6 +280,7 @@ pressfreedomfoundation.org: did not receive HSTS header
prodpad.com: did not receive HSTS header
promecon-gmbh.de: did not receive HSTS header
proximato.com: could not connect to host
pult.co: could not connect to host
py.search.yahoo.com: did not receive HSTS header
qc.search.yahoo.com: did not receive HSTS header
rapidresearch.me: could not connect to host
@ -277,7 +288,6 @@ redlatam.org: did not receive HSTS header
redports.org: did not receive HSTS header
regar42.fr: could not connect to host
reserve-online.net: did not receive HSTS header
richiemail.net: could not connect to host
riseup.net: did not receive HSTS header
rme.li: did not receive HSTS header
ro.search.yahoo.com: did not receive HSTS header
@ -301,9 +311,9 @@ silentcircle.org: could not connect to host
simon.butcher.name: max-age too low: 2629743
simplyfixit.co.uk: [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 134" data: no]
sites.google.com: did not receive HSTS header (error ignored - included regardless)
smartcleaningcenter.nl: could not connect to host
smartlend.se: [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 134" data: no]
sol.io: could not connect to host
soulogic.com: could not connect to host
souyar.de: could not connect to host
souyar.net: could not connect to host
souyar.us: could not connect to host
@ -332,9 +342,13 @@ temehu.com: did not receive HSTS header
terrax.berlin: could not connect to host
th.search.yahoo.com: did not receive HSTS header
the-sky-of-valkyries.com: could not connect to host
thetomharling.com: did not receive HSTS header
thomasgriffin.io: did not receive HSTS header
thorncreek.net: did not receive HSTS header
tomharling.co.uk: did not receive HSTS header
tomharling.uk: could not connect to host
toptexture.com: did not receive HSTS header
tor2web.org: could not connect to host
tr.search.yahoo.com: did not receive HSTS header
translate.googleapis.com: did not receive HSTS header (error ignored - included regardless)
translatoruk.co.uk: did not receive HSTS header
@ -349,7 +363,7 @@ uy.search.yahoo.com: did not receive HSTS header
uz.search.yahoo.com: did not receive HSTS header
ve.search.yahoo.com: did not receive HSTS header
vhost.co.id: could not connect to host
viennan.net: did not receive HSTS header
viennan.net: could not connect to host
vn.search.yahoo.com: did not receive HSTS header
vyncke.org: did not receive HSTS header
wallet.google.com: did not receive HSTS header (error ignored - included regardless)

View File

@ -8,7 +8,7 @@
/*****************************************************************************/
#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1438424329809000);
const PRTime gPreloadListExpirationTime = INT64_C(1439029112102000);
class nsSTSPreload
{
@ -29,6 +29,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "2600hq.com", true },
{ "301.website", true },
{ "302.nyc", true },
{ "47ronin.com", false },
{ "5apps.com", false },
{ "7183.org", true },
{ "8ack.de", true },
@ -37,6 +38,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "accounts.google.com", true },
{ "aclu.org", false },
{ "activiti.alfresco.com", false },
{ "acuica.co.uk", false },
{ "acus.gov", true },
{ "adamkostecki.de", true },
{ "adamstas.com", true },
@ -47,6 +49,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "admin.stg.fedoraproject.org", true },
{ "adorai.tk", true },
{ "adsfund.org", true },
{ "advanced-online.eu", true },
{ "afp548.com", true },
{ "agrimap.com", true },
{ "ahoyconference.com", true },
@ -102,6 +105,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "apps.fedoraproject.org", true },
{ "apps.stg.fedoraproject.org", true },
{ "aprz.de", true },
{ "arbitrary.ch", true },
{ "archlinux.de", true },
{ "areafiftylan.nl", true },
{ "arendburgers.nl", true },
@ -114,8 +118,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "arty.name", true },
{ "ask.fedoraproject.org", true },
{ "ask.stg.fedoraproject.org", true },
{ "atavio.at", true },
{ "atavio.ch", true },
{ "atc.io", true },
{ "athenelive.com", true },
{ "atishchenko.com", true },
@ -160,6 +162,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "bgneuesheim.de", true },
{ "bhatia.at", true },
{ "biathloncup.ru", true },
{ "bidon.ca", true },
{ "big-andy.co.uk", true },
{ "bigbrownpromotions.com.au", true },
{ "billigssl.dk", true },
@ -190,6 +193,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "blubbablasen.de", true },
{ "bodo-wolff.de", true },
{ "bohramt.de", true },
{ "boiseonlinemall.com", true },
{ "bonigo.de", true },
{ "bonitabrazilian.co.nz", true },
{ "bookingapp.nl", true },
@ -197,7 +201,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "boypoint.de", true },
{ "bradkovach.com", true },
{ "brage.info", true },
{ "braintreegateway.com", true },
{ "brakemanpro.com", true },
{ "bran.cc", true },
{ "brandbuilderwebsites.com", true },
@ -232,6 +235,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "cartucce24.it", true },
{ "casa-su.casa", true },
{ "cbhq.net", true },
{ "cdlcenter.com", true },
{ "cdnb.co", true },
{ "certible.com", true },
{ "certly.io", true },
@ -242,7 +246,6 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "chatbot.me", true },
{ "check.torproject.org", false },
{ "checkout.google.com", true },
{ "chontalpa.pw", true },
{ "chrisirwin.ca", true },
{ "chrisjean.com", true },
{ "chrome-devtools-frontend.appspot.com", true },
@ -271,6 +274,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "codepx.com", true },
{ "codereview.appspot.com", false },
{ "codereview.chromium.org", true },
{ "coding.net", false },
{ "coffeeetc.co.uk", true },
{ "coinapult.com", true },
{ "coinbase.com", true },
@ -286,6 +290,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "cordial-restaurant.com", true },
{ "cotonea.de", true },
{ "courtlistener.com", true },
{ "covenantoftheriver.org", true },
{ "crm.onlime.ch", false },
{ "crowdjuris.com", true },
{ "crypto.cat", false },
@ -313,6 +318,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "danielalvarez.net", true },
{ "danonsecurity.com", true },
{ "danskoferie.dk", true },
{ "danw.io", true },
{ "daphne.informatik.uni-freiburg.de", true },
{ "darchoods.net", false },
{ "darknode.in", true },
@ -336,6 +342,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "debtkit.co.uk", true },
{ "dedimax.de", true },
{ "dee.pe", true },
{ "defcon.org", true },
{ "deliverance.co.uk", true },
{ "denh.am", true },
{ "depechemode-live.com", true },
@ -348,11 +355,12 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "diamante.ro", true },
{ "die-besten-weisheiten.de", true },
{ "diedrich.co", true },
{ "digital1st.co.uk", true },
{ "dillonkorman.com", true },
{ "dinamoelektrik.com", true },
{ "disking.co.uk", true },
{ "dist.torproject.org", false },
{ "dixmag.com", true },
{ "dixmag.com", false },
{ "dl.google.com", true },
{ "dlc.viasinc.com", true },
{ "dm.lookout.com", false },
@ -364,8 +372,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "docs.python.org", true },
{ "domainkauf.de", true },
{ "domains.google.com", true },
{ "donmez.ws", false },
{ "donmez.ws", true },
{ "donotcall.gov", true },
{ "dragons-of-highlands.cz", true },
{ "dreadbyte.com", true },
{ "dreamsforabetterworld.com.au", true },
{ "drive.google.com", true },
@ -404,6 +413,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "encrypted.google.com", true },
{ "energy-drink-magazin.de", true },
{ "enorekcah.com", true },
{ "enskat.de", true },
{ "enskatson-sippe.de", true },
{ "entropia.de", false },
{ "eromixx.com", true },
{ "erotische-aanbiedingen.nl", true },
@ -415,6 +426,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "eva.cz", true },
{ "evalesc.com", true },
{ "everhome.de", true },
{ "eveshamglass.co.uk", true },
{ "evstatus.com", true },
{ "exiahost.com", false },
{ "exon.io", true },
@ -447,11 +459,13 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "finn.io", true },
{ "firebaseio-demo.com", true },
{ "firebaseio.com", true },
{ "firebirdrangecookers.com", true },
{ "firefart.at", true },
{ "firemail.io", true },
{ "firma-offshore.com", true },
{ "firstlook.org", true },
{ "fischer-its.com", true },
{ "fitkram.cz", true },
{ "fj.simple.com", false },
{ "flagspot.net", true },
{ "flamer-scene.com", true },
@ -480,12 +494,15 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "futos.de", true },
{ "fx5.de", true },
{ "gallery44.org", true },
{ "gambit.pro", true },
{ "gambitnash.co.uk", true },
{ "gambitnash.com", true },
{ "gamercredo.com", true },
{ "garron.net", true },
{ "gavick.com", true },
{ "gaytorrent.ru", true },
{ "gc.net", true },
{ "ge3k.net", true },
{ "gemeinfreie-lieder.de", true },
{ "geoip.fedoraproject.org", true },
{ "geoip.stg.fedoraproject.org", true },
@ -543,6 +560,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "haste.ch", true },
{ "haufschild.de", true },
{ "hausverbrauch.de", true },
{ "hboeck.de", true },
{ "hda.me", true },
{ "healthcare.gov", false },
{ "heartlandrentals.com", true },
@ -574,6 +592,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "howrandom.org", true },
{ "howsmyssl.com", true },
{ "howsmytls.com", true },
{ "hozana.si", true },
{ "hpac-portal.com", true },
{ "hrackydomino.cz", true },
{ "hsmr.cc", true },
@ -603,6 +622,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "inb4.us", true },
{ "inbox.google.com", true },
{ "indiecert.net", true },
{ "indovinabank.com.vn", true },
{ "iniiter.com", true },
{ "inkbunny.net", true },
{ "inleaked.com", true },
@ -614,6 +634,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "interasistmen.se", true },
{ "ionas-law.ro", true },
{ "ipmimagazine.com", true },
{ "ipomue.com", false },
{ "ipsec.pl", true },
{ "iranianlawschool.com", true },
{ "iridiumbrowser.de", true },
{ "irische-segenswuensche.info", true },
@ -627,9 +649,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "itsamurai.ru", true },
{ "itshost.ru", true },
{ "izdiwho.com", true },
{ "j0s.at", true },
{ "jackyyf.com", false },
{ "jakub-boucek.cz", true },
{ "jamesdoylephoto.com", true },
{ "janus-engineering.de", true },
{ "jbn.mx", true },
{ "jelmer.co.uk", true },
@ -652,6 +674,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "jonathan.ir", true },
{ "jonnybarnes.uk", true },
{ "jonpads.com", true },
{ "jpbike.cz", true },
{ "jrc9.ca", true },
{ "julian-kipka.de", true },
{ "jwilsson.com", true },
@ -660,13 +683,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "kaheim.de", true },
{ "kalmar.com", true },
{ "kamikano.com", true },
{ "kaneo-gmbh.de", true },
{ "kanzashi.com", true },
{ "kardize24.pl", true },
{ "karmaspa.se", true },
{ "kartonmodellbau.org", true },
{ "kaufberatung.community", true },
{ "kdex.de", true },
{ "kdyby.org", true },
{ "kedarastudios.com", true },
{ "keeleysam.com", true },
{ "keeleysam.me", true },
{ "keepa.com", true },
@ -745,6 +769,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "lists.mayfirst.org", false },
{ "lists.stg.fedoraproject.org", true },
{ "livej.am", true },
{ "livekaarten.nl", true },
{ "ljs.io", true },
{ "lnx.li", true },
{ "lobste.rs", true },
@ -762,6 +787,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "login.yahoo.com", false },
{ "lolicore.ch", true },
{ "lookout.com", false },
{ "lookzook.com", true },
{ "ludwig.im", true },
{ "luelistan.net", true },
{ "lukonet.com", true },
@ -802,6 +828,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "markusueberallassetmanagement.de", true },
{ "marshut.net", true },
{ "massivum.de", true },
{ "masters.black", true },
{ "matatall.com", true },
{ "mathiasbynens.be", true },
{ "matteomarescotti.it", true },
@ -817,6 +844,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "md5file.com", true },
{ "mdfnet.se", false },
{ "meamod.com", true },
{ "medallia.io", true },
{ "mediacru.sh", true },
{ "medium.com", true },
{ "meetfinch.com", true },
@ -832,22 +860,25 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "miasarafina.de", true },
{ "michalspacek.cz", true },
{ "miconcinemas.com", true },
{ "micropple.net", true },
{ "mig5.net", true },
{ "mijn-email.org", true },
{ "mike-bland.com", true },
{ "miketabor.com", true },
{ "mikewest.org", true },
{ "miku.hatsune.my", false },
{ "mimeit.de", true },
{ "mimovrste.com", true },
{ "mindcoding.ro", true },
{ "mindoktor.se", true },
{ "minecraftvoter.com", true },
{ "mineover.es", true },
{ "minez-nightswatch.com", true },
{ "minikneet.com", true },
{ "minnesotadata.com", true },
{ "mironet.cz", true },
{ "mirrorx.com", true },
{ "miskatonic.org", true },
{ "miss-inventory.co.uk", true },
{ "mister.hosting", true },
{ "mitell.jp", false },
{ "mittenhacks.com", true },
@ -902,6 +933,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "nan.zone", true },
{ "narodniki.com", true },
{ "nationalpriorities.org", true },
{ "nayahe.ru", true },
{ "nbl.org.tw", true },
{ "nctx.co.uk", true },
{ "nectarleaf.com", true },
@ -918,12 +950,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "newstarnootropics.com", true },
{ "ng-security.com", true },
{ "nginxnudes.com", true },
{ "nicolaw.uk", true },
{ "nieselregen.com", true },
{ "niloxy.com", true },
{ "nmctest.net", true },
{ "nodari.com.ar", true },
{ "noemax.com", true },
{ "noobs-r-us.co.uk", true },
{ "nopex.no", true },
{ "nos-oignons.net", true },
{ "notalone.gov", true },
{ "nouvelle-vague-saint-cast.fr", true },
@ -978,6 +1012,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "partyvan.it", true },
{ "partyvan.nl", true },
{ "partyvan.se", true },
{ "passphrase.today", true },
{ "passport.yandex.by", true },
{ "passport.yandex.com", true },
{ "passport.yandex.com.tr", true },
@ -1029,6 +1064,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "pmg-offshore-company.com", true },
{ "pmg-purchase.com", true },
{ "pmg-purchase.net", true },
{ "pollpodium.nl", true },
{ "polymathematician.com", true },
{ "polypho.nyc", true },
{ "ponythread.com", true },
@ -1090,10 +1126,12 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "riccy.org", true },
{ "richiemail.net", true },
{ "ricochet.im", true },
{ "rid-wan.com", true },
{ "riesenmagnete.de", true },
{ "rika.me", true },
{ "rippleunion.com", true },
{ "rlalique.com", true },
{ "roan24.pl", true },
{ "robinadr.com", true },
{ "robteix.com", true },
{ "rodosto.com", true },
@ -1113,6 +1151,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "rubecodeberg.com", true },
{ "rubendv.be", true },
{ "rudloff.pro", true },
{ "rusadmin.biz", false },
{ "ruudkoot.nl", true },
{ "rws-vertriebsportal.de", true },
{ "s-c.se", true },
@ -1140,6 +1179,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "schreiber-netzwerk.eu", true },
{ "schwarzer.it", true },
{ "sciencex.com", true },
{ "scotthel.me", true },
{ "scotthelme.co.uk", true },
{ "scoutdb.ch", true },
{ "scrambl.is", true },
@ -1200,7 +1240,9 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "smartcoin.com.br", true },
{ "smartlend.se", true },
{ "smartship.co.jp", true },
{ "smith.is", true },
{ "snakehosting.dk", true },
{ "sneezry.com", true },
{ "snowflake.ch", false },
{ "sockeye.cc", true },
{ "soia.ca", true },
@ -1244,6 +1286,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "studienportal.eu", true },
{ "studydrive.net", true },
{ "stulda.cz", true },
{ "subeesu.com", true },
{ "subrosa.io", true },
{ "suite73.org", true },
{ "sunjaydhama.com", true },
@ -1282,11 +1325,14 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "techloaner.com", true },
{ "tegelsensanitaironline.nl", true },
{ "tekshrek.com", true },
{ "tempus-aquilae.de", true },
{ "tent.io", true },
{ "terraelectronica.ru", true },
{ "terraweb.net", true },
{ "terrty.net", true },
{ "testsuite.org", true },
{ "texte-zur-taufe.de", true },
{ "theamp.com", true },
{ "thebimhub.com", true },
{ "thecustomizewindows.com", true },
{ "theescapistswiki.com", true },
@ -1295,7 +1341,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "therapynotes.com", true },
{ "therapyportal.com", true },
{ "theshadestore.com", true },
{ "thetomharling.com", true },
{ "theunitedstates.io", true },
{ "thomastimepieces.com.au", true },
{ "thusoy.com", true },
{ "thyngster.com", false },
@ -1317,8 +1363,8 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "todoist.com", true },
{ "tollmanz.com", true },
{ "tomfisher.eu", true },
{ "tomharling.co.uk", true },
{ "tomharling.uk", true },
{ "tomrichards.net", true },
{ "tomvote.com", true },
{ "toner24.at", true },
{ "toner24.co.uk", true },
@ -1355,8 +1401,10 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "tresorit.com", true },
{ "tribut.de", true },
{ "tucuxi.org", true },
{ "tuitle.com", true },
{ "tunebitfm.de", true },
{ "tuturulianda.com", true },
{ "tuxplace.nl", true },
{ "twentymilliseconds.com", true },
{ "twisto.cz", true },
{ "twitter.com", false },
@ -1383,6 +1431,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "utilityapi.com", true },
{ "utleieplassen.no", true },
{ "vaddder.com", true },
{ "vechkasov.ru", true },
{ "vhost.co.id", true },
{ "viasinc.com", false },
{ "vijos.org", true },
@ -1396,6 +1445,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "vrobert.fr", false },
{ "w-spotlight.appspot.com", true },
{ "wallet.google.com", true },
{ "walnutgaming.co.uk", true },
{ "walnutgaming.com", true },
{ "warrencreative.com", false },
{ "watsonhall.uk", true },
@ -1515,6 +1565,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "xps2pdf.co.uk", true },
{ "xuntier.ch", true },
{ "y-o-w.com", true },
{ "yafuoku.ru", true },
{ "yahvehyireh.com", true },
{ "yanovich.net", true },
{ "yaporn.tv", false },
@ -1522,6 +1573,7 @@ static const nsSTSPreload kSTSPreloadList[] = {
{ "yksityisyydensuoja.fi", true },
{ "yokeepo.com", true },
{ "yorcom.nl", true },
{ "youdowell.com", true },
{ "yoursecondphone.co", true },
{ "ypart.eu", true },
{ "z.ai", true },

View File

@ -6,6 +6,7 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/ClientID.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-common/utils.js");
@ -65,13 +66,6 @@ this.DataReportingService = function () {
this._os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
this._clientID = null;
this._loadClientIdTask = null;
this._saveClientIdTask = null;
this._stateDir = null;
this._stateFilePath = null;
// Used for testing only, when true results in getSessionRecorder() returning
// undefined. Controlled via simulate* methods.
this._simulateNoSessionRecorder = false;
@ -140,9 +134,6 @@ DataReportingService.prototype = Object.freeze({
let policyPrefs = new Preferences(POLICY_BRANCH);
this.policy = new DataReportingPolicy(policyPrefs, this._prefs, this);
this._stateDir = OS.Path.join(OS.Constants.Path.profileDir, "datareporting");
this._stateFilePath = OS.Path.join(this._stateDir, "state.json");
this._os.addObserver(this, "sessionstore-windows-restored", true);
} catch (ex) {
Cu.reportError("Exception when initializing data reporting service: " +
@ -302,68 +293,6 @@ DataReportingService.prototype = Object.freeze({
}.bind(this));
},
_loadClientID: function () {
if (this._loadClientIdTask) {
return this._loadClientIdTask;
}
this._loadClientIdTask = Task.spawn(function* () {
// Previously we had the stable client ID managed in FHR.
// As we want to start correlating FHR and telemetry data (and moving towards
// unifying the two), we moved the ID management to the datareporting
// service. Consequently, we try to import the FHR ID first, so we can keep
// using it.
// Try to load the client id from the DRS state file first.
try {
let state = yield CommonUtils.readJSON(this._stateFilePath);
if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
this._clientID = state.clientID;
this._loadClientIdTask = null;
return this._clientID;
}
} catch (e) {
// fall through to next option
}
// If we dont have DRS state yet, try to import from the FHR state.
try {
let fhrStatePath = OS.Path.join(OS.Constants.Path.profileDir, "healthreport", "state.json");
let state = yield CommonUtils.readJSON(fhrStatePath);
if (state && 'clientID' in state && typeof(state.clientID) == 'string') {
this._clientID = state.clientID;
this._loadClientIdTask = null;
this._saveClientID();
return this._clientID;
}
} catch (e) {
// fall through to next option
}
// We dont have an id from FHR yet, generate a new ID.
this._clientID = CommonUtils.generateUUID();
this._loadClientIdTask = null;
this._saveClientIdTask = this._saveClientID();
// Wait on persisting the id. Otherwise failure to save the ID would result in
// the client creating and subsequently sending multiple IDs to the server.
// This would appear as multiple clients submitting similar data, which would
// result in orphaning.
yield this._saveClientIdTask;
return this._clientID;
}.bind(this));
return this._loadClientIdTask;
},
_saveClientID: Task.async(function* () {
let obj = { clientID: this._clientID };
yield OS.File.makeDir(this._stateDir);
yield CommonUtils.writeJSON(obj, this._stateFilePath);
this._saveClientIdTask = null;
}),
/**
* This returns a promise resolving to the the stable client ID we use for
* data reporting (FHR & Telemetry). Previously exising FHR client IDs are
@ -372,11 +301,7 @@ DataReportingService.prototype = Object.freeze({
* @return Promise<string> The stable client ID.
*/
getClientID: function() {
if (!this._clientID) {
return this._loadClientID();
}
return Promise.resolve(this._clientID);
return ClientID.getClientID();
},
/**
@ -385,14 +310,7 @@ DataReportingService.prototype = Object.freeze({
* @return Promise<string> The new client ID.
*/
resetClientID: Task.async(function* () {
yield this._loadClientIdTask;
yield this._saveClientIdTask;
this._clientID = CommonUtils.generateUUID();
this._saveClientIdTask = this._saveClientID();
yield this._saveClientIdTask;
return this._clientID;
return ClientID.resetClientID();
}),
/**
@ -413,15 +331,6 @@ DataReportingService.prototype = Object.freeze({
simulateRestoreSessionRecorder() {
this._simulateNoSessionRecorder = false;
},
/*
* Simulate a restart of the service. This is for testing only.
*/
_reset: Task.async(function* () {
yield this._loadClientIdTask;
yield this._saveClientIdTask;
this._clientID = null;
}),
});
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataReportingService]);

View File

@ -5,4 +5,3 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_policy.js]
[test_session_recorder.js]
[test_client_id.js]

View File

@ -45,6 +45,7 @@ let publicProperties = [
"now",
"promiseAccountsForceSigninURI",
"promiseAccountsChangeProfileURI",
"removeCachedOAuthToken",
"resendVerificationEmail",
"setSignedInUser",
"signOut",
@ -70,17 +71,24 @@ let publicProperties = [
// }
// If the state has changed between the function being called and the promise
// being resolved, the .resolve() call will actually be rejected.
let AccountState = function(fxaInternal) {
let AccountState = function(fxaInternal, signedInUserStorage, accountData = null) {
this.fxaInternal = fxaInternal;
this.signedInUserStorage = signedInUserStorage;
this.signedInUser = accountData ? {version: DATA_FORMAT_VERSION, accountData} : null;
this.uid = accountData ? accountData.uid : null;
this.oauthTokens = {};
};
AccountState.prototype = {
cert: null,
keyPair: null,
signedInUser: null,
oauthTokens: null,
whenVerifiedDeferred: null,
whenKeysReadyDeferred: null,
profile: null,
promiseInitialAccountData: null,
uid: null,
get isCurrent() this.fxaInternal && this.fxaInternal.currentAccountState === this,
@ -100,6 +108,7 @@ AccountState.prototype = {
this.cert = null;
this.keyPair = null;
this.signedInUser = null;
this.uid = null;
this.fxaInternal = null;
this.initProfilePromise = null;
@ -109,46 +118,113 @@ AccountState.prototype = {
}
},
getUserAccountData: function() {
// Skip disk if user is cached.
// Clobber all cached data and write that empty data to storage.
signOut() {
this.cert = null;
this.keyPair = null;
this.signedInUser = null;
this.oauthTokens = {};
this.uid = null;
return this.persistUserData();
},
getUserAccountData() {
if (!this.isCurrent) {
return this.reject(new Error("Another user has signed in"));
}
if (this.promiseInitialAccountData) {
// We are still reading the data for the first and only time.
return this.promiseInitialAccountData;
}
// We've previously read it successfully (and possibly updated it since)
if (this.signedInUser) {
return this.resolve(this.signedInUser.accountData);
}
return this.fxaInternal.signedInUserStorage.get().then(
user => {
// We fetch the signedInUser data first, then fetch the token store and
// ensure the uid in the tokens matches our user.
let accountData = null;
let oauthTokens = {};
return this.promiseInitialAccountData = this.signedInUserStorage.get()
.then(user => {
if (logPII) {
// don't stringify unless it will be written. We should replace this
// check with param substitutions added in bug 966674
log.debug("getUserAccountData -> " + JSON.stringify(user));
log.debug("getUserAccountData", user);
}
if (user && user.version == this.version) {
log.debug("setting signed in user");
this.signedInUser = user;
}
return this.resolve(user ? user.accountData : null);
},
err => {
// In an ideal world we could cache the data in this.signedInUser, but
// if we do, the interaction with the login manager breaks when the
// password is locked as this read may only have obtained partial data.
// Therefore every read *must* really read incase the login manager is
// now unlocked. We could fix this with a refactor...
accountData = user ? user.accountData : null;
}, err => {
// Error reading signed in user account data.
this.promiseInitialAccountData = null;
if (err instanceof OS.File.Error && err.becauseNoSuchFile) {
// File hasn't been created yet. That will be done
// on the first call to getSignedInUser
return this.resolve(null);
// on the first call to setSignedInUser
return;
}
return this.reject(err);
}
);
// something else went wrong - report the error but continue without
// user data.
log.error("Failed to read signed in user data", err);
}).then(() => {
if (!accountData) {
return null;
}
return this.signedInUserStorage.getOAuthTokens();
}).then(tokenData => {
if (tokenData && tokenData.tokens &&
tokenData.version == DATA_FORMAT_VERSION &&
tokenData.uid == accountData.uid ) {
oauthTokens = tokenData.tokens;
}
}, err => {
// Error reading the OAuth tokens file.
if (err instanceof OS.File.Error && err.becauseNoSuchFile) {
// File hasn't been created yet, but will be when tokens are saved.
return;
}
log.error("Failed to read oauth tokens", err)
}).then(() => {
// We are done - clear our promise and save the data if we are still
// current.
this.promiseInitialAccountData = null;
if (this.isCurrent) {
// As above, we can not cache the data to this.signedInUser as we
// may only have partial data due to a locked MP, so the next
// request must re-read incase it is now unlocked.
// But we do save the tokens and the uid
this.oauthTokens = oauthTokens;
this.uid = accountData ? accountData.uid : null;
}
return accountData;
});
// phew!
},
// XXX - this should really be called "updateCurrentUserData" or similar as
// it is only ever used to add new fields to the *current* user, not to
// set a new user as current.
setUserAccountData: function(accountData) {
return this.fxaInternal.signedInUserStorage.get().then(record => {
if (!this.isCurrent) {
return this.reject(new Error("Another user has signed in"));
}
record.accountData = accountData;
this.signedInUser = record;
return this.fxaInternal.signedInUserStorage.set(record)
if (!this.isCurrent) {
return this.reject(new Error("Another user has signed in"));
}
if (this.promiseInitialAccountData) {
throw new Error("Can't set account data before it's been read.");
}
if (!accountData) {
// see above - this should really be called "updateCurrentUserData" or similar.
throw new Error("Attempt to use setUserAccountData with null user data.");
}
if (accountData.uid != this.uid) {
// see above - this should really be called "updateCurrentUserData" or similar.
throw new Error("Attempt to use setUserAccountData with a different user.");
}
// Set our signedInUser before we start the write, so any updates to the
// data while the write completes are still captured.
this.signedInUser = {version: DATA_FORMAT_VERSION, accountData: accountData};
return this.signedInUserStorage.set(this.signedInUser)
.then(() => this.resolve(accountData));
});
},
@ -276,7 +352,107 @@ AccountState.prototype = {
return Promise.reject(error);
},
};
// Abstractions for storage of cached tokens - these are all sync, and don't
// handle revocation etc - it's just storage.
// A preamble for the cache helpers...
_cachePreamble() {
if (!this.isCurrent) {
throw new Error("Another user has signed in");
}
},
// Set a cached token. |tokenData| must have a 'token' element, but may also
// have additional fields (eg, it probably specifies the server to revoke
// from). The 'get' functions below return the entire |tokenData| value.
setCachedToken(scopeArray, tokenData) {
this._cachePreamble();
if (!tokenData.token) {
throw new Error("No token");
}
let key = getScopeKey(scopeArray);
this.oauthTokens[key] = tokenData;
// And a background save...
this._persistCachedTokens();
},
// Return data for a cached token or null (or throws on bad state etc)
getCachedToken(scopeArray) {
this._cachePreamble();
let key = getScopeKey(scopeArray);
if (this.oauthTokens[key]) {
// later we might want to check an expiry date - but we currently
// have no such concept, so just return it.
log.trace("getCachedToken returning cached token");
return this.oauthTokens[key];
}
return null;
},
// Get an array of tokenData for all cached tokens.
getAllCachedTokens() {
this._cachePreamble();
let result = [];
for (let [key, tokenValue] in Iterator(this.oauthTokens)) {
result.push(tokenValue);
}
return result;
},
// Remove a cached token from the cache. Does *not* revoke it from anywhere.
// Returns the entire token entry if found, null otherwise.
removeCachedToken(token) {
this._cachePreamble();
let data = this.oauthTokens;
for (let [key, tokenValue] in Iterator(data)) {
if (tokenValue.token == token) {
delete data[key];
// And a background save...
this._persistCachedTokens();
return tokenValue;
}
}
return null;
},
// A hook-point for tests. Returns a promise that's ignored in most cases
// (notable exceptions are tests and when we explicitly are saving the entire
// set of user data.)
_persistCachedTokens() {
this._cachePreamble();
let record;
if (this.uid) {
record = {
version: DATA_FORMAT_VERSION,
uid: this.uid,
tokens: this.oauthTokens,
};
} else {
record = null;
}
return this.signedInUserStorage.setOAuthTokens(record).catch(
err => {
log.error("Failed to save account data for token cache", err);
}
);
},
persistUserData() {
return this._persistCachedTokens().catch(err => {
log.error("Failed to persist cached tokens", err);
}).then(() => {
return this.signedInUserStorage.set(this.signedInUser);
}).catch(err => {
log.error("Failed to persist account data", err);
});
},
}
/* Given an array of scopes, make a string key by normalizing. */
function getScopeKey(scopeArray) {
let normalizedScopes = scopeArray.map(item => item.toLowerCase());
return normalizedScopes.sort().join("|");
}
/**
* Copies properties from a given object to another object.
@ -336,6 +512,11 @@ this.FxAccounts = function (mockInternal) {
}
if (mockInternal) {
// A little work-around to ensure the initial currentAccountState has
// the same mock storage the test passed in.
if (mockInternal.signedInUserStorage) {
internal.currentAccountState.signedInUserStorage = mockInternal.signedInUserStorage;
}
// Exposes the internal object for testing only.
external.internal = internal;
}
@ -352,6 +533,28 @@ function FxAccountsInternal() {
// Make a local copy of this constant so we can mock it in testing
this.POLL_SESSION = POLL_SESSION;
// The one and only "storage" object. While this is created here, the
// FxAccountsInternal object does *not* use it directly, but instead passes
// it to AccountState objects which has sole responsibility for storage.
// Ideally we would create it in the AccountState objects, but that makes
// testing hard as AccountState objects are regularly created and thrown
// away. Doing it this way means tests can mock/replace this storage object
// and have it used by all AccountState objects, even those created before
// and after the mock has been setup.
// We only want the fancy LoginManagerStorage on desktop.
#if defined(MOZ_B2G)
this.signedInUserStorage = new JSONStorage({
#else
this.signedInUserStorage = new LoginManagerStorage({
#endif
// We don't reference |profileDir| in the top-level module scope
// as we may be imported before we know where it is.
filename: DEFAULT_STORAGE_FILENAME,
oauthTokensFilename: DEFAULT_OAUTH_TOKENS_FILENAME,
baseDir: OS.Constants.Path.profileDir,
});
// We interact with the Firefox Accounts auth server in order to confirm that
// a user's email has been verified and also to fetch the user's keys from
// the server. We manage these processes in possibly long-lived promises
@ -363,19 +566,7 @@ function FxAccountsInternal() {
// currentAccountState are used for this purpose.
// (XXX - should the timer be directly on the currentAccountState?)
this.currentTimer = null;
this.currentAccountState = new AccountState(this);
// We don't reference |profileDir| in the top-level module scope
// as we may be imported before we know where it is.
// We only want the fancy new LoginManagerStorage on desktop.
#if defined(MOZ_B2G)
this.signedInUserStorage = new JSONStorage({
#else
this.signedInUserStorage = new LoginManagerStorage({
#endif
filename: DEFAULT_STORAGE_FILENAME,
baseDir: OS.Constants.Path.profileDir,
});
this.currentAccountState = new AccountState(this, this.signedInUserStorage);
}
/**
@ -509,19 +700,22 @@ FxAccountsInternal.prototype = {
log.debug("setSignedInUser - aborting any existing flows");
this.abortExistingFlow();
let record = {version: this.version, accountData: credentials};
let currentState = this.currentAccountState;
// Cache a clone of the credentials object.
currentState.signedInUser = JSON.parse(JSON.stringify(record));
let currentAccountState = this.currentAccountState = new AccountState(
this,
this.signedInUserStorage,
JSON.parse(JSON.stringify(credentials)) // Pass a clone of the credentials object.
);
// This promise waits for storage, but not for verification.
// We're telling the caller that this is durable now.
return this.signedInUserStorage.set(record).then(() => {
return currentAccountState.persistUserData().then(() => {
this.notifyObservers(ONLOGIN_NOTIFICATION);
if (!this.isUserEmailVerified(credentials)) {
this.startVerifiedCheck(credentials);
}
}).then(result => currentState.resolve(result));
}).then(() => {
return currentAccountState.resolve();
});
},
/**
@ -578,7 +772,7 @@ FxAccountsInternal.prototype = {
this.currentTimer = 0;
}
this.currentAccountState.abort();
this.currentAccountState = new AccountState(this);
this.currentAccountState = new AccountState(this, this.signedInUserStorage);
},
accountStatus: function accountStatus() {
@ -590,12 +784,31 @@ FxAccountsInternal.prototype = {
});
},
_destroyOAuthToken: function(tokenData) {
let client = new FxAccountsOAuthGrantClient({
serverURL: tokenData.server,
client_id: FX_OAUTH_CLIENT_ID
});
return client.destroyToken(tokenData.token)
},
_destroyAllOAuthTokens: function(tokenInfos) {
// let's just destroy them all in parallel...
let promises = [];
for (let tokenInfo of tokenInfos) {
promises.push(this._destroyOAuthToken(tokenInfo));
}
return Promise.all(promises);
},
signOut: function signOut(localOnly) {
let currentState = this.currentAccountState;
let sessionToken;
let tokensToRevoke;
return currentState.getUserAccountData().then(data => {
// Save the session token for use in the call to signOut below.
sessionToken = data && data.sessionToken;
tokensToRevoke = currentState.getAllCachedTokens();
return this._signOutLocal();
}).then(() => {
// FxAccountsManager calls here, then does its own call
@ -608,8 +821,15 @@ FxAccountsInternal.prototype = {
// the user from signing out. The server must tolerate
// clients just disappearing, so this call should be best effort.
return this._signOutServer(sessionToken);
}).then(null, err => {
log.error("Error during remote sign out of Firefox Accounts: " + err);
}).catch(err => {
log.error("Error during remote sign out of Firefox Accounts", err);
}).then(() => {
return this._destroyAllOAuthTokens(tokensToRevoke);
}).catch(err => {
log.error("Error during destruction of oauth tokens during signout", err);
}).then(() => {
// just for testing - notifications are cheap when no observers.
this.notifyObservers("testhelper-fxa-signout-complete");
});
}
}).then(() => {
@ -622,9 +842,10 @@ FxAccountsInternal.prototype = {
* signOut via FxAccountsClient.
*/
_signOutLocal: function signOutLocal() {
this.abortExistingFlow();
this.currentAccountState.signedInUser = null; // clear in-memory cache
return this.signedInUserStorage.set(null);
let currentAccountState = this.currentAccountState;
return currentAccountState.signOut().then(() => {
this.abortExistingFlow(); // this resets this.currentAccountState.
});
},
_signOutServer: function signOutServer(sessionToken) {
@ -995,7 +1216,9 @@ FxAccountsInternal.prototype = {
*
* @param options
* {
* scope: (string) the oauth scope being requested
* scope: (string/array) the oauth scope(s) being requested. As a
* convenience, you may pass a string if only one scope is
* required, or an array of strings if multiple are needed.
* }
*
* @return Promise.<string | Error>
@ -1008,46 +1231,107 @@ FxAccountsInternal.prototype = {
* AUTH_ERROR
* UNKNOWN_ERROR
*/
getOAuthToken: function (options = {}) {
getOAuthToken: Task.async(function* (options = {}) {
log.debug("getOAuthToken enter");
if (!options.scope) {
return this._error(ERROR_INVALID_PARAMETER, "Missing 'scope' option");
let scope = options.scope;
if (typeof scope === "string") {
scope = [scope];
}
let oAuthURL = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.oauth.uri");
if (!scope || !scope.length) {
throw this._error(ERROR_INVALID_PARAMETER, "Missing or invalid 'scope' option");
}
yield this._getVerifiedAccountOrReject();
// Early exit for a cached token.
let currentState = this.currentAccountState;
let cached = currentState.getCachedToken(scope);
if (cached) {
log.debug("getOAuthToken returning a cached token");
return cached.token;
}
// We are going to hit the server - this is the string we pass to it.
let scopeString = scope.join(" ");
let client = options.client;
if (!client) {
try {
let defaultURL = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.oauth.uri");
client = new FxAccountsOAuthGrantClient({
serverURL: oAuthURL,
serverURL: defaultURL,
client_id: FX_OAUTH_CLIENT_ID
});
} catch (e) {
return this._error(ERROR_INVALID_PARAMETER, e);
throw this._error(ERROR_INVALID_PARAMETER, e);
}
}
let oAuthURL = client.serverURL.href;
return this._getVerifiedAccountOrReject()
.then(() => this.getAssertion(oAuthURL))
.then(assertion => client.getTokenFromAssertion(assertion, options.scope))
.then(result => result.access_token)
.then(null, err => this._errorToErrorClass(err));
},
try {
log.debug("getOAuthToken fetching new token from", oAuthURL);
let assertion = yield this.getAssertion(oAuthURL);
let result = yield client.getTokenFromAssertion(assertion, scopeString);
let token = result.access_token;
// If we got one, cache it.
if (token) {
let entry = {token: token, server: oAuthURL};
// But before we do, check the cache again - if we find one now, it
// means someone else concurrently requested the same scope and beat
// us to the cache write. To be nice to the server, we revoke the one
// we just got and return the newly cached value.
let cached = currentState.getCachedToken(scope);
if (cached) {
log.debug("Detected a race for this token - revoking the new one.");
this._destroyOAuthToken(entry);
return cached.token;
}
currentState.setCachedToken(scope, entry);
}
return token;
} catch (err) {
throw this._errorToErrorClass(err);
}
}),
_getVerifiedAccountOrReject: function () {
return this.currentAccountState.getUserAccountData().then(data => {
if (!data) {
// No signed-in user
return this._error(ERROR_NO_ACCOUNT);
}
if (!this.isUserEmailVerified(data)) {
// Signed-in user has not verified email
return this._error(ERROR_UNVERIFIED_ACCOUNT);
}
});
},
/**
* Remove an OAuth token from the token cache. Callers should call this
* after they determine a token is invalid, so a new token will be fetched
* on the next call to getOAuthToken().
*
* @param options
* {
* token: (string) A previously fetched token.
* }
* @return Promise.<undefined> This function will always resolve, even if
* an unknown token is passed.
*/
removeCachedOAuthToken: Task.async(function* (options) {
if (!options.token || typeof options.token !== "string") {
throw this._error(ERROR_INVALID_PARAMETER, "Missing or invalid 'token' option");
}
let currentState = this.currentAccountState;
let existing = currentState.removeCachedToken(options.token);
if (existing) {
// background destroy.
this._destroyOAuthToken(existing).catch(err => {
log.warn("FxA failed to revoke a cached token", err);
});
}
}),
_getVerifiedAccountOrReject: Task.async(function* () {
let data = yield this.currentAccountState.getUserAccountData();
if (!data) {
// No signed-in user
throw this._error(ERROR_NO_ACCOUNT);
}
if (!this.isUserEmailVerified(data)) {
// Signed-in user has not verified email
throw this._error(ERROR_UNVERIFIED_ACCOUNT);
}
}),
/*
* Coerce an error into one of the general error cases:
@ -1068,7 +1352,7 @@ FxAccountsInternal.prototype = {
(aError.message === "INVALID_PARAMETER" ||
aError.message === "NO_ACCOUNT" ||
aError.message === "UNVERIFIED_ACCOUNT")) {
return Promise.reject(aError);
return aError;
}
return this._error(ERROR_UNKNOWN, aError);
},
@ -1079,7 +1363,7 @@ FxAccountsInternal.prototype = {
if (aDetails) {
reason.details = aDetails;
}
return Promise.reject(reason);
return reason;
},
/**
@ -1115,7 +1399,7 @@ FxAccountsInternal.prototype = {
log.error("Could not retrieve profile data", error);
return accountState.reject(error);
})
.then(null, err => this._errorToErrorClass(err));
.then(null, err => Promise.reject(this._errorToErrorClass(err)));
},
};
@ -1133,6 +1417,7 @@ FxAccountsInternal.prototype = {
function JSONStorage(options) {
this.baseDir = options.baseDir;
this.path = OS.Path.join(options.baseDir, options.filename);
this.oauthTokensPath = OS.Path.join(options.baseDir, options.oauthTokensFilename);
};
JSONStorage.prototype = {
@ -1143,7 +1428,17 @@ JSONStorage.prototype = {
get: function() {
return CommonUtils.readJSON(this.path);
}
},
setOAuthTokens: function(contents) {
return OS.File.makeDir(this.baseDir, {ignoreExisting: true})
.then(CommonUtils.writeJSON.bind(null, contents, this.oauthTokensPath));
},
getOAuthTokens: function(contents) {
return CommonUtils.readJSON(this.oauthTokensPath);
},
};
/**
@ -1332,6 +1627,16 @@ LoginManagerStorage.prototype = {
return data;
}),
// OAuth tokens are always written to disk, so delegate to our JSON storage.
// (Bug 1013064 comments 23-25 explain why we save the sessionToken into the
// plain JSON file, and the same logic applies for oauthTokens being in JSON)
getOAuthTokens() {
return this.jsonStorage.getOAuthTokens();
},
setOAuthTokens(contents) {
return this.jsonStorage.setOAuthTokens(contents);
},
}
// A getter for the instance to export

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