Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,205 @@
/* global SettingsListener, Service */
(function(exports) {
'use strict';
/**
* The Developer HUD displays app metrics as an overlay on top of MozApps.
* @class DeveloperHud
*/
function DeveloperHud() {
SettingsListener.observe('hud.hide', false, this.hide.bind(this));
SettingsListener.observe('devtools.overlay.system',
false, this.toggleSystemHUD.bind(this));
}
DeveloperHud.prototype = {
name: 'DeveloperHud',
start: function() {
window.addEventListener('developer-hud-update', this);
Service.register('stop', this);
},
stop: function() {
window.removeEventListener('developer-hud-update', this);
},
hide: function(hidden) {
var screen = document.getElementById('screen');
screen.classList.toggle('hidden-developer-hud', hidden);
},
_showSystemHUD: false,
toggleSystemHUD: function(enabled) {
if (!enabled) {
this.display(window, {});
}
this._showSystemHUD = enabled;
},
handleEvent: function(e) {
this.display(e.target, e.detail);
e.preventDefault();
},
/**
* Display a HUD over an app to show its metrics' values.
* @param {Object} target The iframe of the app being tracked.
* @param {Object} data The metric values to display.
*/
display: function(target, data) {
if (!target) {
return;
}
// For regular mozbrowser iframes use the div container.
var appwindow = target.parentElement;
// For system messages, directly insert the hud into the #screen
// wrapper if needed.
if (!appwindow) {
if (target === window && this._showSystemHUD) {
appwindow = document.getElementById('screen');
} else {
return;
}
}
var overlay = appwindow.querySelector(':scope > .developer-hud');
if (!overlay) {
overlay = document.createElement('div');
overlay.classList.add('developer-hud');
appwindow.appendChild(overlay);
}
if (!data.metrics || data.metrics.length < 1) {
overlay.remove();
return;
}
var canvas = overlay.querySelector('.widgets');
if (!canvas) {
canvas = document.createElement('canvas');
canvas.classList.add('widgets');
canvas.height = 30;
overlay.appendChild(canvas);
}
// The width is always set to the size of the screen in case the screen
// has been rotated. This does not cause a reflow as long as the width
// is the same.
canvas.width = window.innerWidth;
var ctx = canvas.getContext('2d');
ctx.font = '18px sans-serif';
ctx.textBaseline = 'top';
ctx.save();
// Widgets are positioned starting from the right side of the screen.
ctx.translate(canvas.width, 0);
data.metrics.reverse().forEach((function(metric) {
var widget = this.widget(metric);
if (!widget) {
return;
}
// The size of a widget is comprise between 30px and the size of its
// content. There is also an additional padding of 5px on each side.
var textWidth = ctx.measureText(widget.value).width;
var widgetWidth = Math.max(30, textWidth) + (5 * 2);
// Position the widget relatively to the last position on the left
// of the screen.
ctx.translate(-widgetWidth, 0);
// Fill widget background-color.
ctx.fillStyle = widget.color;
ctx.fillRect(0, 0, widgetWidth, canvas.height);
// Draw widget text centered both horizontally and vertically.
ctx.fillStyle = 'white';
ctx.fillText(widget.value,
(widgetWidth - textWidth) / 2,
canvas.height / 4);
}).bind(this));
ctx.restore();
},
widget: function(metric) {
var value = metric.value;
if (!value) {
return null;
}
var color;
switch(metric.name) {
case 'warnings':
color = 'orange';
break;
case 'errors':
color = 'red';
break;
case 'security':
color = 'black';
break;
case 'reflows':
color = 'purple';
break;
case 'jank':
color = 'cornflowerblue';
value += 'ms';
break;
case 'uss':
color = 'dimgrey';
value = this.formatMemory(value);
break;
case 'memory':
color = 'lightslategrey';
value = this.formatMemory(value);
break;
default:
color = this.colorHash(metric.name);
break;
}
return {
'color': color,
'value': value
};
},
colorHash: function(name) {
var hue = 0;
for (var i = 0; i < name.length; i++) {
hue += name.charCodeAt(i);
}
return 'hsl(' + (hue % 360) + ', 75%, 50%)';
},
formatMemory: function(bytes) {
var prefix = ['','K','M','G','T','P','E','Z','Y'];
var i = 0;
for (; bytes > 1024 && i < prefix.length; ++i) {
bytes /= 1024;
}
return (Math.round(bytes * 100) / 100) + ' ' + prefix[i] + 'B';
}
};
exports.DeveloperHud = DeveloperHud;
}(window));