mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to central, a=merge
This commit is contained in:
commit
3e0ec8b89f
@ -128,10 +128,6 @@
|
||||
<description class="identity-popup-warning-yellow"
|
||||
when-ciphers="weak">&identity.description.weakCipher2;</description>
|
||||
|
||||
<!-- More Security Information -->
|
||||
<button label="&identity.moreInfoLinkText2;"
|
||||
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
|
||||
|
||||
<!-- Active Mixed Content Blocked -->
|
||||
<description class="identity-popup-warning-gray"
|
||||
when-mixedcontent="active-blocked">&identity.description.activeBlocked; <label observes="identity-popup-mcb-learn-more"/></description>
|
||||
@ -159,6 +155,10 @@
|
||||
label="&identity.enableMixedContentBlocking.label;"
|
||||
accesskey="&identity.enableMixedContentBlocking.accesskey;"
|
||||
oncommand="gIdentityHandler.enableMixedContentProtection()"/>
|
||||
|
||||
<!-- More Security Information -->
|
||||
<button label="&identity.moreInfoLinkText2;"
|
||||
oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
|
||||
</vbox>
|
||||
|
||||
</panelview>
|
||||
|
@ -980,7 +980,7 @@ AnimationsTimeline.prototype = {
|
||||
createNode({
|
||||
parent: iterations,
|
||||
attributes: {
|
||||
"class": "delay",
|
||||
"class": "delay" + (delay < 0 ? " negative" : ""),
|
||||
"style": `left:-${x}px;
|
||||
width:${w}px;`
|
||||
}
|
||||
|
@ -5,11 +5,14 @@ support-files =
|
||||
doc_body_animation.html
|
||||
doc_frame_script.js
|
||||
doc_modify_playbackRate.html
|
||||
doc_negative_animation.html
|
||||
doc_simple_animation.html
|
||||
head.js
|
||||
|
||||
[browser_animation_controller_exposes_document_currentTime.js]
|
||||
[browser_animation_empty_on_invalid_nodes.js]
|
||||
[browser_animation_iterationCount_hidden_by_default.js]
|
||||
[browser_animation_mutations_with_same_names.js]
|
||||
[browser_animation_panel_exists.js]
|
||||
[browser_animation_participate_in_inspector_update.js]
|
||||
[browser_animation_play_pause_button.js]
|
||||
|
@ -0,0 +1,43 @@
|
||||
/* 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 controller provides the document.timeline currentTime (at least
|
||||
// the last known version since new animations were added).
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel, controller} = yield openAnimationInspectorNewUI();
|
||||
|
||||
ok(controller.documentCurrentTime, "The documentCurrentTime getter exists");
|
||||
checkDocumentTimeIsCorrect(controller);
|
||||
let time1 = controller.documentCurrentTime;
|
||||
|
||||
yield startNewAnimation(controller, panel);
|
||||
checkDocumentTimeIsCorrect(controller);
|
||||
let time2 = controller.documentCurrentTime;
|
||||
ok(time2 > time1, "The new documentCurrentTime is higher than the old one");
|
||||
});
|
||||
|
||||
function checkDocumentTimeIsCorrect(controller) {
|
||||
let time = 0;
|
||||
for (let {state} of controller.animationPlayers) {
|
||||
time = Math.max(time, state.documentCurrentTime);
|
||||
}
|
||||
is(controller.documentCurrentTime, time,
|
||||
"The documentCurrentTime is correct");
|
||||
}
|
||||
|
||||
function* startNewAnimation(controller, panel) {
|
||||
info("Add a new animation to the page and check the time again");
|
||||
let onPlayerAdded = controller.once(controller.PLAYERS_UPDATED_EVENT);
|
||||
yield executeInContent("devtools:test:setAttribute", {
|
||||
selector: ".still",
|
||||
attributeName: "class",
|
||||
attributeValue: "ball still short"
|
||||
});
|
||||
yield onPlayerAdded;
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/* 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";
|
||||
|
||||
// Check that when animations are added later (through animation mutations) and
|
||||
// if these animations have the same names, then all of them are still being
|
||||
// displayed (which should be true as long as these animations apply to
|
||||
// different nodes).
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_negative_animation.html");
|
||||
let {controller, panel} = yield openAnimationInspectorNewUI();
|
||||
|
||||
info("Wait until all animations have been added " +
|
||||
"(they're added with setTimeout)");
|
||||
while (controller.animationPlayers.length < 3) {
|
||||
yield controller.once(controller.PLAYERS_UPDATED_EVENT);
|
||||
}
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
is(panel.animationsTimelineComponent.animations.length, 3,
|
||||
"The timeline shows 3 animations too");
|
||||
|
||||
// Reduce the known nodeFronts to a set to make them unique.
|
||||
let nodeFronts = new Set(panel.animationsTimelineComponent
|
||||
.targetNodes.map(n => n.nodeFront));
|
||||
is(nodeFronts.size, 3,
|
||||
"The animations are applied to 3 different node fronts");
|
||||
});
|
@ -20,10 +20,11 @@ add_task(function*() {
|
||||
|
||||
ok(!timeline.hasAttribute("disabled"), "The timeline input[range] is enabled");
|
||||
ok(widget.setCurrentTime, "The widget has the setCurrentTime method");
|
||||
ok(widget.player.setCurrentTime, "The associated player front has the setCurrentTime method");
|
||||
ok(widget.player.setCurrentTime,
|
||||
"The associated player front has the setCurrentTime method");
|
||||
|
||||
info("Faking an older server version by setting " +
|
||||
"AnimationsController.traits.hasSetCurrentTime to false");
|
||||
"AnimationsController.traits.hasSetCurrentTime to false");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
controller.traits.hasSetCurrentTime = false;
|
||||
@ -35,7 +36,4 @@ add_task(function*() {
|
||||
timeline = widget.currentTimeEl;
|
||||
|
||||
ok(timeline.hasAttribute("disabled"), "The timeline input[range] is disabled");
|
||||
|
||||
yield selectNode("body", inspector);
|
||||
controller.traits.hasSetCurrentTime = true;
|
||||
});
|
||||
|
@ -47,6 +47,7 @@ function* testRefreshOnRemove(inspector, panel) {
|
||||
attributeValue: "ball short test-node"
|
||||
});
|
||||
yield onPanelUpdated;
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
assertAnimationsDisplayed(panel, 1);
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel} = yield openAnimationInspectorNewUI();
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
let timeline = panel.animationsTimelineComponent;
|
||||
let scrubberEl = timeline.scrubberEl;
|
||||
|
@ -11,7 +11,6 @@ add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
|
||||
let {panel} = yield openAnimationInspectorNewUI();
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
let timeline = panel.animationsTimelineComponent;
|
||||
let win = timeline.win;
|
||||
@ -20,17 +19,17 @@ add_task(function*() {
|
||||
|
||||
info("Mousedown in the header to move the scrubber");
|
||||
EventUtils.synthesizeMouse(timeHeaderEl, 50, 1, {type: "mousedown"}, win);
|
||||
let newPos = parseInt(scrubberEl.style.left);
|
||||
let newPos = parseInt(scrubberEl.style.left, 10);
|
||||
is(newPos, 50, "The scrubber moved on mousedown");
|
||||
|
||||
info("Continue moving the mouse and verify that the scrubber tracks it");
|
||||
EventUtils.synthesizeMouse(timeHeaderEl, 100, 1, {type: "mousemove"}, win);
|
||||
newPos = parseInt(scrubberEl.style.left);
|
||||
newPos = parseInt(scrubberEl.style.left, 10);
|
||||
is(newPos, 100, "The scrubber followed the mouse");
|
||||
|
||||
info("Release the mouse and move again and verify that the scrubber stays");
|
||||
EventUtils.synthesizeMouse(timeHeaderEl, 100, 1, {type: "mouseup"}, win);
|
||||
EventUtils.synthesizeMouse(timeHeaderEl, 200, 1, {type: "mousemove"}, win);
|
||||
newPos = parseInt(scrubberEl.style.left);
|
||||
newPos = parseInt(scrubberEl.style.left, 10);
|
||||
is(newPos, 100, "The scrubber stopped following the mouse");
|
||||
});
|
||||
|
@ -12,15 +12,10 @@
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
|
||||
let {panel} = yield openAnimationInspectorNewUI();
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
let timeline = panel.animationsTimelineComponent;
|
||||
let win = timeline.win;
|
||||
let timeHeaderEl = timeline.timeHeaderEl;
|
||||
let scrubberEl = timeline.scrubberEl;
|
||||
|
||||
let startPos = scrubberEl.getBoundingClientRect().left;
|
||||
|
||||
info("Wait for some time to check that the scrubber moves");
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
// Check that animation delay is visualized in the timeline-based UI when the
|
||||
// animation is delayed.
|
||||
// Also check that negative delays do not overflow the UI, and are shown like
|
||||
// positive delays.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
@ -13,18 +15,38 @@ add_task(function*() {
|
||||
|
||||
info("Selecting a delayed animated node");
|
||||
yield selectNode(".delayed", inspector);
|
||||
|
||||
info("Getting the animation and delay elements from the panel");
|
||||
let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
|
||||
let delay = timelineEl.querySelector(".delay");
|
||||
|
||||
ok(delay, "The animation timeline contains the delay element");
|
||||
checkDelayAndName(timelineEl, true);
|
||||
|
||||
info("Selecting a no-delay animated node");
|
||||
yield selectNode(".animated", inspector);
|
||||
checkDelayAndName(timelineEl, false);
|
||||
|
||||
info("Getting the animation and delay elements from the panel again");
|
||||
delay = timelineEl.querySelector(".delay");
|
||||
|
||||
ok(!delay, "The animation timeline contains no delay element");
|
||||
info("Selecting a negative-delay animated node");
|
||||
yield selectNode(".negative-delay", inspector);
|
||||
checkDelayAndName(timelineEl, true);
|
||||
});
|
||||
|
||||
function checkDelayAndName(timelineEl, hasDelay) {
|
||||
let delay = timelineEl.querySelector(".delay");
|
||||
|
||||
is(!!delay, hasDelay, "The timeline " +
|
||||
(hasDelay ? "contains" : "does not contain") +
|
||||
" a delay element, as expected");
|
||||
|
||||
if (hasDelay) {
|
||||
let name = timelineEl.querySelector(".name");
|
||||
let targetNode = timelineEl.querySelector(".target");
|
||||
|
||||
// Check that the delay element does not cause the timeline to overflow.
|
||||
let delayRect = delay.getBoundingClientRect();
|
||||
let sidebarWidth = targetNode.getBoundingClientRect().width;
|
||||
ok(delayRect.x >= sidebarWidth,
|
||||
"The delay element isn't displayed over the sidebar");
|
||||
|
||||
// Check that the delay is not displayed on top of the name.
|
||||
let nameLeft = name.getBoundingClientRect().left;
|
||||
ok(delayRect.right <= nameLeft,
|
||||
"The delay element does not span over the name element");
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
|
||||
let {panel} = yield openAnimationInspectorNewUI();
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
info("Getting the animation element from the panel");
|
||||
let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
|
||||
@ -22,8 +21,8 @@ add_task(function*() {
|
||||
ok(el.hasAttribute("title"), "The tooltip is defined");
|
||||
|
||||
let title = el.getAttribute("title");
|
||||
ok(title.match(/Delay: [\d.]+s/), "The tooltip shows the delay");
|
||||
ok(title.match(/Duration: [\d.]+s/), "The tooltip shows the delay");
|
||||
ok(title.match(/Delay: [\d.-]+s/), "The tooltip shows the delay");
|
||||
ok(title.match(/Duration: [\d.]+s/), "The tooltip shows the duration");
|
||||
ok(title.match(/Repeats: /), "The tooltip shows the iterations");
|
||||
}
|
||||
});
|
||||
|
@ -15,7 +15,6 @@ add_task(function*() {
|
||||
yield addTab(TEST_URL_ROOT + "doc_modify_playbackRate.html");
|
||||
|
||||
let {panel} = yield openAnimationInspectorNewUI();
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
|
||||
|
||||
|
@ -23,9 +23,9 @@ function* testDataUpdates({panel, controller, inspector}, isNewUI=false) {
|
||||
yield selectNode(".animated", inspector);
|
||||
|
||||
let animation = controller.animationPlayers[0];
|
||||
yield setStyle(animation, "animationDuration", "5.5s", isNewUI);
|
||||
yield setStyle(animation, "animationIterationCount", "300", isNewUI);
|
||||
yield setStyle(animation, "animationDelay", "45s", isNewUI);
|
||||
yield setStyle(animation, panel, "animationDuration", "5.5s", isNewUI);
|
||||
yield setStyle(animation, panel, "animationIterationCount", "300", isNewUI);
|
||||
yield setStyle(animation, panel, "animationDelay", "45s", isNewUI);
|
||||
|
||||
if (isNewUI) {
|
||||
let animationsEl = panel.animationsTimelineComponent.animationsEl;
|
||||
@ -52,7 +52,7 @@ function* testDataUpdates({panel, controller, inspector}, isNewUI=false) {
|
||||
}
|
||||
}
|
||||
|
||||
function* setStyle(animation, name, value, isNewUI=false) {
|
||||
function* setStyle(animation, panel, name, value, isNewUI=false) {
|
||||
info("Change the animation style via the content DOM. Setting " +
|
||||
name + " to " + value);
|
||||
|
||||
@ -64,6 +64,10 @@ function* setStyle(animation, name, value, isNewUI=false) {
|
||||
});
|
||||
yield onAnimationChanged;
|
||||
|
||||
// Also wait for the target node previews to be loaded if the panel got
|
||||
// refreshed as a result of this animation mutation.
|
||||
yield waitForAllAnimationTargets(panel);
|
||||
|
||||
// If this is the playerWidget-based UI, wait for the auto-refresh event too
|
||||
// to make sure the UI has updated.
|
||||
if (!isNewUI) {
|
||||
|
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -500px;
|
||||
height: 20px;
|
||||
width: 500px;
|
||||
color: red;
|
||||
background: linear-gradient(to left, currentColor, currentColor 2px, transparent);
|
||||
}
|
||||
|
||||
.zero {
|
||||
color: blue;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: green;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.negative.move { animation: 5s -1s move linear forwards; }
|
||||
.zero.move { animation: 5s 0s move linear forwards; }
|
||||
.positive.move { animation: 5s 1s move linear forwards; }
|
||||
|
||||
@keyframes move {
|
||||
to {
|
||||
transform: translateX(500px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="negative"></div>
|
||||
<div class="zero"></div>
|
||||
<div class="positive"></div>
|
||||
<script>
|
||||
var negative = document.querySelector(".negative");
|
||||
var zero = document.querySelector(".zero");
|
||||
var positive = document.querySelector(".positive");
|
||||
|
||||
// The non-delayed animation starts now.
|
||||
zero.classList.add("move");
|
||||
// The negative-delayed animation starts in 1 second.
|
||||
setTimeout(function() {
|
||||
negative.classList.add("move");
|
||||
}, 1000);
|
||||
// The positive-delayed animation starts in 200 ms.
|
||||
setTimeout(function() {
|
||||
positive.classList.add("move");
|
||||
}, 200);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -65,6 +65,15 @@
|
||||
animation: simple-animation 120s;
|
||||
}
|
||||
|
||||
.negative-delay {
|
||||
top: 700px;
|
||||
left: 10px;
|
||||
background: gray;
|
||||
|
||||
animation: simple-animation 15s -10s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes simple-animation {
|
||||
100% {
|
||||
transform: translateX(300px);
|
||||
@ -87,5 +96,6 @@
|
||||
<div class="ball multi-finite"></div>
|
||||
<div class="ball short"></div>
|
||||
<div class="ball long"></div>
|
||||
<div class="ball negative-delay"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -21,6 +21,7 @@ const ROOT_TEST_DIR = getRootDirectory(gTestPath);
|
||||
const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
|
||||
const COMMON_FRAME_SCRIPT_URL = "chrome://browser/content/devtools/frame-script-utils.js";
|
||||
const NEW_UI_PREF = "devtools.inspector.animationInspectorV3";
|
||||
const TAB_NAME = "animationinspector";
|
||||
|
||||
// Auto clean-up when a test ends
|
||||
registerCleanupFunction(function*() {
|
||||
@ -129,6 +130,13 @@ let selectNode = Task.async(function*(data, inspector, reason="test") {
|
||||
let updated = inspector.once("inspector-updated");
|
||||
inspector.selection.setNodeFront(nodeFront, reason);
|
||||
yield updated;
|
||||
|
||||
// 99% of the times, selectNode is called to select an animated node, and we
|
||||
// want to make sure the rest of the test waits for the animations to be
|
||||
// properly displayed (wait for all target DOM nodes to be previewed).
|
||||
// Even if there are no animations, this is safe to do.
|
||||
let {AnimationsPanel} = inspector.sidebar.getWindowForTab(TAB_NAME);
|
||||
yield waitForAllAnimationTargets(AnimationsPanel);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -159,7 +167,7 @@ function assertAnimationsDisplayed(panel, nbAnimations, msg="") {
|
||||
* @return {Promise}
|
||||
*/
|
||||
let waitForAnimationInspectorReady = Task.async(function*(inspector) {
|
||||
let win = inspector.sidebar.getWindowForTab("animationinspector");
|
||||
let win = inspector.sidebar.getWindowForTab(TAB_NAME);
|
||||
let updated = inspector.once("inspector-updated");
|
||||
|
||||
// In e10s, if we wait for underlying toolbox actors to
|
||||
@ -192,12 +200,12 @@ let openAnimationInspector = Task.async(function*() {
|
||||
info("Waiting for toolbox focus");
|
||||
yield waitForToolboxFrameFocus(toolbox);
|
||||
|
||||
inspector.sidebar.select("animationinspector");
|
||||
inspector.sidebar.select(TAB_NAME);
|
||||
|
||||
info("Waiting for the inspector and sidebar to be ready");
|
||||
yield panelReady;
|
||||
|
||||
let win = inspector.sidebar.getWindowForTab("animationinspector");
|
||||
let win = inspector.sidebar.getWindowForTab(TAB_NAME);
|
||||
let {AnimationsController, AnimationsPanel} = win;
|
||||
|
||||
info("Waiting for the animation controller and panel to be ready");
|
||||
@ -207,6 +215,11 @@ let openAnimationInspector = Task.async(function*() {
|
||||
yield AnimationsPanel.once(AnimationsPanel.PANEL_INITIALIZED);
|
||||
}
|
||||
|
||||
// Make sure we wait for all animations to be loaded (especially their target
|
||||
// nodes to be lazily displayed). This is safe to do even if there are no
|
||||
// animations displayed.
|
||||
yield waitForAllAnimationTargets(AnimationsPanel);
|
||||
|
||||
return {
|
||||
toolbox: toolbox,
|
||||
inspector: inspector,
|
||||
@ -250,11 +263,9 @@ let closeAnimationInspectorAndRestartWithNewUI = Task.async(function*(reload) {
|
||||
if (reload) {
|
||||
yield reloadTab();
|
||||
}
|
||||
enableNewUI();
|
||||
return yield openAnimationInspector();
|
||||
return yield openAnimationInspectorNewUI();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Wait for the toolbox frame to receive focus after it loads
|
||||
* @param {Toolbox} toolbox
|
||||
|
@ -10,26 +10,51 @@ const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const {TimeScale} = require("devtools/animationinspector/components");
|
||||
|
||||
const TEST_ANIMATIONS = [{
|
||||
startTime: 500,
|
||||
delay: 0,
|
||||
duration: 1000,
|
||||
iterationCount: 1,
|
||||
playbackRate: 1
|
||||
desc: "Testing a few standard animations",
|
||||
animations: [{
|
||||
startTime: 500,
|
||||
delay: 0,
|
||||
duration: 1000,
|
||||
iterationCount: 1,
|
||||
playbackRate: 1
|
||||
}, {
|
||||
startTime: 400,
|
||||
delay: 100,
|
||||
duration: 10,
|
||||
iterationCount: 100,
|
||||
playbackRate: 1
|
||||
}, {
|
||||
startTime: 50,
|
||||
delay: 1000,
|
||||
duration: 100,
|
||||
iterationCount: 20,
|
||||
playbackRate: 1
|
||||
}],
|
||||
expectedMinStart: 50,
|
||||
expectedMaxEnd: 3050
|
||||
}, {
|
||||
startTime: 400,
|
||||
delay: 100,
|
||||
duration: 10,
|
||||
iterationCount: 100,
|
||||
playbackRate: 1
|
||||
desc: "Testing a single negative-delay animation",
|
||||
animations: [{
|
||||
startTime: 100,
|
||||
delay: -100,
|
||||
duration: 100,
|
||||
iterationCount: 1,
|
||||
playbackRate: 1
|
||||
}],
|
||||
expectedMinStart: 0,
|
||||
expectedMaxEnd: 100
|
||||
}, {
|
||||
startTime: 50,
|
||||
delay: 1000,
|
||||
duration: 100,
|
||||
iterationCount: 20,
|
||||
playbackRate: 1
|
||||
desc: "Testing a single negative-delay animation with a different rate",
|
||||
animations: [{
|
||||
startTime: 3500,
|
||||
delay: -1000,
|
||||
duration: 10000,
|
||||
iterationCount: 2,
|
||||
playbackRate: 2
|
||||
}],
|
||||
expectedMinStart: 3000,
|
||||
expectedMaxEnd: 13000
|
||||
}];
|
||||
const EXPECTED_MIN_START = 50;
|
||||
const EXPECTED_MAX_END = 3050;
|
||||
|
||||
const TEST_STARTTIME_TO_DISTANCE = [{
|
||||
time: 50,
|
||||
@ -126,24 +151,27 @@ function run_test() {
|
||||
equal(TimeScale.minStartTime, Infinity);
|
||||
equal(TimeScale.maxEndTime, 0);
|
||||
|
||||
do_print("Test adding a few animations");
|
||||
for (let state of TEST_ANIMATIONS) {
|
||||
for (let {desc, animations, expectedMinStart, expectedMaxEnd} of
|
||||
TEST_ANIMATIONS) {
|
||||
do_print("Test adding a few animations: " + desc);
|
||||
for (let state of animations) {
|
||||
TimeScale.addAnimation(state);
|
||||
}
|
||||
|
||||
do_print("Checking the time scale range");
|
||||
equal(TimeScale.minStartTime, expectedMinStart);
|
||||
equal(TimeScale.maxEndTime, expectedMaxEnd);
|
||||
|
||||
do_print("Test reseting the animations");
|
||||
TimeScale.reset();
|
||||
equal(TimeScale.minStartTime, Infinity);
|
||||
equal(TimeScale.maxEndTime, 0);
|
||||
}
|
||||
|
||||
do_print("Add a set of animations again");
|
||||
for (let state of TEST_ANIMATIONS[0].animations) {
|
||||
TimeScale.addAnimation(state);
|
||||
}
|
||||
equal(TimeScale.minStartTime, EXPECTED_MIN_START);
|
||||
equal(TimeScale.maxEndTime, EXPECTED_MAX_END);
|
||||
|
||||
do_print("Test reseting the animations");
|
||||
TimeScale.reset();
|
||||
equal(TimeScale.minStartTime, Infinity);
|
||||
equal(TimeScale.maxEndTime, 0);
|
||||
|
||||
do_print("Test adding the animations again");
|
||||
for (let state of TEST_ANIMATIONS) {
|
||||
TimeScale.addAnimation(state);
|
||||
}
|
||||
equal(TimeScale.minStartTime, EXPECTED_MIN_START);
|
||||
equal(TimeScale.maxEndTime, EXPECTED_MAX_END);
|
||||
|
||||
do_print("Test converting start times to distances");
|
||||
for (let {time, width, expectedDistance} of TEST_STARTTIME_TO_DISTANCE) {
|
||||
|
@ -120,8 +120,8 @@
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="fxa-needs-authentication"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background-color: transparent;
|
||||
background-image: url(chrome://browser/skin/warning.svg);
|
||||
background: transparent url(chrome://browser/skin/warning.svg) no-repeat center;
|
||||
height: 13px;
|
||||
box-shadow: none;
|
||||
filter: drop-shadow(0 1px 0 hsla(206, 50%, 10%, .15));
|
||||
}
|
||||
|
@ -13,7 +13,12 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
/* How high should toolbars be */
|
||||
--toolbar-height: 20px;
|
||||
/* How wide should the sidebar be */
|
||||
--timeline-sidebar-width: 150px;
|
||||
/* How high should animations displayed in the timeline be */
|
||||
--timeline-animation-height: 20px;
|
||||
}
|
||||
|
||||
html {
|
||||
@ -38,7 +43,7 @@ body {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 20px;
|
||||
height: var(--toolbar-height);
|
||||
}
|
||||
|
||||
#toolbar .label {
|
||||
@ -47,13 +52,13 @@ body {
|
||||
|
||||
#toggle-all {
|
||||
border-width: 0 0 0 1px;
|
||||
min-height: 20px;
|
||||
min-height: var(--toolbar-height);
|
||||
}
|
||||
|
||||
/* The main animations container */
|
||||
|
||||
#players {
|
||||
height: calc(100% - 20px);
|
||||
height: calc(100% - var(--toolbar-height));
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@ -159,7 +164,7 @@ body {
|
||||
|
||||
.animation-timeline .time-header {
|
||||
margin-left: var(--timeline-sidebar-width);
|
||||
height: 20px;
|
||||
min-height: var(--toolbar-height);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
/* This is the same color as the time graduations in
|
||||
@ -187,7 +192,7 @@ body {
|
||||
|
||||
.animation-timeline .animation {
|
||||
margin: 4px 0;
|
||||
height: 20px;
|
||||
height: var(--timeline-animation-height);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@ -289,14 +294,25 @@ body {
|
||||
top: 0;
|
||||
/* Make sure the delay covers up the animation border */
|
||||
transform: translate(-1px, -1px);
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
height: calc(100% + 2px);
|
||||
|
||||
border: 1px solid var(--timelime-border-color);
|
||||
border-width: 1px 0 1px 1px;
|
||||
background-image: repeating-linear-gradient(45deg,
|
||||
transparent,
|
||||
transparent 1px,
|
||||
var(--theme-selection-color) 1px,
|
||||
var(--theme-selection-color) 4px);
|
||||
background-color: var(--timelime-border-color);
|
||||
border: 1px solid var(--timelime-border-color);
|
||||
}
|
||||
|
||||
.animation-timeline .animation .delay.negative {
|
||||
/* Negative delays are displayed on top of the animation, so they need a
|
||||
right border. Whereas normal delays are displayed just before the
|
||||
animation, so there's already the animation's left border that serves as
|
||||
a separation. */
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
/* Animation target node gutter, contains a preview of the dom node */
|
||||
@ -361,7 +377,7 @@ body {
|
||||
/* Timeline wiget */
|
||||
|
||||
.timeline {
|
||||
height: 20px;
|
||||
height: var(--timeline-animation-height);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -99,7 +99,7 @@
|
||||
|
||||
<!-- In a 56x60dp space, centering 24dp image will leave 16x18dp. -->
|
||||
<org.mozilla.gecko.toolbar.TabCounter android:id="@+id/tabs_counter"
|
||||
style="@style/UrlBar.ImageButton.TabCount"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_alignLeft="@id/tabs"
|
||||
android:layout_alignRight="@id/tabs"
|
||||
android:layout_alignTop="@id/tabs"
|
||||
@ -107,7 +107,8 @@
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginBottom="18dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"/>
|
||||
android:layout_marginRight="16dp"
|
||||
android:background="@drawable/tabs_count"/>
|
||||
|
||||
<org.mozilla.gecko.widget.themed.ThemedFrameLayout
|
||||
android:id="@+id/menu"
|
||||
@ -133,7 +134,10 @@
|
||||
which is thus drawn on top, may be pressed. -->
|
||||
<org.mozilla.gecko.widget.themed.ThemedImageView
|
||||
android:id="@+id/edit_cancel"
|
||||
style="@style/UrlBar.ImageButton.Icon"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="@dimen/browser_toolbar_icon_width"
|
||||
android:layout_height="@dimen/browser_toolbar_height"
|
||||
android:layout_weight="0.0"
|
||||
android:layout_alignParentRight="true"
|
||||
android:src="@drawable/close_edit_mode_selector"
|
||||
android:contentDescription="@string/edit_mode_cancel"
|
||||
|
@ -70,12 +70,16 @@
|
||||
The margins will be 40dp on left, 8dp on right, instead of ideal 30dp
|
||||
and 12dp. -->
|
||||
<org.mozilla.gecko.toolbar.TabCounter android:id="@+id/tabs_counter"
|
||||
style="@style/UrlBar.ImageButton.TabCount"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="24dip"
|
||||
android:layout_height="24dip"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="8dip"
|
||||
android:layout_alignRight="@id/tabs"/>
|
||||
android:layout_alignRight="@id/tabs"
|
||||
android:background="@drawable/tabs_count"
|
||||
android:gravity="center_horizontal"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<!-- Note that the edit components are invisible so that the views
|
||||
depending on their location can properly layout. -->
|
||||
|
@ -15,10 +15,6 @@
|
||||
<item name="drawableTintList">@color/action_bar_menu_item_colors</item>
|
||||
</style>
|
||||
|
||||
<style name="UrlBar.ImageButton.TabCount">
|
||||
<item name="android:background">@drawable/tabs_count</item>
|
||||
</style>
|
||||
|
||||
<style name="UrlBar.Button.Container">
|
||||
<item name="android:layout_marginTop">6dp</item>
|
||||
<item name="android:layout_marginBottom">6dp</item>
|
||||
|
@ -457,13 +457,6 @@
|
||||
<item name="android:orientation">horizontal</item>
|
||||
</style>
|
||||
|
||||
<style name="UrlBar.ImageButton.TabCount">
|
||||
<item name="android:background">@drawable/tabs_count</item>
|
||||
<item name="android:gravity">center_horizontal</item>
|
||||
<item name="android:clipChildren">false</item>
|
||||
<item name="android:clipToPadding">false</item>
|
||||
</style>
|
||||
|
||||
<!-- URL bar -->
|
||||
<style name="UrlBar">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
@ -503,13 +496,6 @@
|
||||
<item name="android:layout_width">@dimen/browser_toolbar_height</item>
|
||||
</style>
|
||||
|
||||
<!-- URL bar - Image Button - Icon -->
|
||||
<style name="UrlBar.ImageButton.Icon">
|
||||
<item name="android:layout_width">@dimen/browser_toolbar_icon_width</item>
|
||||
<item name="android:layout_height">@dimen/browser_toolbar_height</item>
|
||||
<item name="android:layout_weight">0.0</item>
|
||||
</style>
|
||||
|
||||
<!-- TabsLayout -->
|
||||
<style name="TabsLayoutBase">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
|
@ -162,7 +162,7 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final int width = mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width);
|
||||
ImageButton imageButton = new ImageButton(mContext, null, R.style.UrlBar_ImageButton_Icon);
|
||||
ImageButton imageButton = new ImageButton(mContext, null, R.style.UrlBar_ImageButton);
|
||||
imageButton.setLayoutParams(new LayoutParams(width, LayoutParams.MATCH_PARENT));
|
||||
imageButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
imageButton.setOnClickListener(this);
|
||||
|
@ -1077,10 +1077,14 @@ EnvironmentCache.prototype = {
|
||||
_getCpuData: function () {
|
||||
let cpuData = {
|
||||
count: getSysinfoProperty("cpucount", null),
|
||||
vendor: null, // TODO: bug 1128472
|
||||
family: null, // TODO: bug 1128472
|
||||
model: null, // TODO: bug 1128472
|
||||
stepping: null, // TODO: bug 1128472
|
||||
cores: getSysinfoProperty("cpucores", null),
|
||||
vendor: getSysinfoProperty("cpuvendor", null),
|
||||
family: getSysinfoProperty("cpufamily", null),
|
||||
model: getSysinfoProperty("cpumodel", null),
|
||||
stepping: getSysinfoProperty("cpustepping", null),
|
||||
l2cacheKB: getSysinfoProperty("cpucachel2", null),
|
||||
l3cacheKB: getSysinfoProperty("cpucachel3", null),
|
||||
speedMHz: getSysinfoProperty("cpuspeed", null),
|
||||
};
|
||||
|
||||
const CPU_EXTENSIONS = ["hasMMX", "hasSSE", "hasSSE2", "hasSSE3", "hasSSSE3",
|
||||
@ -1223,8 +1227,16 @@ EnvironmentCache.prototype = {
|
||||
memoryMB = Math.round(memoryMB / 1024 / 1024);
|
||||
}
|
||||
|
||||
let virtualMB = getSysinfoProperty("virtualmemsize", null);
|
||||
if (virtualMB) {
|
||||
// Send the total virtual memory size in megabytes. Rounding because
|
||||
// sysinfo doesn't always provide RAM in multiples of 1024.
|
||||
virtualMB = Math.round(virtualMB / 1024 / 1024);
|
||||
}
|
||||
|
||||
return {
|
||||
memoryMB: memoryMB,
|
||||
virtualMaxMB: virtualMB,
|
||||
#ifdef XP_WIN
|
||||
isWow64: getSysinfoProperty("isWow64", null),
|
||||
#endif
|
||||
|
@ -75,13 +75,18 @@ Structure::
|
||||
},
|
||||
system: {
|
||||
memoryMB: <number>,
|
||||
virtualMaxMB: <number>, // windows-only
|
||||
isWow64: <bool>, // windows-only
|
||||
cpu: {
|
||||
count: <number>, // e.g. 8, or null on failure
|
||||
vendor: <string>, // e.g. "GenuineIntel", or null on failure
|
||||
family: <string>, // null on failure
|
||||
model: <string>, // null on failure
|
||||
stepping: <string>, // null on failure
|
||||
count: <number>, // desktop only, e.g. 8, or null on failure - logical cpus
|
||||
cores: <number>, // desktop only, e.g., 4, or null on failure - physical cores
|
||||
vendor: <string>, // desktop only, e.g. "GenuineIntel", or null on failure
|
||||
family: <string>, // desktop only, null on failure
|
||||
model: <string>, // desktop only, null on failure
|
||||
stepping: <string>, // desktop only, null on failure
|
||||
l2cacheKB: <number>, // L2 cache size in KB, only on windows & mac
|
||||
l3cacheKB: <number>, // desktop only, L3 cache size in KB
|
||||
speedMHz: <number>, // desktop only, cpu clock speed in MHz
|
||||
extensions: [
|
||||
<string>,
|
||||
...
|
||||
|
@ -8,11 +8,13 @@ Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://testing-common/httpd.js", this);
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
const gIsMac = ("@mozilla.org/xpcom/mac-utils;1" in Cc);
|
||||
const gIsAndroid = ("@mozilla.org/android/bridge;1" in Cc);
|
||||
const gIsGonk = ("@mozilla.org/cellbroadcast/gonkservice;1" in Cc);
|
||||
const gIsWindows = AppConstants.platform == "win";
|
||||
const gIsMac = AppConstants.platform == "macosx";
|
||||
const gIsAndroid = AppConstants.platform == "android";
|
||||
const gIsGonk = AppConstants.platform == "gonk";
|
||||
const gIsLinux = AppConstants.platform == "linux";
|
||||
|
||||
const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
|
||||
|
@ -365,9 +365,40 @@ function checkSystemSection(data) {
|
||||
}
|
||||
|
||||
Assert.ok(Number.isFinite(data.system.memoryMB), "MemoryMB must be a number.");
|
||||
if (gIsWindows) {
|
||||
Assert.equal(typeof data.system.isWow64, "boolean",
|
||||
"isWow64 must be available on Windows and have the correct type.");
|
||||
|
||||
if (gIsWindows || gIsMac || gIsLinux) {
|
||||
let EXTRA_CPU_FIELDS = ["cores", "model", "family", "stepping",
|
||||
"l2cacheKB", "l3cacheKB", "speedMHz", "vendor"];
|
||||
|
||||
for (let f of EXTRA_CPU_FIELDS) {
|
||||
// Note this is testing TelemetryEnvironment.js only, not that the
|
||||
// values are valid - null is the fallback.
|
||||
Assert.ok(f in data.system.cpu, f + " must be available under cpu.");
|
||||
}
|
||||
|
||||
if (gIsWindows) {
|
||||
Assert.equal(typeof data.system.isWow64, "boolean",
|
||||
"isWow64 must be available on Windows and have the correct type.");
|
||||
Assert.ok("virtualMaxMB" in data.system, "virtualMaxMB must be available.");
|
||||
Assert.ok(Number.isFinite(data.system.virtualMaxMB),
|
||||
"virtualMaxMB must be a number.");
|
||||
}
|
||||
|
||||
// We insist these are available
|
||||
for (let f of ["cores"]) {
|
||||
Assert.ok(!(f in data.system.cpu) ||
|
||||
Number.isFinite(data.system.cpu[f]),
|
||||
f + " must be a number if non null.");
|
||||
}
|
||||
|
||||
// These should be numbers if they are not null
|
||||
for (let f of ["model", "family", "stepping", "l2cacheKB",
|
||||
"l3cacheKB", "speedMHz"]) {
|
||||
Assert.ok(!(f in data.system.cpu) ||
|
||||
data.system.cpu[f] === null ||
|
||||
Number.isFinite(data.system.cpu[f]),
|
||||
f + " must be a number if non null.");
|
||||
}
|
||||
}
|
||||
|
||||
let cpuData = data.system.cpu;
|
||||
|
@ -41,6 +41,7 @@ function* playerHasAnInitialState(walker, front) {
|
||||
ok("iterationCount" in player.initialState, "Player's state has iterationCount");
|
||||
ok("isRunningOnCompositor" in player.initialState, "Player's state has isRunningOnCompositor");
|
||||
ok("type" in player.initialState, "Player's state has type");
|
||||
ok("documentCurrentTime" in player.initialState, "Player's state has documentCurrentTime");
|
||||
}
|
||||
|
||||
function* playerStateIsCorrect(walker, front) {
|
||||
|
@ -2998,6 +2998,8 @@ this.AddonManager = {
|
||||
SIGNEDSTATE_PRELIMINARY: 1,
|
||||
// Add-on is fully reviewed.
|
||||
SIGNEDSTATE_SIGNED: 2,
|
||||
// Add-on is system add-on.
|
||||
SIGNEDSTATE_SYSTEM: 3,
|
||||
|
||||
// Constants for the Addon.userDisabled property
|
||||
// Indicates that the userDisabled state of this add-on is currently
|
||||
|
@ -617,6 +617,12 @@ function isUsableAddon(aAddon) {
|
||||
return false;
|
||||
if (aAddon.foreignInstall && aAddon.signedState < AddonManager.SIGNEDSTATE_SIGNED)
|
||||
return false;
|
||||
|
||||
if (aAddon._installLocation.name == KEY_APP_SYSTEM_ADDONS ||
|
||||
aAddon._installLocation.name == KEY_APP_SYSTEM_DEFAULTS) {
|
||||
if (aAddon.signedState != AddonManager.SIGNEDSTATE_SYSTEM)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aAddon.blocklistState == Blocklist.STATE_BLOCKED)
|
||||
@ -1155,7 +1161,7 @@ function defineSyncGUID(aAddon) {
|
||||
* @return an AddonInternal object
|
||||
* @throws if the directory does not contain a valid install manifest
|
||||
*/
|
||||
let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
|
||||
let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstallLocation) {
|
||||
function getFileSize(aFile) {
|
||||
if (aFile.isSymlink())
|
||||
return 0;
|
||||
@ -1202,6 +1208,7 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
|
||||
loadFromRDF(file, bis);
|
||||
|
||||
addon._sourceBundle = aDir.clone();
|
||||
addon._installLocation = aInstallLocation;
|
||||
addon.size = getFileSize(aDir);
|
||||
addon.signedState = yield verifyDirSignedState(aDir, addon);
|
||||
addon.appDisabled = !isUsableAddon(addon);
|
||||
@ -1224,7 +1231,7 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
|
||||
* @return an AddonInternal object
|
||||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader) {
|
||||
let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader, aInstallLocation) {
|
||||
function loadFromRDF(aStream) {
|
||||
let uri = buildJarURI(aZipReader.file, FILE_RDF_MANIFEST);
|
||||
let addon = loadManifestFromRDF(uri, aStream);
|
||||
@ -1259,6 +1266,7 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
|
||||
loadFromRDF(bis);
|
||||
|
||||
addon._sourceBundle = aZipReader.file;
|
||||
addon._installLocation = aInstallLocation;
|
||||
|
||||
addon.size = 0;
|
||||
let entries = aZipReader.findEntries(null);
|
||||
@ -1286,7 +1294,7 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
|
||||
* @return an AddonInternal object
|
||||
* @throws if the XPI file does not contain a valid install manifest
|
||||
*/
|
||||
let loadManifestFromZipFile = Task.async(function* loadManifestFromZipFile(aXPIFile) {
|
||||
let loadManifestFromZipFile = Task.async(function* loadManifestFromZipFile(aXPIFile, aInstallLocation) {
|
||||
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
try {
|
||||
@ -1295,7 +1303,7 @@ let loadManifestFromZipFile = Task.async(function* loadManifestFromZipFile(aXPIF
|
||||
// Can't return this promise because that will make us close the zip reader
|
||||
// before it has finished loading the manifest. Wait for the result and then
|
||||
// return.
|
||||
let manifest = yield loadManifestFromZipReader(zipReader);
|
||||
let manifest = yield loadManifestFromZipReader(zipReader, aInstallLocation);
|
||||
return manifest;
|
||||
}
|
||||
finally {
|
||||
@ -1303,22 +1311,22 @@ let loadManifestFromZipFile = Task.async(function* loadManifestFromZipFile(aXPIF
|
||||
}
|
||||
});
|
||||
|
||||
function loadManifestFromFile(aFile) {
|
||||
function loadManifestFromFile(aFile, aInstallLocation) {
|
||||
if (aFile.isFile())
|
||||
return loadManifestFromZipFile(aFile);
|
||||
return loadManifestFromZipFile(aFile, aInstallLocation);
|
||||
else
|
||||
return loadManifestFromDir(aFile);
|
||||
return loadManifestFromDir(aFile, aInstallLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* A synchronous method for loading an add-on's manifest. This should only ever
|
||||
* be used during startup or a sync load of the add-ons DB
|
||||
*/
|
||||
function syncLoadManifestFromFile(aFile) {
|
||||
function syncLoadManifestFromFile(aFile, aInstallLocation) {
|
||||
let success = undefined;
|
||||
let result = null;
|
||||
|
||||
loadManifestFromFile(aFile).then(val => {
|
||||
loadManifestFromFile(aFile, aInstallLocation).then(val => {
|
||||
success = true;
|
||||
result = val;
|
||||
}, val => {
|
||||
@ -1466,6 +1474,9 @@ function getSignedStatus(aRv, aCert, aExpectedID) {
|
||||
}
|
||||
}
|
||||
|
||||
if (aCert.organizationalUnit == "Mozilla Components")
|
||||
return AddonManager.SIGNEDSTATE_SYSTEM;
|
||||
|
||||
return /preliminary/i.test(aCert.organizationalUnit)
|
||||
? AddonManager.SIGNEDSTATE_PRELIMINARY
|
||||
: AddonManager.SIGNEDSTATE_SIGNED;
|
||||
@ -2922,7 +2933,7 @@ this.XPIProvider = {
|
||||
let addon;
|
||||
|
||||
try {
|
||||
addon = syncLoadManifestFromFile(stageDirEntry);
|
||||
addon = syncLoadManifestFromFile(stageDirEntry, aLocation);
|
||||
}
|
||||
catch (e) {
|
||||
logger.error("Unable to read add-on manifest from " + stageDirEntry.path, e);
|
||||
@ -3096,7 +3107,7 @@ this.XPIProvider = {
|
||||
|
||||
let addon;
|
||||
try {
|
||||
addon = syncLoadManifestFromFile(entry);
|
||||
addon = syncLoadManifestFromFile(entry, profileLocation);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("File entry " + entry.path + " contains an invalid add-on", e);
|
||||
@ -3119,7 +3130,7 @@ this.XPIProvider = {
|
||||
if (existingEntry) {
|
||||
let existingAddon;
|
||||
try {
|
||||
existingAddon = syncLoadManifestFromFile(existingEntry);
|
||||
existingAddon = syncLoadManifestFromFile(existingEntry, profileLocation);
|
||||
|
||||
if (Services.vc.compare(addon.version, existingAddon.version) <= 0)
|
||||
continue;
|
||||
@ -4958,7 +4969,7 @@ AddonInstall.prototype = {
|
||||
|
||||
try {
|
||||
// loadManifestFromZipReader performs the certificate verification for us
|
||||
this.addon = yield loadManifestFromZipReader(zipreader);
|
||||
this.addon = yield loadManifestFromZipReader(zipreader, this.installLocation);
|
||||
}
|
||||
catch (e) {
|
||||
zipreader.close();
|
||||
@ -5506,7 +5517,6 @@ AddonInstall.prototype = {
|
||||
|
||||
// Update the metadata in the database
|
||||
this.addon._sourceBundle = file;
|
||||
this.addon._installLocation = this.installLocation;
|
||||
this.addon.visible = true;
|
||||
|
||||
if (isUpgrade) {
|
||||
|
@ -1604,7 +1604,7 @@ this.XPIDatabaseReconcile = {
|
||||
// Load the manifest from the add-on.
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
aNewAddon = syncLoadManifestFromFile(file);
|
||||
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
}
|
||||
// The add-on in the manifest should match the add-on ID.
|
||||
if (aNewAddon.id != aId) {
|
||||
@ -1625,7 +1625,6 @@ this.XPIDatabaseReconcile = {
|
||||
}
|
||||
|
||||
// Update the AddonInternal properties.
|
||||
aNewAddon._installLocation = aInstallLocation;
|
||||
aNewAddon.installDate = aAddonState.mtime;
|
||||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
@ -1728,7 +1727,7 @@ this.XPIDatabaseReconcile = {
|
||||
if (!aNewAddon) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
aNewAddon = syncLoadManifestFromFile(file);
|
||||
aNewAddon = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
applyBlocklistChanges(aOldAddon, aNewAddon);
|
||||
|
||||
// Carry over any pendingUninstall state to add-ons modified directly
|
||||
@ -1756,7 +1755,6 @@ this.XPIDatabaseReconcile = {
|
||||
}
|
||||
|
||||
// Set the additional properties on the new AddonInternal
|
||||
aNewAddon._installLocation = aInstallLocation;
|
||||
aNewAddon.updateDate = aAddonState.mtime;
|
||||
|
||||
// Update the database
|
||||
@ -1814,7 +1812,7 @@ this.XPIDatabaseReconcile = {
|
||||
SIGNED_TYPES.has(aOldAddon.type)) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.persistentDescriptor = aAddonState.descriptor;
|
||||
let manifest = syncLoadManifestFromFile(file);
|
||||
let manifest = syncLoadManifestFromFile(file, aInstallLocation);
|
||||
aOldAddon.signedState = manifest.signedState;
|
||||
}
|
||||
// This updates the addon's JSON cached data in place
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -2,6 +2,9 @@
|
||||
// application versions
|
||||
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
|
||||
|
||||
// Enable signature checks for these tests
|
||||
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, true);
|
||||
|
||||
const featureDir = gProfD.clone();
|
||||
featureDir.append("features");
|
||||
|
||||
@ -47,13 +50,21 @@ function* check_installed(inProfile, ...versions) {
|
||||
do_check_true(uri instanceof AM_Ci.nsIFileURL);
|
||||
do_check_eq(uri.file.path, file.path);
|
||||
|
||||
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_SYSTEM);
|
||||
|
||||
// Verify the add-on actually started
|
||||
let installed = Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
|
||||
do_check_eq(installed, versions[i]);
|
||||
}
|
||||
else {
|
||||
// Add-on should not be installed
|
||||
do_check_eq(addon, null);
|
||||
if (inProfile) {
|
||||
// Add-on should not be installed
|
||||
do_check_eq(addon, null);
|
||||
}
|
||||
else {
|
||||
// Either add-on should not be installed or it shouldn't be active
|
||||
do_check_true(!addon || !addon.isActive);
|
||||
}
|
||||
|
||||
try {
|
||||
Services.prefs.getCharPref("bootstraptest." + id + ".active_version");
|
||||
@ -131,7 +142,7 @@ add_task(function* test_updated() {
|
||||
// Inject it into the system set
|
||||
let addonSet = {
|
||||
schema: 1,
|
||||
directory: dirname,
|
||||
directory: featureDir.leafName,
|
||||
addons: {
|
||||
"system2@tests.mozilla.org": {
|
||||
version: "1.0"
|
||||
@ -198,3 +209,50 @@ add_task(function* test_corrupt_pref() {
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// An add-on with a bad certificate should cause us to use the default set
|
||||
add_task(function* test_bad_profile_cert() {
|
||||
let file = do_get_file("data/system_addons/app3/features/system1@tests.mozilla.org.xpi");
|
||||
file.copyTo(featureDir, file.leafName);
|
||||
|
||||
// Inject it into the system set
|
||||
let addonSet = {
|
||||
schema: 1,
|
||||
directory: featureDir.leafName,
|
||||
addons: {
|
||||
"system1@tests.mozilla.org": {
|
||||
version: "2.0"
|
||||
},
|
||||
"system2@tests.mozilla.org": {
|
||||
version: "1.0"
|
||||
},
|
||||
"system3@tests.mozilla.org": {
|
||||
version: "1.0"
|
||||
},
|
||||
}
|
||||
};
|
||||
Services.prefs.setCharPref(PREF_SYSTEM_ADDON_SET, JSON.stringify(addonSet));
|
||||
|
||||
startupManager(false);
|
||||
|
||||
yield check_installed(false, "1.0", "1.0", null);
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Switching to app defaults that contain a bad certificate should ignore the
|
||||
// bad add-on
|
||||
add_task(function* test_bad_app_cert() {
|
||||
gAppInfo.version = "3";
|
||||
distroDir.leafName = "app3";
|
||||
startupManager();
|
||||
|
||||
// Add-on will still be present just not active
|
||||
let addon = yield promiseAddonByID("system1@tests.mozilla.org");
|
||||
do_check_neq(addon, null);
|
||||
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED);
|
||||
|
||||
yield check_installed(false, null, null, "1.0");
|
||||
|
||||
yield promiseShutdownManager();
|
||||
});
|
||||
|
@ -31,6 +31,13 @@
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#include <gtk/gtk.h>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include "mozilla/Tokenizer.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -49,6 +56,10 @@ NS_EXPORT int android_sdk_version;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
#include "mozilla/SandboxInfo.h"
|
||||
#endif
|
||||
@ -60,6 +71,30 @@ NS_EXPORT int android_sdk_version;
|
||||
// only happens well after that point.
|
||||
uint32_t nsSystemInfo::gUserUmask = 0;
|
||||
|
||||
#if defined (MOZ_WIDGET_GTK)
|
||||
static void
|
||||
SimpleParseKeyValuePairs(const std::string& aFilename,
|
||||
std::map<nsCString, nsCString>& aKeyValuePairs)
|
||||
{
|
||||
std::ifstream input(aFilename.c_str());
|
||||
for (std::string line; std::getline(input, line); ) {
|
||||
nsAutoCString key, value;
|
||||
|
||||
nsCCharSeparatedTokenizer tokens(nsDependentCString(line.c_str()), ':');
|
||||
if (tokens.hasMoreTokens()) {
|
||||
key = tokens.nextToken();
|
||||
if (tokens.hasMoreTokens()) {
|
||||
value = tokens.nextToken();
|
||||
}
|
||||
// We want the value even if there was just one token, to cover the
|
||||
// case where we had the key, and the value was blank (seems to be
|
||||
// a valid scenario some files.)
|
||||
aKeyValuePairs[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
namespace {
|
||||
nsresult
|
||||
@ -235,6 +270,66 @@ static const struct PropItems
|
||||
{ "hasNEON", mozilla::supports_neon }
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Lifted from media/webrtc/trunk/webrtc/base/systeminfo.cc,
|
||||
// so keeping the _ instead of switching to camel case for now.
|
||||
typedef BOOL (WINAPI *LPFN_GLPI)(
|
||||
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,
|
||||
PDWORD);
|
||||
static void
|
||||
GetProcessorInformation(int* physical_cpus, int* cache_size_L2, int* cache_size_L3)
|
||||
{
|
||||
MOZ_ASSERT(physical_cpus && cache_size_L2 && cache_size_L3);
|
||||
|
||||
*physical_cpus = 0;
|
||||
*cache_size_L2 = 0; // This will be in kbytes
|
||||
*cache_size_L3 = 0; // This will be in kbytes
|
||||
|
||||
// GetLogicalProcessorInformation() is available on Windows XP SP3 and beyond.
|
||||
LPFN_GLPI glpi = reinterpret_cast<LPFN_GLPI>(GetProcAddress(
|
||||
GetModuleHandle(L"kernel32"),
|
||||
"GetLogicalProcessorInformation"));
|
||||
if (nullptr == glpi) {
|
||||
return;
|
||||
}
|
||||
// Determine buffer size, allocate and get processor information.
|
||||
// Size can change between calls (unlikely), so a loop is done.
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION info_buffer[32];
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION* infos = &info_buffer[0];
|
||||
DWORD return_length = sizeof(info_buffer);
|
||||
while (!glpi(infos, &return_length)) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && infos == &info_buffer[0]) {
|
||||
infos = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0;
|
||||
i < return_length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) {
|
||||
if (infos[i].Relationship == RelationProcessorCore) {
|
||||
++*physical_cpus;
|
||||
} else if (infos[i].Relationship == RelationCache) {
|
||||
// Only care about L2 and L3 cache
|
||||
switch (infos[i].Cache.Level) {
|
||||
case 2:
|
||||
*cache_size_L2 = static_cast<int>(infos[i].Cache.Size/1024);
|
||||
break;
|
||||
case 3:
|
||||
*cache_size_L3 = static_cast<int>(infos[i].Cache.Size/1024);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (infos != &info_buffer[0]) {
|
||||
delete [] infos;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult
|
||||
nsSystemInfo::Init()
|
||||
{
|
||||
@ -272,10 +367,246 @@ nsSystemInfo::Init()
|
||||
SetInt32Property(NS_LITERAL_STRING("pagesize"), PR_GetPageSize());
|
||||
SetInt32Property(NS_LITERAL_STRING("pageshift"), PR_GetPageShift());
|
||||
SetInt32Property(NS_LITERAL_STRING("memmapalign"), PR_GetMemMapAlignment());
|
||||
SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
|
||||
SetUint64Property(NS_LITERAL_STRING("memsize"), PR_GetPhysicalMemorySize());
|
||||
SetUint32Property(NS_LITERAL_STRING("umask"), nsSystemInfo::gUserUmask);
|
||||
|
||||
uint64_t virtualMem = 0;
|
||||
nsAutoCString cpuVendor;
|
||||
int cpuSpeed = -1;
|
||||
int cpuFamily = -1;
|
||||
int cpuModel = -1;
|
||||
int cpuStepping = -1;
|
||||
int logicalCPUs = -1;
|
||||
int physicalCPUs = -1;
|
||||
int cacheSizeL2 = -1;
|
||||
int cacheSizeL3 = -1;
|
||||
|
||||
#if defined (XP_WIN)
|
||||
// Virtual memory:
|
||||
MEMORYSTATUSEX memStat;
|
||||
memStat.dwLength = sizeof(memStat);
|
||||
if (GlobalMemoryStatusEx(&memStat)) {
|
||||
virtualMem = memStat.ullTotalVirtual;
|
||||
}
|
||||
|
||||
// CPU speed
|
||||
HKEY key;
|
||||
static const WCHAR keyName[] =
|
||||
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName , 0, KEY_QUERY_VALUE, &key)
|
||||
== ERROR_SUCCESS) {
|
||||
DWORD data, len, vtype;
|
||||
len = sizeof(data);
|
||||
|
||||
if (RegQueryValueEx(key, L"~Mhz", 0, 0, reinterpret_cast<LPBYTE>(&data),
|
||||
&len) == ERROR_SUCCESS) {
|
||||
cpuSpeed = static_cast<int>(data);
|
||||
}
|
||||
|
||||
// Limit to 64 double byte characters, should be plenty, but create
|
||||
// a buffer one larger as the result may not be null terminated. If
|
||||
// it is more than 64, we will not get the value.
|
||||
wchar_t cpuVendorStr[64+1];
|
||||
len = sizeof(cpuVendorStr)-2;
|
||||
if (RegQueryValueExW(key, L"VendorIdentifier",
|
||||
0, &vtype,
|
||||
reinterpret_cast<LPBYTE>(cpuVendorStr),
|
||||
&len) == ERROR_SUCCESS &&
|
||||
vtype == REG_SZ && len % 2 == 0 && len > 1) {
|
||||
cpuVendorStr[len/2] = 0; // In case it isn't null terminated
|
||||
CopyUTF16toUTF8(nsDependentString(cpuVendorStr), cpuVendor);
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
// Other CPU attributes:
|
||||
SYSTEM_INFO si;
|
||||
GetNativeSystemInfo(&si);
|
||||
logicalCPUs = si.dwNumberOfProcessors;
|
||||
GetProcessorInformation(&physicalCPUs, &cacheSizeL2, &cacheSizeL3);
|
||||
if (physicalCPUs <= 0) {
|
||||
physicalCPUs = logicalCPUs;
|
||||
}
|
||||
cpuFamily = si.wProcessorLevel;
|
||||
cpuModel = si.wProcessorRevision >> 8;
|
||||
cpuStepping = si.wProcessorRevision & 0xFF;
|
||||
#elif defined (XP_MACOSX)
|
||||
// CPU speed
|
||||
uint64_t sysctlValue64 = 0;
|
||||
uint32_t sysctlValue32 = 0;
|
||||
size_t len = 0;
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.cpufrequency_max", &sysctlValue64, &len, NULL, 0)) {
|
||||
cpuSpeed = static_cast<int>(sysctlValue64/1000000);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("hw.physicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
|
||||
physicalCPUs = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("hw.logicalcpu_max", &sysctlValue32, &len, NULL, 0)) {
|
||||
logicalCPUs = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.l2cachesize", &sysctlValue64, &len, NULL, 0)) {
|
||||
cacheSizeL2 = static_cast<int>(sysctlValue64/1024);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
len = sizeof(sysctlValue64);
|
||||
if (!sysctlbyname("hw.l3cachesize", &sysctlValue64, &len, NULL, 0)) {
|
||||
cacheSizeL3 = static_cast<int>(sysctlValue64/1024);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue64) == len);
|
||||
|
||||
if (!sysctlbyname("machdep.cpu.vendor", NULL, &len, NULL, 0)) {
|
||||
char* cpuVendorStr = new char[len];
|
||||
if (!sysctlbyname("machdep.cpu.vendor", cpuVendorStr, &len, NULL, 0)) {
|
||||
cpuVendor = cpuVendorStr;
|
||||
}
|
||||
delete [] cpuVendorStr;
|
||||
}
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.family", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuFamily = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.model", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuModel = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
len = sizeof(sysctlValue32);
|
||||
if (!sysctlbyname("machdep.cpu.stepping", &sysctlValue32, &len, NULL, 0)) {
|
||||
cpuStepping = static_cast<int>(sysctlValue32);
|
||||
}
|
||||
MOZ_ASSERT(sizeof(sysctlValue32) == len);
|
||||
|
||||
#elif defined (MOZ_WIDGET_GTK)
|
||||
// Get vendor, family, model, stepping, physical cores, L3 cache size
|
||||
// from /proc/cpuinfo file
|
||||
{
|
||||
std::map<nsCString, nsCString> keyValuePairs;
|
||||
SimpleParseKeyValuePairs("/proc/cpuinfo", keyValuePairs);
|
||||
|
||||
// cpuVendor from "vendor_id"
|
||||
cpuVendor.Assign(keyValuePairs[NS_LITERAL_CSTRING("vendor_id")]);
|
||||
|
||||
{
|
||||
// cpuFamily from "cpu family"
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu family")]);
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cpuFamily = static_cast<int>(t.AsInteger());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// cpuModel from "model"
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("model")]);
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cpuModel = static_cast<int>(t.AsInteger());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// cpuStepping from "stepping"
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("stepping")]);
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cpuStepping = static_cast<int>(t.AsInteger());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// physicalCPUs from "cpu cores"
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cpu cores")]);
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
physicalCPUs = static_cast<int>(t.AsInteger());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// cacheSizeL3 from "cache size"
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(keyValuePairs[NS_LITERAL_CSTRING("cache size")]);
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cacheSizeL3 = static_cast<int>(t.AsInteger());
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_WORD &&
|
||||
t.AsString() != NS_LITERAL_CSTRING("KB")) {
|
||||
// If we get here, there was some text after the cache size value
|
||||
// and that text was not KB. For now, just don't report the
|
||||
// L3 cache.
|
||||
cacheSizeL3 = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Get cpuSpeed from another file.
|
||||
std::ifstream input("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
|
||||
std::string line;
|
||||
if (getline(input, line)) {
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(line.c_str());
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cpuSpeed = static_cast<int>(t.AsInteger()/1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Get cacheSizeL2 from yet another file
|
||||
std::ifstream input("/sys/devices/system/cpu/cpu0/cache/index2/size");
|
||||
std::string line;
|
||||
if (getline(input, line)) {
|
||||
Tokenizer::Token t;
|
||||
Tokenizer p(line.c_str(), nullptr, "K");
|
||||
if (p.Next(t) && t.Type() == Tokenizer::TOKEN_INTEGER &&
|
||||
t.AsInteger() <= INT32_MAX) {
|
||||
cacheSizeL2 = static_cast<int>(t.AsInteger());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
|
||||
#else
|
||||
SetInt32Property(NS_LITERAL_STRING("cpucount"), PR_GetNumberOfProcessors());
|
||||
#endif
|
||||
|
||||
if (virtualMem) SetUint64Property(NS_LITERAL_STRING("virtualmemsize"), virtualMem);
|
||||
if (cpuSpeed >= 0) SetInt32Property(NS_LITERAL_STRING("cpuspeed"), cpuSpeed);
|
||||
if (!cpuVendor.IsEmpty()) SetPropertyAsACString(NS_LITERAL_STRING("cpuvendor"), cpuVendor);
|
||||
if (cpuFamily >= 0) SetInt32Property(NS_LITERAL_STRING("cpufamily"), cpuFamily);
|
||||
if (cpuModel >= 0) SetInt32Property(NS_LITERAL_STRING("cpumodel"), cpuModel);
|
||||
if (cpuStepping >= 0) SetInt32Property(NS_LITERAL_STRING("cpustepping"), cpuStepping);
|
||||
|
||||
if (logicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucount"), logicalCPUs);
|
||||
if (physicalCPUs >= 0) SetInt32Property(NS_LITERAL_STRING("cpucores"), physicalCPUs);
|
||||
|
||||
if (cacheSizeL2 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel2"), cacheSizeL2);
|
||||
if (cacheSizeL3 >= 0) SetInt32Property(NS_LITERAL_STRING("cpucachel3"), cacheSizeL3);
|
||||
|
||||
for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) {
|
||||
rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name),
|
||||
cpuPropItems[i].propfun());
|
||||
|
Loading…
Reference in New Issue
Block a user