зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
66b7c55e79
|
@ -26,6 +26,13 @@
|
||||||
padding: 15px 10px 0;
|
padding: 15px 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#release {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 125%;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#version {
|
#version {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
|
@ -78,6 +78,9 @@ function init(aEvent) {
|
||||||
currentChannelText.hidden = true;
|
currentChannelText.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AppConstants.MOZ_UPDATE_CHANNEL == "esr") {
|
||||||
|
document.getElementById("release").hidden = false;
|
||||||
|
}
|
||||||
if (AppConstants.platform == "macosx") {
|
if (AppConstants.platform == "macosx") {
|
||||||
// it may not be sized at this point, and we need its width to calculate its position
|
// it may not be sized at this point, and we need its width to calculate its position
|
||||||
window.sizeToContent();
|
window.sizeToContent();
|
||||||
|
|
|
@ -45,6 +45,10 @@
|
||||||
<hbox id="clientBox">
|
<hbox id="clientBox">
|
||||||
<vbox id="leftBox" flex="1"/>
|
<vbox id="leftBox" flex="1"/>
|
||||||
<vbox id="rightBox" flex="1">
|
<vbox id="rightBox" flex="1">
|
||||||
|
<label id="release" hidden="true">
|
||||||
|
<!-- This string is explicitly not translated -->
|
||||||
|
Extended Support Release
|
||||||
|
</label>
|
||||||
<hbox align="baseline">
|
<hbox align="baseline">
|
||||||
#expand <label id="version">__MOZ_APP_VERSION_DISPLAY__</label>
|
#expand <label id="version">__MOZ_APP_VERSION_DISPLAY__</label>
|
||||||
<label id="releasenotes" class="text-link" hidden="true">&releaseNotes.link;</label>
|
<label id="releasenotes" class="text-link" hidden="true">&releaseNotes.link;</label>
|
||||||
|
|
|
@ -294,10 +294,7 @@ function setText(id, value) {
|
||||||
if (element.localName == "textbox" || element.localName == "label")
|
if (element.localName == "textbox" || element.localName == "label")
|
||||||
element.value = value;
|
element.value = value;
|
||||||
else {
|
else {
|
||||||
if (element.hasChildNodes())
|
element.textContent = value;
|
||||||
element.firstChild.remove();
|
|
||||||
var textNode = document.createTextNode(value);
|
|
||||||
element.appendChild(textNode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,9 +298,11 @@ var Policies = {
|
||||||
setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
|
setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
|
||||||
setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
|
setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
|
||||||
} else {
|
} else {
|
||||||
|
setDefaultPref("browser.startup.homepage", homepages);
|
||||||
|
setDefaultPref("browser.startup.page", 1);
|
||||||
runOncePerModification("setHomepage", homepages, () => {
|
runOncePerModification("setHomepage", homepages, () => {
|
||||||
Services.prefs.setStringPref("browser.startup.homepage", homepages);
|
Services.prefs.clearUserPref("browser.startup.homepage");
|
||||||
Services.prefs.setIntPref("browser.startup.page", 1);
|
Services.prefs.clearUserPref("browser.startup.page");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ this.EnterprisePolicyTesting = {
|
||||||
let promise = new Promise(resolve => {
|
let promise = new Promise(resolve => {
|
||||||
Services.obs.addObserver(function observer() {
|
Services.obs.addObserver(function observer() {
|
||||||
Services.obs.removeObserver(observer, "EnterprisePolicies:AllPoliciesApplied");
|
Services.obs.removeObserver(observer, "EnterprisePolicies:AllPoliciesApplied");
|
||||||
dump(`bytesized: setupPolicyEngineWithJson resolving`);
|
|
||||||
resolve();
|
resolve();
|
||||||
}, "EnterprisePolicies:AllPoliciesApplied");
|
}, "EnterprisePolicies:AllPoliciesApplied");
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,10 +36,10 @@ endif
|
||||||
MOZ_SFX_PACKAGE=$(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
|
MOZ_SFX_PACKAGE=$(topsrcdir)/other-licenses/7zstub/firefox/7zSD.sfx
|
||||||
MOZ_INSTALLER_PATH=$(topsrcdir)/browser/installer/windows
|
MOZ_INSTALLER_PATH=$(topsrcdir)/browser/installer/windows
|
||||||
|
|
||||||
SEARCHPLUGINS_FILENAMES := $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD)))
|
SEARCHPLUGINS_FILENAMES := $(or $(shell $(call py_action,output_searchplugins_list,$(srcdir)/search/list.json $(AB_CD))), $(error Missing search plugins))
|
||||||
SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
|
SEARCHPLUGINS_PATH := .deps/generated_$(AB_CD)
|
||||||
SEARCHPLUGINS_TARGET := libs searchplugins
|
SEARCHPLUGINS_TARGET := libs searchplugins
|
||||||
SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(srcdir)/searchplugins/$(plugin)),$(warning Missing searchplugin: $(plugin))))
|
SEARCHPLUGINS := $(foreach plugin,$(addsuffix .xml,$(SEARCHPLUGINS_FILENAMES)),$(or $(wildcard $(srcdir)/searchplugins/$(plugin)),$(error Missing searchplugin: $(plugin))))
|
||||||
# Some locale-specific search plugins may have preprocessor directives, but the
|
# Some locale-specific search plugins may have preprocessor directives, but the
|
||||||
# default en-US ones do not.
|
# default en-US ones do not.
|
||||||
SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
|
SEARCHPLUGINS_FLAGS := --silence-missing-directive-warnings
|
||||||
|
|
|
@ -1354,6 +1354,9 @@ def security_hardening_cflags(hardening_flag, asan, optimize, c_compiler, target
|
||||||
# fno-common -----------------------------------------
|
# fno-common -----------------------------------------
|
||||||
# Do not merge variables for ASAN; can detect some subtle bugs
|
# Do not merge variables for ASAN; can detect some subtle bugs
|
||||||
if asan:
|
if asan:
|
||||||
|
# clang-cl does not recognize the flag, it must be passed down to clang
|
||||||
|
if c_compiler.type == 'clang-cl':
|
||||||
|
flags.append("-Xclang")
|
||||||
flags.append("-fno-common")
|
flags.append("-fno-common")
|
||||||
|
|
||||||
return namespace(
|
return namespace(
|
||||||
|
|
|
@ -13,15 +13,15 @@ const { require, DevToolsLoader } = ChromeUtils.import("resource://devtools/shar
|
||||||
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
ChromeUtils.defineModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
|
ChromeUtils.defineModuleGetter(this, "Subprocess", "resource://gre/modules/Subprocess.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "Telemetry", function() {
|
XPCOMUtils.defineLazyGetter(this, "Telemetry", function() {
|
||||||
return require("devtools/client/shared/telemetry");
|
return require("devtools/client/shared/telemetry");
|
||||||
});
|
});
|
||||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||||
return require("devtools/shared/event-emitter");
|
return require("devtools/shared/event-emitter");
|
||||||
});
|
});
|
||||||
XPCOMUtils.defineLazyGetter(this, "system", function() {
|
|
||||||
return require("devtools/shared/system");
|
|
||||||
});
|
|
||||||
const promise = require("promise");
|
const promise = require("promise");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ BrowserToolboxProcess.prototype = {
|
||||||
// well.
|
// well.
|
||||||
//
|
//
|
||||||
// As an approximation of "isLocalBuild", check for an unofficial build.
|
// As an approximation of "isLocalBuild", check for an unofficial build.
|
||||||
if (!system.constants.MOZILLA_OFFICIAL) {
|
if (!AppConstants.MOZILLA_OFFICIAL) {
|
||||||
args.push("-purgecaches");
|
args.push("-purgecaches");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ const defer = require("devtools/shared/defer");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const {DOMHelpers} = require("resource://devtools/client/shared/DOMHelpers.jsm");
|
const {DOMHelpers} = require("resource://devtools/client/shared/DOMHelpers.jsm");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
|
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
|
||||||
|
|
||||||
/* A host should always allow this much space for the page to be displayed.
|
/* A host should always allow this much space for the page to be displayed.
|
||||||
|
@ -295,7 +295,7 @@ WindowHost.prototype = {
|
||||||
win.focus();
|
win.focus();
|
||||||
|
|
||||||
let key;
|
let key;
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
key = win.document.getElementById("toolbox-key-toggle-osx");
|
key = win.document.getElementById("toolbox-key-toggle-osx");
|
||||||
} else {
|
} else {
|
||||||
key = win.document.getElementById("toolbox-key-toggle");
|
key = win.document.getElementById("toolbox-key-toggle");
|
||||||
|
|
|
@ -11,7 +11,7 @@ const {gDevTools} = require("devtools/client/framework/devtools");
|
||||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||||
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
|
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
|
|
||||||
exports.OptionsPanel = OptionsPanel;
|
exports.OptionsPanel = OptionsPanel;
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ OptionsPanel.prototype = {
|
||||||
* Add common preferences enabled only on Nightly.
|
* Add common preferences enabled only on Nightly.
|
||||||
*/
|
*/
|
||||||
setupNightlyOptions: function() {
|
setupNightlyOptions: function() {
|
||||||
let isNightly = system.constants.NIGHTLY_BUILD;
|
let isNightly = AppConstants.NIGHTLY_BUILD;
|
||||||
if (!isNightly) {
|
if (!isNightly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ function isNodeVisible(node) {
|
||||||
*/
|
*/
|
||||||
function waitForUpdate(inspector, waitForSelectionUpdate) {
|
function waitForUpdate(inspector, waitForSelectionUpdate) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
inspector.on("boxmodel-view-updated", function onUpdate(e, reasons) {
|
inspector.on("boxmodel-view-updated", function onUpdate(reasons) {
|
||||||
// Wait for another update event if we are waiting for a selection related event.
|
// Wait for another update event if we are waiting for a selection related event.
|
||||||
if (waitForSelectionUpdate && !reasons.includes("new-selection")) {
|
if (waitForSelectionUpdate && !reasons.includes("new-selection")) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -15,7 +15,7 @@ const MAX_LABEL_LENGTH = 40;
|
||||||
const NS_XHTML = "http://www.w3.org/1999/xhtml";
|
const NS_XHTML = "http://www.w3.org/1999/xhtml";
|
||||||
const SCROLL_REPEAT_MS = 100;
|
const SCROLL_REPEAT_MS = 100;
|
||||||
|
|
||||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
||||||
|
|
||||||
// Some margin may be required for visible element detection.
|
// Some margin may be required for visible element detection.
|
||||||
|
@ -401,11 +401,12 @@ HTMLBreadcrumbs.prototype = {
|
||||||
this.breadcrumbsWidgetItemId = 0;
|
this.breadcrumbsWidgetItemId = 0;
|
||||||
|
|
||||||
this.update = this.update.bind(this);
|
this.update = this.update.bind(this);
|
||||||
|
this.updateWithMutations = this.updateWithMutations.bind(this);
|
||||||
this.updateSelectors = this.updateSelectors.bind(this);
|
this.updateSelectors = this.updateSelectors.bind(this);
|
||||||
this.selection.on("new-node-front", this.update);
|
this.selection.on("new-node-front", this.update);
|
||||||
this.selection.on("pseudoclass", this.updateSelectors);
|
this.selection.on("pseudoclass", this.updateSelectors);
|
||||||
this.selection.on("attribute-changed", this.updateSelectors);
|
this.selection.on("attribute-changed", this.updateSelectors);
|
||||||
this.inspector.on("markupmutation", this.update);
|
this.inspector.on("markupmutation", this.updateWithMutations);
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -612,7 +613,7 @@ HTMLBreadcrumbs.prototype = {
|
||||||
this.selection.off("new-node-front", this.update);
|
this.selection.off("new-node-front", this.update);
|
||||||
this.selection.off("pseudoclass", this.updateSelectors);
|
this.selection.off("pseudoclass", this.updateSelectors);
|
||||||
this.selection.off("attribute-changed", this.updateSelectors);
|
this.selection.off("attribute-changed", this.updateSelectors);
|
||||||
this.inspector.off("markupmutation", this.update);
|
this.inspector.off("markupmutation", this.updateWithMutations);
|
||||||
|
|
||||||
this.container.removeEventListener("click", this, true);
|
this.container.removeEventListener("click", this, true);
|
||||||
this.container.removeEventListener("mouseover", this, true);
|
this.container.removeEventListener("mouseover", this, true);
|
||||||
|
@ -829,6 +830,16 @@ HTMLBreadcrumbs.prototype = {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the breadcrumbs display when a new node is selected and there are
|
||||||
|
* mutations.
|
||||||
|
* @param {Array} mutations An array of mutations in case this was called as
|
||||||
|
* the "markupmutation" event listener.
|
||||||
|
*/
|
||||||
|
updateWithMutations(mutations) {
|
||||||
|
return this.update("markupmutation", mutations);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the breadcrumbs display when a new node is selected.
|
* Update the breadcrumbs display when a new node is selected.
|
||||||
* @param {String} reason The reason for the update, if any.
|
* @param {String} reason The reason for the update, if any.
|
||||||
|
|
|
@ -8,7 +8,7 @@ const promise = require("promise");
|
||||||
const {Task} = require("devtools/shared/task");
|
const {Task} = require("devtools/shared/task");
|
||||||
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
||||||
|
|
||||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
|
const AutocompletePopup = require("devtools/client/shared/autocomplete-popup");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const promise = require("promise");
|
const promise = require("promise");
|
||||||
const EventEmitter = require("devtools/shared/old-event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const {executeSoon} = require("devtools/shared/DevToolsUtils");
|
const {executeSoon} = require("devtools/shared/DevToolsUtils");
|
||||||
const {Task} = require("devtools/shared/task");
|
const {Task} = require("devtools/shared/task");
|
||||||
const {PrefObserver} = require("devtools/client/shared/prefs");
|
const {PrefObserver} = require("devtools/client/shared/prefs");
|
||||||
|
@ -123,6 +123,7 @@ function Inspector(toolbox) {
|
||||||
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
|
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
|
||||||
this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
|
this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
|
||||||
this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this);
|
this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this);
|
||||||
|
this._clearSearchResultsLabel = this._clearSearchResultsLabel.bind(this);
|
||||||
|
|
||||||
this.onDetached = this.onDetached.bind(this);
|
this.onDetached = this.onDetached.bind(this);
|
||||||
this.onMarkupLoaded = this.onMarkupLoaded.bind(this);
|
this.onMarkupLoaded = this.onMarkupLoaded.bind(this);
|
||||||
|
@ -383,7 +384,7 @@ Inspector.prototype = {
|
||||||
this.searchResultsLabel = this.panelDoc.getElementById("inspector-searchlabel");
|
this.searchResultsLabel = this.panelDoc.getElementById("inspector-searchlabel");
|
||||||
|
|
||||||
this.search = new InspectorSearch(this, this.searchBox, this.searchClearButton);
|
this.search = new InspectorSearch(this, this.searchBox, this.searchClearButton);
|
||||||
this.search.on("search-cleared", this._updateSearchResultsLabel);
|
this.search.on("search-cleared", this._clearSearchResultsLabel);
|
||||||
this.search.on("search-result", this._updateSearchResultsLabel);
|
this.search.on("search-result", this._updateSearchResultsLabel);
|
||||||
|
|
||||||
let shortcuts = new KeyShortcuts({
|
let shortcuts = new KeyShortcuts({
|
||||||
|
@ -405,9 +406,13 @@ Inspector.prototype = {
|
||||||
return this.search.autocompleter;
|
return this.search.autocompleter;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateSearchResultsLabel: function(event, result) {
|
_clearSearchResultsLabel: function(result) {
|
||||||
|
return this._updateSearchResultsLabel(result, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateSearchResultsLabel: function(result, clear = false) {
|
||||||
let str = "";
|
let str = "";
|
||||||
if (event !== "search-cleared") {
|
if (!clear) {
|
||||||
if (result) {
|
if (result) {
|
||||||
str = INSPECTOR_L10N.getFormatStr(
|
str = INSPECTOR_L10N.getFormatStr(
|
||||||
"inspector.searchResultsCount2", result.resultsIndex + 1, result.resultsLength);
|
"inspector.searchResultsCount2", result.resultsIndex + 1, result.resultsLength);
|
||||||
|
@ -559,7 +564,7 @@ Inspector.prototype = {
|
||||||
this.toolbox.emit("inspector-sidebar-resized", { width, height });
|
this.toolbox.emit("inspector-sidebar-resized", { width, height });
|
||||||
},
|
},
|
||||||
|
|
||||||
onSidebarSelect: function(event, toolId) {
|
onSidebarSelect: function(toolId) {
|
||||||
// Save the currently selected sidebar panel
|
// Save the currently selected sidebar panel
|
||||||
Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
|
Services.prefs.setCharPref("devtools.inspector.activeSidebar", toolId);
|
||||||
|
|
||||||
|
|
|
@ -1283,7 +1283,7 @@ MarkupView.prototype = {
|
||||||
let parentContainer = this.getContainer(removedNode.parentNode());
|
let parentContainer = this.getContainer(removedNode.parentNode());
|
||||||
let childIndex = parentContainer.getChildContainers().indexOf(oldContainer);
|
let childIndex = parentContainer.getChildContainers().indexOf(oldContainer);
|
||||||
|
|
||||||
let onMutations = this._removedNodeObserver = (e, mutations) => {
|
let onMutations = this._removedNodeObserver = mutations => {
|
||||||
let isNodeRemovalMutation = false;
|
let isNodeRemovalMutation = false;
|
||||||
for (let mutation of mutations) {
|
for (let mutation of mutations) {
|
||||||
let containsRemovedNode = mutation.removed &&
|
let containsRemovedNode = mutation.removed &&
|
||||||
|
|
|
@ -272,6 +272,6 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Record all containers that are created dynamically into elms object.
|
// Record all containers that are created dynamically into elms object.
|
||||||
function memorizeContainer(event, container) {
|
function memorizeContainer(container) {
|
||||||
elms[`container-${containerID++}`] = container;
|
elms[`container-${containerID++}`] = container;
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,7 +319,7 @@ add_task(function* () {
|
||||||
// event or possibly in multiples.
|
// event or possibly in multiples.
|
||||||
let seenMutations = 0;
|
let seenMutations = 0;
|
||||||
let promise = new Promise(resolve => {
|
let promise = new Promise(resolve => {
|
||||||
inspector.on("markupmutation", function onmutation(e, mutations) {
|
inspector.on("markupmutation", function onmutation(mutations) {
|
||||||
seenMutations += mutations.length;
|
seenMutations += mutations.length;
|
||||||
info("Receieved " + seenMutations +
|
info("Receieved " + seenMutations +
|
||||||
" mutations, expecting at least " + numMutations);
|
" mutations, expecting at least " + numMutations);
|
||||||
|
|
|
@ -547,7 +547,7 @@ ElementEditor.prototype = {
|
||||||
.filter(el => el.style.display != "none");
|
.filter(el => el.style.display != "none");
|
||||||
let attributeIndex = activeAttrs.indexOf(attrNode);
|
let attributeIndex = activeAttrs.indexOf(attrNode);
|
||||||
|
|
||||||
let onMutations = this._editedAttributeObserver = (e, mutations) => {
|
let onMutations = this._editedAttributeObserver = mutations => {
|
||||||
let isDeletedAttribute = false;
|
let isDeletedAttribute = false;
|
||||||
let isNewAttribute = false;
|
let isNewAttribute = false;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
// Bug 1275446 - This test happen to hit the default timeout on linux32
|
// Bug 1275446 - This test happen to hit the default timeout on linux32
|
||||||
requestLongerTimeout(2);
|
requestLongerTimeout(2);
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
|
|
||||||
const TEST_URI = `
|
const TEST_URI = `
|
||||||
<style>
|
<style>
|
||||||
|
@ -294,7 +294,7 @@ function* testIncrement(editor, options, view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let smallIncrementKey = {ctrlKey: options.ctrl};
|
let smallIncrementKey = {ctrlKey: options.ctrl};
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
smallIncrementKey = {altKey: options.alt};
|
smallIncrementKey = {altKey: options.alt};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ function* testIncrement(editor, options, view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSmallIncrementKey() {
|
function getSmallIncrementKey() {
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
return { alt: true };
|
return { alt: true };
|
||||||
}
|
}
|
||||||
return { ctrl: true };
|
return { ctrl: true };
|
||||||
|
|
|
@ -478,7 +478,7 @@ function* sendKeysAndWaitForFocus(view, element, keys) {
|
||||||
*/
|
*/
|
||||||
function waitForStyleModification(inspector) {
|
function waitForStyleModification(inspector) {
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
function checkForStyleModification(name, mutations) {
|
function checkForStyleModification(mutations) {
|
||||||
for (let mutation of mutations) {
|
for (let mutation of mutations) {
|
||||||
if (mutation.type === "attributes" && mutation.attributeName === "style") {
|
if (mutation.type === "attributes" && mutation.attributeName === "style") {
|
||||||
inspector.off("markupmutation", checkForStyleModification);
|
inspector.off("markupmutation", checkForStyleModification);
|
||||||
|
|
|
@ -169,7 +169,7 @@ ClassListPreviewerModel.prototype = {
|
||||||
return mod.apply();
|
return mod.apply();
|
||||||
},
|
},
|
||||||
|
|
||||||
onMutations(e, mutations) {
|
onMutations(mutations) {
|
||||||
for (let {type, target, attributeName} of mutations) {
|
for (let {type, target, attributeName} of mutations) {
|
||||||
// Only care if this mutation is for the class attribute.
|
// Only care if this mutation is for the class attribute.
|
||||||
if (type !== "attributes" || attributeName !== "class") {
|
if (type !== "attributes" || attributeName !== "class") {
|
||||||
|
|
|
@ -261,7 +261,7 @@ DomNodePreview.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onMarkupMutations: function(e, mutations) {
|
onMarkupMutations: function(mutations) {
|
||||||
if (!this.nodeFront) {
|
if (!this.nodeFront) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -861,7 +861,7 @@ class HighlightersOverlay {
|
||||||
* Handler function for "markupmutation" events. Hides the flexbox/grid/shapes
|
* Handler function for "markupmutation" events. Hides the flexbox/grid/shapes
|
||||||
* highlighter if the flexbox/grid/shapes container is no longer in the DOM tree.
|
* highlighter if the flexbox/grid/shapes container is no longer in the DOM tree.
|
||||||
*/
|
*/
|
||||||
async onMarkupMutation(evt, mutations) {
|
async onMarkupMutation(mutations) {
|
||||||
let hasInterestingMutation = mutations.some(mut => mut.type === "childList");
|
let hasInterestingMutation = mutations.some(mut => mut.type === "childList");
|
||||||
if (!hasInterestingMutation) {
|
if (!hasInterestingMutation) {
|
||||||
// Bail out if the mutations did not remove nodes, or if no grid highlighter is
|
// Bail out if the mutations did not remove nodes, or if no grid highlighter is
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var EventEmitter = require("devtools/shared/old-event-emitter");
|
var EventEmitter = require("devtools/shared/event-emitter");
|
||||||
var Telemetry = require("devtools/client/shared/telemetry");
|
var Telemetry = require("devtools/client/shared/telemetry");
|
||||||
var { Task } = require("devtools/shared/task");
|
var { Task } = require("devtools/shared/task");
|
||||||
|
|
||||||
|
|
|
@ -50,20 +50,10 @@ async function addJsonViewTab(url, {
|
||||||
docReadyState = "complete",
|
docReadyState = "complete",
|
||||||
} = {}) {
|
} = {}) {
|
||||||
info("Adding a new JSON tab with URL: '" + url + "'");
|
info("Adding a new JSON tab with URL: '" + url + "'");
|
||||||
|
let tabAdded = BrowserTestUtils.waitForNewTab(gBrowser, url);
|
||||||
let tabLoaded = addTab(url);
|
let tabLoaded = addTab(url);
|
||||||
let tab = gBrowser.selectedTab;
|
let tab = await Promise.race([tabAdded, tabLoaded]);
|
||||||
let browser = tab.linkedBrowser;
|
let browser = tab.linkedBrowser;
|
||||||
await Promise.race([tabLoaded, new Promise(resolve => {
|
|
||||||
browser.webProgress.addProgressListener({
|
|
||||||
QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
|
|
||||||
"nsISupportsWeakReference"]),
|
|
||||||
onLocationChange(webProgress) {
|
|
||||||
// Fires when the tab is ready but before completely loaded.
|
|
||||||
webProgress.removeProgressListener(this);
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
}, Ci.nsIWebProgress.NOTIFY_LOCATION);
|
|
||||||
})]);
|
|
||||||
|
|
||||||
// Load devtools/shared/test/frame-script-utils.js
|
// Load devtools/shared/test/frame-script-utils.js
|
||||||
loadFrameScriptUtils();
|
loadFrameScriptUtils();
|
||||||
|
|
|
@ -80,12 +80,6 @@ class RequestListContent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const { connector, cloneSelectedRequest, openStatistics } = this.props;
|
|
||||||
this.contextMenu = new RequestListContextMenu({
|
|
||||||
connector,
|
|
||||||
cloneSelectedRequest,
|
|
||||||
openStatistics,
|
|
||||||
});
|
|
||||||
this.tooltip = new HTMLTooltip(window.parent.document, { type: "arrow" });
|
this.tooltip = new HTMLTooltip(window.parent.document, { type: "arrow" });
|
||||||
window.addEventListener("resize", this.onResize);
|
window.addEventListener("resize", this.onResize);
|
||||||
}
|
}
|
||||||
|
@ -244,6 +238,16 @@ class RequestListContent extends Component {
|
||||||
onContextMenu(evt) {
|
onContextMenu(evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
let { selectedRequest, displayedRequests } = this.props;
|
let { selectedRequest, displayedRequests } = this.props;
|
||||||
|
|
||||||
|
if (!this.contextMenu) {
|
||||||
|
const { connector, cloneSelectedRequest, openStatistics } = this.props;
|
||||||
|
this.contextMenu = new RequestListContextMenu({
|
||||||
|
connector,
|
||||||
|
cloneSelectedRequest,
|
||||||
|
openStatistics,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.contextMenu.open(evt, selectedRequest, displayedRequests);
|
this.contextMenu.open(evt, selectedRequest, displayedRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ const Services = require("Services");
|
||||||
const focusManager = Services.focus;
|
const focusManager = Services.focus;
|
||||||
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
const {KeyCodes} = require("devtools/client/shared/keycodes");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
const CONTENT_TYPES = {
|
const CONTENT_TYPES = {
|
||||||
|
@ -1209,7 +1209,7 @@ InplaceEditor.prototype = {
|
||||||
*/
|
*/
|
||||||
_getIncrement: function(event) {
|
_getIncrement: function(event) {
|
||||||
const getSmallIncrementKey = (evt) => {
|
const getSmallIncrementKey = (evt) => {
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
return evt.altKey;
|
return evt.altKey;
|
||||||
}
|
}
|
||||||
return evt.ctrlKey;
|
return evt.ctrlKey;
|
||||||
|
|
|
@ -11,7 +11,7 @@ if (/Mac OS X/.test(window.navigator.userAgent)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
constants: {
|
AppConstants: {
|
||||||
platform: platform
|
platform
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -16,7 +16,9 @@ const { JSTerm } = require("devtools/client/webconsole/jsterm");
|
||||||
const { WebConsoleConnectionProxy } = require("devtools/client/webconsole/webconsole-connection-proxy");
|
const { WebConsoleConnectionProxy } = require("devtools/client/webconsole/webconsole-connection-proxy");
|
||||||
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
|
||||||
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
|
const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages");
|
||||||
const system = require("devtools/shared/system");
|
|
||||||
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
|
|
||||||
const ZoomKeys = require("devtools/client/shared/zoom-keys");
|
const ZoomKeys = require("devtools/client/shared/zoom-keys");
|
||||||
|
|
||||||
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
|
const PREF_MESSAGE_TIMESTAMP = "devtools.webconsole.timestampMessages";
|
||||||
|
@ -240,7 +242,7 @@ NewWebConsoleFrame.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
let clearShortcut;
|
let clearShortcut;
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
clearShortcut = l10n.getStr("webconsole.clear.keyOSX");
|
clearShortcut = l10n.getStr("webconsole.clear.keyOSX");
|
||||||
} else {
|
} else {
|
||||||
clearShortcut = l10n.getStr("webconsole.clear.key");
|
clearShortcut = l10n.getStr("webconsole.clear.key");
|
||||||
|
@ -254,7 +256,7 @@ NewWebConsoleFrame.prototype = {
|
||||||
|
|
||||||
ZoomKeys.register(this.window);
|
ZoomKeys.register(this.window);
|
||||||
|
|
||||||
if (!system.constants.MOZILLA_OFFICIAL) {
|
if (!AppConstants.MOZILLA_OFFICIAL) {
|
||||||
// In local builds, inject the "quick restart" shortcut.
|
// In local builds, inject the "quick restart" shortcut.
|
||||||
// This script expects to have Services on the global and we haven't yet imported
|
// This script expects to have Services on the global and we haven't yet imported
|
||||||
// it into the window, so assign it.
|
// it into the window, so assign it.
|
||||||
|
|
|
@ -25,12 +25,12 @@ const {PrefObserver} = require("devtools/client/shared/prefs");
|
||||||
loader.lazyServiceGetter(this, "clipboardHelper",
|
loader.lazyServiceGetter(this, "clipboardHelper",
|
||||||
"@mozilla.org/widget/clipboardhelper;1",
|
"@mozilla.org/widget/clipboardhelper;1",
|
||||||
"nsIClipboardHelper");
|
"nsIClipboardHelper");
|
||||||
|
loader.lazyRequireGetter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm", true);
|
||||||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||||
loader.lazyRequireGetter(this, "ConsoleOutput", "devtools/client/webconsole/console-output", true);
|
loader.lazyRequireGetter(this, "ConsoleOutput", "devtools/client/webconsole/console-output", true);
|
||||||
loader.lazyRequireGetter(this, "Messages", "devtools/client/webconsole/console-output", true);
|
loader.lazyRequireGetter(this, "Messages", "devtools/client/webconsole/console-output", true);
|
||||||
loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/environment-client");
|
loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/environment-client");
|
||||||
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
|
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
|
||||||
loader.lazyRequireGetter(this, "system", "devtools/shared/system");
|
|
||||||
loader.lazyRequireGetter(this, "JSTerm", "devtools/client/webconsole/jsterm", true);
|
loader.lazyRequireGetter(this, "JSTerm", "devtools/client/webconsole/jsterm", true);
|
||||||
loader.lazyRequireGetter(this, "gSequenceId", "devtools/client/webconsole/jsterm", true);
|
loader.lazyRequireGetter(this, "gSequenceId", "devtools/client/webconsole/jsterm", true);
|
||||||
loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm");
|
loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm");
|
||||||
|
@ -642,7 +642,7 @@ WebConsoleFrame.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
let clearShortcut;
|
let clearShortcut;
|
||||||
if (system.constants.platform === "macosx") {
|
if (AppConstants.platform === "macosx") {
|
||||||
clearShortcut = l10n.getStr("webconsole.clear.keyOSX");
|
clearShortcut = l10n.getStr("webconsole.clear.keyOSX");
|
||||||
} else {
|
} else {
|
||||||
clearShortcut = l10n.getStr("webconsole.clear.key");
|
clearShortcut = l10n.getStr("webconsole.clear.key");
|
||||||
|
|
|
@ -87,7 +87,7 @@ webpackConfig.resolve = {
|
||||||
"devtools/client/shared/vendor/redux": "redux",
|
"devtools/client/shared/vendor/redux": "redux",
|
||||||
"devtools/client/shared/vendor/reselect": "reselect",
|
"devtools/client/shared/vendor/reselect": "reselect",
|
||||||
|
|
||||||
"devtools/shared/system": path.join(__dirname, "../../client/shared/webpack/shims/system-stub"),
|
"resource://gre/modules/AppConstants.jsm": path.join(__dirname, "../../client/shared/webpack/shims/app-constants-stub"),
|
||||||
|
|
||||||
"devtools/client/framework/devtools": path.join(__dirname, "../../client/shared/webpack/shims/framework-devtools-shim"),
|
"devtools/client/framework/devtools": path.join(__dirname, "../../client/shared/webpack/shims/framework-devtools-shim"),
|
||||||
"devtools/client/framework/menu": "devtools-modules/src/menu",
|
"devtools/client/framework/menu": "devtools-modules/src/menu",
|
||||||
|
|
|
@ -265,39 +265,6 @@ function getScreenDimensions() {
|
||||||
return 11;
|
return 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function for fetching OS CPU and returning
|
|
||||||
* an enum for Telemetry.
|
|
||||||
*/
|
|
||||||
function getOSCPU() {
|
|
||||||
if (oscpu.includes("NT 5.1") || oscpu.includes("NT 5.2")) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("NT 6.0")) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("NT 6.1")) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("NT 6.2")) {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("NT 6.3")) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("OS X")) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("Linux")) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
if (oscpu.includes("NT 10.")) {
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
// Other OS.
|
|
||||||
return 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSetting(name) {
|
function getSetting(name) {
|
||||||
let deferred = defer();
|
let deferred = defer();
|
||||||
|
|
||||||
|
@ -326,5 +293,3 @@ function getSetting(name) {
|
||||||
exports.getSystemInfo = getSystemInfo;
|
exports.getSystemInfo = getSystemInfo;
|
||||||
exports.getSetting = getSetting;
|
exports.getSetting = getSetting;
|
||||||
exports.getScreenDimensions = getScreenDimensions;
|
exports.getScreenDimensions = getScreenDimensions;
|
||||||
exports.getOSCPU = getOSCPU;
|
|
||||||
exports.constants = AppConstants;
|
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
#define PREF_CUBEB_BACKEND "media.cubeb.backend"
|
#define PREF_CUBEB_BACKEND "media.cubeb.backend"
|
||||||
#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
|
#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
|
||||||
#define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
|
#define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
|
||||||
|
// Allows to get something non-default for the preferred sample-rate, to allow
|
||||||
|
// troubleshooting in the field and testing.
|
||||||
|
#define PREF_CUBEB_FORCE_SAMPLE_RATE "media.cubeb.force_sample_rate"
|
||||||
#define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
|
#define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
|
||||||
#define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
|
#define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
|
||||||
|
|
||||||
|
@ -122,6 +125,10 @@ cubeb* sCubebContext;
|
||||||
double sVolumeScale = 1.0;
|
double sVolumeScale = 1.0;
|
||||||
uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
|
uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
|
||||||
uint32_t sCubebMSGLatencyInFrames = 512;
|
uint32_t sCubebMSGLatencyInFrames = 512;
|
||||||
|
// If sCubebForcedSampleRate is zero, PreferredSampleRate will return the
|
||||||
|
// preferred sample-rate for the audio backend in use. Otherwise, it will be
|
||||||
|
// used as the preferred sample-rate.
|
||||||
|
uint32_t sCubebForcedSampleRate = 0;
|
||||||
bool sCubebPlaybackLatencyPrefSet = false;
|
bool sCubebPlaybackLatencyPrefSet = false;
|
||||||
bool sCubebMSGLatencyPrefSet = false;
|
bool sCubebMSGLatencyPrefSet = false;
|
||||||
bool sAudioStreamInitEverSucceeded = false;
|
bool sAudioStreamInitEverSucceeded = false;
|
||||||
|
@ -237,6 +244,9 @@ void PrefChanged(const char* aPref, void* aClosure)
|
||||||
// We don't want to limit the upper limit too much, so that people can
|
// We don't want to limit the upper limit too much, so that people can
|
||||||
// experiment.
|
// experiment.
|
||||||
sCubebMSGLatencyInFrames = std::min<uint32_t>(std::max<uint32_t>(value, 128), 1e6);
|
sCubebMSGLatencyInFrames = std::min<uint32_t>(std::max<uint32_t>(value, 128), 1e6);
|
||||||
|
} else if (strcmp(aPref, PREF_CUBEB_FORCE_SAMPLE_RATE) == 0) {
|
||||||
|
StaticMutexAutoLock lock(sMutex);
|
||||||
|
sCubebForcedSampleRate = Preferences::GetUint(aPref);
|
||||||
} else if (strcmp(aPref, PREF_CUBEB_LOGGING_LEVEL) == 0) {
|
} else if (strcmp(aPref, PREF_CUBEB_LOGGING_LEVEL) == 0) {
|
||||||
nsAutoCString value;
|
nsAutoCString value;
|
||||||
Preferences::GetCString(aPref, value);
|
Preferences::GetCString(aPref, value);
|
||||||
|
@ -323,6 +333,9 @@ bool InitPreferredSampleRate()
|
||||||
|
|
||||||
uint32_t PreferredSampleRate()
|
uint32_t PreferredSampleRate()
|
||||||
{
|
{
|
||||||
|
if (sCubebForcedSampleRate) {
|
||||||
|
return sCubebForcedSampleRate;
|
||||||
|
}
|
||||||
if (!InitPreferredSampleRate()) {
|
if (!InitPreferredSampleRate()) {
|
||||||
return 44100;
|
return 44100;
|
||||||
}
|
}
|
||||||
|
@ -563,6 +576,7 @@ void InitLibrary()
|
||||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
|
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
|
||||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
|
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
|
||||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
||||||
|
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
|
||||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
|
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
|
||||||
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
|
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
|
||||||
if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
|
if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
|
||||||
|
@ -592,6 +606,7 @@ void ShutdownLibrary()
|
||||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_SANDBOX);
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_SANDBOX);
|
||||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
|
||||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
|
||||||
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
|
||||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_MSG);
|
||||||
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
|
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ support-files =
|
||||||
sdpUtils.js
|
sdpUtils.js
|
||||||
addTurnsSelfsignedCert.js
|
addTurnsSelfsignedCert.js
|
||||||
parser_rtp.js
|
parser_rtp.js
|
||||||
|
peerconnection_audio_forced_sample_rate.js
|
||||||
!/dom/canvas/test/captureStream_common.js
|
!/dom/canvas/test/captureStream_common.js
|
||||||
!/dom/canvas/test/webgl-mochitest/webgl-util.js
|
!/dom/canvas/test/webgl-mochitest/webgl-util.js
|
||||||
!/dom/media/test/manifest.js
|
!/dom/media/test/manifest.js
|
||||||
|
@ -104,6 +105,10 @@ skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emula
|
||||||
skip-if = (android_version == '18') || (os == 'linux' && debug) # android(Bug 1189784, timeouts on 4.3 emulator), Bug 1432025
|
skip-if = (android_version == '18') || (os == 'linux' && debug) # android(Bug 1189784, timeouts on 4.3 emulator), Bug 1432025
|
||||||
[test_peerConnection_basicAudio.html]
|
[test_peerConnection_basicAudio.html]
|
||||||
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||||
|
[test_peerConnection_basicAudio_forced_lower_rate.html]
|
||||||
|
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||||
|
[test_peerConnection_basicAudio_forced_higher_rate.html]
|
||||||
|
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||||
[test_peerConnection_audioSynchronizationSources.html]
|
[test_peerConnection_audioSynchronizationSources.html]
|
||||||
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
|
||||||
[test_peerConnection_audioSynchronizationSourcesUnidirectional.html]
|
[test_peerConnection_audioSynchronizationSourcesUnidirectional.html]
|
||||||
|
@ -329,3 +334,4 @@ skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emula
|
||||||
[test_peerConnection_verifyDescriptions.html]
|
[test_peerConnection_verifyDescriptions.html]
|
||||||
skip-if = (android_version == '18')
|
skip-if = (android_version == '18')
|
||||||
[test_fingerprinting_resistance.html]
|
[test_fingerprinting_resistance.html]
|
||||||
|
[test_forceSampleRate.html]
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// This function takes a sample-rate, and tests that audio flows correctly when
|
||||||
|
// the sampling-rate at which the MSG runs is not one of the sampling-rates that
|
||||||
|
// the MediaPipeline can work with.
|
||||||
|
// It is in a separate file because we have an MSG per document, and we want to
|
||||||
|
// test multiple sample-rates, so we include it in multiple HTML mochitest
|
||||||
|
// files.
|
||||||
|
function test_peerconnection_audio_forced_sample_rate(forcedSampleRate) {
|
||||||
|
scriptsReady.then(function () {
|
||||||
|
pushPrefs(
|
||||||
|
["media.cubeb.force_sample_rate", forcedSampleRate]
|
||||||
|
).then(function () {
|
||||||
|
runNetworkTest(function (options) {
|
||||||
|
let test = new PeerConnectionTest(options);
|
||||||
|
let ac = new AudioContext();
|
||||||
|
test.setMediaConstraints([{
|
||||||
|
audio: true
|
||||||
|
}], []);
|
||||||
|
test.chain.replace("PC_LOCAL_GUM", [
|
||||||
|
function PC_LOCAL_WEBAUDIO_SOURCE(test) {
|
||||||
|
let oscillator = ac.createOscillator();
|
||||||
|
oscillator.type = 'sine';
|
||||||
|
oscillator.frequency.value = 700;
|
||||||
|
oscillator.start();
|
||||||
|
let dest = ac.createMediaStreamDestination();
|
||||||
|
oscillator.connect(dest);
|
||||||
|
test.pcLocal.attachLocalStream(dest.stream);
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
test.chain.append([
|
||||||
|
function CHECK_REMOTE_AUDIO_FLOW(test) {
|
||||||
|
return test.pcRemote.checkReceivingToneFrom(ac, test.pcLocal);
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
test.run();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test the pref media.cubeb.force_sample_rate</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>
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
const WEIRD_SAMPLE_RATE = 44101;
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SpecialPowers.pushPrefEnv({"set": [
|
||||||
|
["media.cubeb.force_sample_rate", WEIRD_SAMPLE_RATE]
|
||||||
|
]}).then(function() {
|
||||||
|
var ac = new AudioContext();
|
||||||
|
is(ac.sampleRate, WEIRD_SAMPLE_RATE, "Forced sample-rate set successfully.");
|
||||||
|
SimpleTest.finish();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="application/javascript" src="pc.js"></script>
|
||||||
|
<script type="application/javascript" src="peerconnection_audio_forced_sample_rate.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
createHTML({
|
||||||
|
bug: "1437366",
|
||||||
|
title: "Basic audio-only peer connection, with the MSG running at a rate not supported by the MediaPipeline (49000Hz)"
|
||||||
|
});
|
||||||
|
|
||||||
|
test_peerconnection_audio_forced_sample_rate(49000);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="application/javascript" src="pc.js"></script>
|
||||||
|
<script type="application/javascript" src="peerconnection_audio_forced_sample_rate.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript">
|
||||||
|
createHTML({
|
||||||
|
bug: "1437366",
|
||||||
|
title: "Basic audio-only peer connection, with the MSG running at a rate not supported by the MediaPipeline (24000Hz)"
|
||||||
|
});
|
||||||
|
|
||||||
|
test_peerconnection_audio_forced_sample_rate(24000);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -35,8 +35,8 @@ smallvec = "0.6"
|
||||||
ws = { optional = true, version = "0.7.3" }
|
ws = { optional = true, version = "0.7.3" }
|
||||||
serde_json = { optional = true, version = "1.0" }
|
serde_json = { optional = true, version = "1.0" }
|
||||||
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
||||||
image = { optional = true, version = "0.17" }
|
image = { optional = true, version = "0.18" }
|
||||||
base64 = { optional = true, version = "0.3.0" }
|
base64 = { optional = true, version = "0.6" }
|
||||||
ron = { optional = true, version = "0.1.7" }
|
ron = { optional = true, version = "0.1.7" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
flat varying int vGradientAddress;
|
flat varying int vGradientAddress;
|
||||||
flat varying float vGradientRepeat;
|
flat varying float vGradientRepeat;
|
||||||
|
|
||||||
flat varying vec2 vStartCenter;
|
flat varying vec2 vCenter;
|
||||||
flat varying vec2 vEndCenter;
|
|
||||||
flat varying float vStartRadius;
|
flat varying float vStartRadius;
|
||||||
flat varying float vEndRadius;
|
flat varying float vEndRadius;
|
||||||
|
|
||||||
|
@ -23,8 +22,8 @@ varying vec2 vLocalPos;
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
|
|
||||||
struct RadialGradient {
|
struct RadialGradient {
|
||||||
vec4 start_end_center;
|
vec4 center_start_end_radius;
|
||||||
vec4 start_end_radius_ratio_xy_extend_mode;
|
vec4 ratio_xy_extend_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
RadialGradient fetch_radial_gradient(int address) {
|
RadialGradient fetch_radial_gradient(int address) {
|
||||||
|
@ -43,23 +42,20 @@ void brush_vs(
|
||||||
|
|
||||||
vPos = vi.local_pos - local_rect.p0;
|
vPos = vi.local_pos - local_rect.p0;
|
||||||
|
|
||||||
vStartCenter = gradient.start_end_center.xy;
|
vCenter = gradient.center_start_end_radius.xy;
|
||||||
vEndCenter = gradient.start_end_center.zw;
|
vStartRadius = gradient.center_start_end_radius.z;
|
||||||
|
vEndRadius = gradient.center_start_end_radius.w;
|
||||||
vStartRadius = gradient.start_end_radius_ratio_xy_extend_mode.x;
|
|
||||||
vEndRadius = gradient.start_end_radius_ratio_xy_extend_mode.y;
|
|
||||||
|
|
||||||
// Transform all coordinates by the y scale so the
|
// Transform all coordinates by the y scale so the
|
||||||
// fragment shader can work with circles
|
// fragment shader can work with circles
|
||||||
float ratio_xy = gradient.start_end_radius_ratio_xy_extend_mode.z;
|
float ratio_xy = gradient.ratio_xy_extend_mode.x;
|
||||||
vPos.y *= ratio_xy;
|
vPos.y *= ratio_xy;
|
||||||
vStartCenter.y *= ratio_xy;
|
vCenter.y *= ratio_xy;
|
||||||
vEndCenter.y *= ratio_xy;
|
|
||||||
|
|
||||||
vGradientAddress = user_data.x;
|
vGradientAddress = user_data.x;
|
||||||
|
|
||||||
// Whether to repeat the gradient instead of clamping.
|
// Whether to repeat the gradient instead of clamping.
|
||||||
vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) != EXTEND_MODE_CLAMP);
|
vGradientRepeat = float(int(gradient.ratio_xy_extend_mode.y) != EXTEND_MODE_CLAMP);
|
||||||
|
|
||||||
#ifdef WR_FEATURE_ALPHA_PASS
|
#ifdef WR_FEATURE_ALPHA_PASS
|
||||||
vLocalPos = vi.local_pos;
|
vLocalPos = vi.local_pos;
|
||||||
|
@ -69,14 +65,13 @@ void brush_vs(
|
||||||
|
|
||||||
#ifdef WR_FRAGMENT_SHADER
|
#ifdef WR_FRAGMENT_SHADER
|
||||||
vec4 brush_fs() {
|
vec4 brush_fs() {
|
||||||
vec2 cd = vEndCenter - vStartCenter;
|
vec2 pd = vPos - vCenter;
|
||||||
vec2 pd = vPos - vStartCenter;
|
|
||||||
float rd = vEndRadius - vStartRadius;
|
float rd = vEndRadius - vStartRadius;
|
||||||
|
|
||||||
// Solve for t in length(t * cd - pd) = vStartRadius + t * rd
|
// Solve for t in length(t - pd) = vStartRadius + t * rd
|
||||||
// using a quadratic equation in form of At^2 - 2Bt + C = 0
|
// using a quadratic equation in form of At^2 - 2Bt + C = 0
|
||||||
float A = dot(cd, cd) - rd * rd;
|
float A = -(rd * rd);
|
||||||
float B = dot(pd, cd) + vStartRadius * rd;
|
float B = vStartRadius * rd;
|
||||||
float C = dot(pd, pd) - vStartRadius * vStartRadius;
|
float C = dot(pd, pd) - vStartRadius * vStartRadius;
|
||||||
|
|
||||||
float offset;
|
float offset;
|
||||||
|
|
|
@ -931,22 +931,6 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: remove once the Angle workaround is no longer needed
|
|
||||||
pub fn reset_angle_sampler_metadata(&mut self, texture: &Texture) {
|
|
||||||
self.bind_texture(DEFAULT_TEXTURE, texture);
|
|
||||||
self.gl.tex_parameter_f(
|
|
||||||
texture.target,
|
|
||||||
gl::TEXTURE_BASE_LEVEL,
|
|
||||||
1.0 as _,
|
|
||||||
);
|
|
||||||
self.gl.draw_arrays(gl::TRIANGLES, 0, 1); // dummy draw
|
|
||||||
self.gl.tex_parameter_f(
|
|
||||||
texture.target,
|
|
||||||
gl::TEXTURE_BASE_LEVEL,
|
|
||||||
0.0 as _, // assumes 0.0 is the normal value for this texture
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_texture(
|
pub fn create_texture(
|
||||||
&mut self,
|
&mut self,
|
||||||
target: TextureTarget,
|
target: TextureTarget,
|
||||||
|
|
|
@ -738,11 +738,10 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
self.add_radial_gradient(
|
self.add_radial_gradient(
|
||||||
clip_and_scroll,
|
clip_and_scroll,
|
||||||
&prim_info,
|
&prim_info,
|
||||||
info.gradient.start_center,
|
info.gradient.center,
|
||||||
info.gradient.start_radius,
|
info.gradient.start_radius,
|
||||||
info.gradient.end_center,
|
|
||||||
info.gradient.end_radius,
|
info.gradient.end_radius,
|
||||||
info.gradient.ratio_xy,
|
info.gradient.radius.width / info.gradient.radius.height,
|
||||||
item.gradient_stops(),
|
item.gradient_stops(),
|
||||||
info.gradient.extend_mode,
|
info.gradient.extend_mode,
|
||||||
info.tile_size,
|
info.tile_size,
|
||||||
|
@ -1824,11 +1823,10 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
self.add_radial_gradient(
|
self.add_radial_gradient(
|
||||||
clip_and_scroll,
|
clip_and_scroll,
|
||||||
&info,
|
&info,
|
||||||
border.gradient.start_center - segment_rel,
|
border.gradient.center - segment_rel,
|
||||||
border.gradient.start_radius,
|
border.gradient.start_radius,
|
||||||
border.gradient.end_center - segment_rel,
|
|
||||||
border.gradient.end_radius,
|
border.gradient.end_radius,
|
||||||
border.gradient.ratio_xy,
|
border.gradient.radius.width / border.gradient.radius.height,
|
||||||
gradient_stops,
|
gradient_stops,
|
||||||
border.gradient.extend_mode,
|
border.gradient.extend_mode,
|
||||||
segment.size,
|
segment.size,
|
||||||
|
@ -1938,9 +1936,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
clip_and_scroll: ScrollNodeAndClipChain,
|
clip_and_scroll: ScrollNodeAndClipChain,
|
||||||
info: &LayerPrimitiveInfo,
|
info: &LayerPrimitiveInfo,
|
||||||
start_center: LayerPoint,
|
center: LayerPoint,
|
||||||
start_radius: f32,
|
start_radius: f32,
|
||||||
end_center: LayerPoint,
|
|
||||||
end_radius: f32,
|
end_radius: f32,
|
||||||
ratio_xy: f32,
|
ratio_xy: f32,
|
||||||
stops: ItemRange<GradientStop>,
|
stops: ItemRange<GradientStop>,
|
||||||
|
@ -1951,8 +1948,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
BrushKind::RadialGradient {
|
BrushKind::RadialGradient {
|
||||||
stops_range: stops,
|
stops_range: stops,
|
||||||
extend_mode,
|
extend_mode,
|
||||||
start_center,
|
center,
|
||||||
end_center,
|
|
||||||
start_radius,
|
start_radius,
|
||||||
end_radius,
|
end_radius,
|
||||||
ratio_xy,
|
ratio_xy,
|
||||||
|
@ -1973,9 +1969,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
clip_and_scroll: ScrollNodeAndClipChain,
|
clip_and_scroll: ScrollNodeAndClipChain,
|
||||||
info: &LayerPrimitiveInfo,
|
info: &LayerPrimitiveInfo,
|
||||||
start_center: LayerPoint,
|
center: LayerPoint,
|
||||||
start_radius: f32,
|
start_radius: f32,
|
||||||
end_center: LayerPoint,
|
|
||||||
end_radius: f32,
|
end_radius: f32,
|
||||||
ratio_xy: f32,
|
ratio_xy: f32,
|
||||||
stops: ItemRange<GradientStop>,
|
stops: ItemRange<GradientStop>,
|
||||||
|
@ -1996,9 +1991,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
self.add_radial_gradient_impl(
|
self.add_radial_gradient_impl(
|
||||||
clip_and_scroll,
|
clip_and_scroll,
|
||||||
info,
|
info,
|
||||||
start_center,
|
center,
|
||||||
start_radius,
|
start_radius,
|
||||||
end_center,
|
|
||||||
end_radius,
|
end_radius,
|
||||||
ratio_xy,
|
ratio_xy,
|
||||||
stops,
|
stops,
|
||||||
|
@ -2010,9 +2004,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
self.add_radial_gradient_impl(
|
self.add_radial_gradient_impl(
|
||||||
clip_and_scroll,
|
clip_and_scroll,
|
||||||
&prim_info,
|
&prim_info,
|
||||||
start_center,
|
center,
|
||||||
start_radius,
|
start_radius,
|
||||||
end_center,
|
|
||||||
end_radius,
|
end_radius,
|
||||||
ratio_xy,
|
ratio_xy,
|
||||||
stops,
|
stops,
|
||||||
|
|
|
@ -2,38 +2,43 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use api::{DevicePoint, DeviceUintSize, GlyphKey};
|
use api::GlyphKey;
|
||||||
use glyph_rasterizer::{FontInstance, GlyphFormat};
|
use glyph_rasterizer::{FontInstance, GlyphFormat};
|
||||||
use internal_types::FastHashMap;
|
use internal_types::FastHashMap;
|
||||||
use resource_cache::ResourceClassCache;
|
use resource_cache::ResourceClassCache;
|
||||||
use std::sync::Arc;
|
use texture_cache::{TextureCache, TextureCacheHandle, EvictionNotice};
|
||||||
use texture_cache::TextureCacheHandle;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct GenericCachedGlyphInfo<D> {
|
pub struct CachedGlyphInfo {
|
||||||
pub texture_cache_handle: TextureCacheHandle,
|
pub texture_cache_handle: TextureCacheHandle,
|
||||||
pub glyph_bytes: D,
|
|
||||||
pub size: DeviceUintSize,
|
|
||||||
pub offset: DevicePoint,
|
|
||||||
pub scale: f32,
|
|
||||||
pub format: GlyphFormat,
|
pub format: GlyphFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CachedGlyphInfo = GenericCachedGlyphInfo<Arc<Vec<u8>>>;
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, Option<CachedGlyphInfo>>;
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub enum GlyphCacheEntry {
|
||||||
|
// A glyph that has been successfully rasterized.
|
||||||
|
Cached(CachedGlyphInfo),
|
||||||
|
// A glyph that should not be rasterized (i.e. a space).
|
||||||
|
Blank,
|
||||||
|
// A glyph that has been submitted to the font backend for rasterization,
|
||||||
|
// but is still pending a result.
|
||||||
|
Pending,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
pub type GlyphKeyCache = ResourceClassCache<GlyphKey, GlyphCacheEntry, EvictionNotice>;
|
||||||
pub type PlainCachedGlyphInfo = GenericCachedGlyphInfo<String>;
|
|
||||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
|
||||||
pub type PlainGlyphKeyCache = ResourceClassCache<GlyphKey, Option<PlainCachedGlyphInfo>>;
|
|
||||||
#[cfg(feature = "capture")]
|
|
||||||
pub type PlainGlyphCacheRef<'a> = FastHashMap<&'a FontInstance, PlainGlyphKeyCache>;
|
|
||||||
#[cfg(feature = "replay")]
|
|
||||||
pub type PlainGlyphCacheOwn = FastHashMap<FontInstance, PlainGlyphKeyCache>;
|
|
||||||
|
|
||||||
|
impl GlyphKeyCache {
|
||||||
|
pub fn eviction_notice(&self) -> &EvictionNotice {
|
||||||
|
&self.user_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct GlyphCache {
|
pub struct GlyphCache {
|
||||||
pub glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
|
glyph_key_caches: FastHashMap<FontInstance, GlyphKeyCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlyphCache {
|
impl GlyphCache {
|
||||||
|
@ -46,7 +51,7 @@ impl GlyphCache {
|
||||||
pub fn get_glyph_key_cache_for_font_mut(&mut self, font: FontInstance) -> &mut GlyphKeyCache {
|
pub fn get_glyph_key_cache_for_font_mut(&mut self, font: FontInstance) -> &mut GlyphKeyCache {
|
||||||
self.glyph_key_caches
|
self.glyph_key_caches
|
||||||
.entry(font)
|
.entry(font)
|
||||||
.or_insert(ResourceClassCache::new())
|
.or_insert_with(|| GlyphKeyCache::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_glyph_key_cache_for_font(&self, font: &FontInstance) -> &GlyphKeyCache {
|
pub fn get_glyph_key_cache_for_font(&self, font: &FontInstance) -> &GlyphKeyCache {
|
||||||
|
@ -78,4 +83,36 @@ impl GlyphCache {
|
||||||
cache.clear();
|
cache.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear out evicted entries from glyph key caches and, if possible,
|
||||||
|
// also remove entirely any subsequently empty glyph key caches.
|
||||||
|
fn clear_evicted(&mut self, texture_cache: &TextureCache) {
|
||||||
|
self.glyph_key_caches.retain(|_, cache| {
|
||||||
|
// Scan for any glyph key caches that have evictions.
|
||||||
|
if cache.eviction_notice().check() {
|
||||||
|
// If there are evictions, filter out any glyphs evicted from the
|
||||||
|
// texture cache from the glyph key cache.
|
||||||
|
let mut keep_cache = false;
|
||||||
|
cache.retain(|_, entry| {
|
||||||
|
let keep_glyph = match *entry {
|
||||||
|
GlyphCacheEntry::Cached(ref glyph) =>
|
||||||
|
texture_cache.is_allocated(&glyph.texture_cache_handle),
|
||||||
|
GlyphCacheEntry::Pending => true,
|
||||||
|
// If the cache only has blank glyphs left, just get rid of it.
|
||||||
|
GlyphCacheEntry::Blank => false,
|
||||||
|
};
|
||||||
|
keep_cache |= keep_glyph;
|
||||||
|
keep_glyph
|
||||||
|
});
|
||||||
|
// Only keep the glyph key cache if it still has valid glyphs.
|
||||||
|
keep_cache
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin_frame(&mut self, texture_cache: &TextureCache) {
|
||||||
|
self.clear_evicted(texture_cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,16 @@
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use api::{IdNamespace, LayoutPoint};
|
use api::{IdNamespace, LayoutPoint};
|
||||||
use api::{ColorF, ColorU, DevicePoint, DeviceUintSize};
|
use api::{ColorF, ColorU};
|
||||||
use api::{FontInstanceFlags, FontInstancePlatformOptions};
|
use api::{FontInstanceFlags, FontInstancePlatformOptions};
|
||||||
use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
|
use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
|
||||||
use api::{GlyphDimensions, GlyphKey, SubpixelDirection};
|
use api::{GlyphDimensions, GlyphKey, SubpixelDirection};
|
||||||
use api::{ImageData, ImageDescriptor, ImageFormat, LayerToWorldTransform};
|
use api::{ImageData, ImageDescriptor, ImageFormat, LayerToWorldTransform};
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use device::TextureFilter;
|
use device::TextureFilter;
|
||||||
use glyph_cache::{CachedGlyphInfo, GlyphCache};
|
use glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
|
||||||
use gpu_cache::GpuCache;
|
use gpu_cache::GpuCache;
|
||||||
use internal_types::{FastHashSet, ResourceCacheError};
|
use internal_types::ResourceCacheError;
|
||||||
use platform::font::FontContext;
|
use platform::font::FontContext;
|
||||||
use profiler::TextureCacheProfileCounters;
|
use profiler::TextureCacheProfileCounters;
|
||||||
use rayon::ThreadPool;
|
use rayon::ThreadPool;
|
||||||
|
@ -309,11 +309,11 @@ pub struct GlyphRasterizer {
|
||||||
// because the glyph cache hash table is not updated
|
// because the glyph cache hash table is not updated
|
||||||
// until the end of the frame when we wait for glyph requests
|
// until the end of the frame when we wait for glyph requests
|
||||||
// to be resolved.
|
// to be resolved.
|
||||||
pending_glyphs: FastHashSet<GlyphRequest>,
|
pending_glyphs: usize,
|
||||||
|
|
||||||
// Receives the rendered glyphs.
|
// Receives the rendered glyphs.
|
||||||
glyph_rx: Receiver<Vec<GlyphRasterJob>>,
|
glyph_rx: Receiver<GlyphRasterJobs>,
|
||||||
glyph_tx: Sender<Vec<GlyphRasterJob>>,
|
glyph_tx: Sender<GlyphRasterJobs>,
|
||||||
|
|
||||||
// We defer removing fonts to the end of the frame so that:
|
// We defer removing fonts to the end of the frame so that:
|
||||||
// - this work is done outside of the critical path,
|
// - this work is done outside of the critical path,
|
||||||
|
@ -341,7 +341,7 @@ impl GlyphRasterizer {
|
||||||
shared_context: Mutex::new(shared_context),
|
shared_context: Mutex::new(shared_context),
|
||||||
workers: Arc::clone(&workers),
|
workers: Arc::clone(&workers),
|
||||||
}),
|
}),
|
||||||
pending_glyphs: FastHashSet::default(),
|
pending_glyphs: 0,
|
||||||
glyph_rx,
|
glyph_rx,
|
||||||
glyph_tx,
|
glyph_tx,
|
||||||
workers,
|
workers,
|
||||||
|
@ -391,7 +391,7 @@ impl GlyphRasterizer {
|
||||||
.lock_shared_context()
|
.lock_shared_context()
|
||||||
.has_font(&font.font_key)
|
.has_font(&font.font_key)
|
||||||
);
|
);
|
||||||
let mut glyphs = Vec::new();
|
let mut new_glyphs = Vec::new();
|
||||||
|
|
||||||
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font.clone());
|
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font.clone());
|
||||||
|
|
||||||
|
@ -399,58 +399,51 @@ impl GlyphRasterizer {
|
||||||
for key in glyph_keys {
|
for key in glyph_keys {
|
||||||
match glyph_key_cache.entry(key.clone()) {
|
match glyph_key_cache.entry(key.clone()) {
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
if let Ok(Some(ref mut glyph_info)) = *entry.get_mut() {
|
let value = entry.into_mut();
|
||||||
if texture_cache.request(&mut glyph_info.texture_cache_handle, gpu_cache) {
|
match *value {
|
||||||
// This case gets hit when we have already rasterized
|
GlyphCacheEntry::Cached(ref glyph) => {
|
||||||
// the glyph and stored it in CPU memory, but the glyph
|
// Skip the glyph if it is already has a valid texture cache handle.
|
||||||
// has been evicted from the texture cache. In which case
|
if !texture_cache.request(&glyph.texture_cache_handle, gpu_cache) {
|
||||||
// we need to re-upload it to the GPU.
|
continue;
|
||||||
texture_cache.update(
|
|
||||||
&mut glyph_info.texture_cache_handle,
|
|
||||||
ImageDescriptor {
|
|
||||||
width: glyph_info.size.width,
|
|
||||||
height: glyph_info.size.height,
|
|
||||||
stride: None,
|
|
||||||
format: ImageFormat::BGRA8,
|
|
||||||
is_opaque: false,
|
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
TextureFilter::Linear,
|
|
||||||
Some(ImageData::Raw(glyph_info.glyph_bytes.clone())),
|
|
||||||
[glyph_info.offset.x, glyph_info.offset.y, glyph_info.scale],
|
|
||||||
None,
|
|
||||||
gpu_cache,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Otherwise, skip the entry if it is blank or pending.
|
||||||
|
GlyphCacheEntry::Blank |
|
||||||
|
GlyphCacheEntry::Pending => continue,
|
||||||
}
|
}
|
||||||
Entry::Vacant(..) => {
|
// This case gets hit when we already rasterized the glyph, but the
|
||||||
let request = GlyphRequest::new(&font, key);
|
// glyph has been evicted from the texture cache. Just force it to
|
||||||
if self.pending_glyphs.insert(request.clone()) {
|
// pending so it gets rematerialized.
|
||||||
glyphs.push(request);
|
*value = GlyphCacheEntry::Pending;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
// This is the first time we've seen the glyph, so mark it as pending.
|
||||||
|
entry.insert(GlyphCacheEntry::Pending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if glyphs.is_empty() {
|
new_glyphs.push(key.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_glyphs.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.pending_glyphs += 1;
|
||||||
let font_contexts = Arc::clone(&self.font_contexts);
|
let font_contexts = Arc::clone(&self.font_contexts);
|
||||||
let glyph_tx = self.glyph_tx.clone();
|
let glyph_tx = self.glyph_tx.clone();
|
||||||
// spawn an async task to get off of the render backend thread as early as
|
// spawn an async task to get off of the render backend thread as early as
|
||||||
// possible and in that task use rayon's fork join dispatch to rasterize the
|
// possible and in that task use rayon's fork join dispatch to rasterize the
|
||||||
// glyphs in the thread pool.
|
// glyphs in the thread pool.
|
||||||
self.workers.spawn(move || {
|
self.workers.spawn(move || {
|
||||||
let jobs = glyphs
|
let jobs = new_glyphs
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|request: &GlyphRequest| {
|
.map(|key: &GlyphKey| {
|
||||||
profile_scope!("glyph-raster");
|
profile_scope!("glyph-raster");
|
||||||
let mut context = font_contexts.lock_current_context();
|
let mut context = font_contexts.lock_current_context();
|
||||||
let job = GlyphRasterJob {
|
let job = GlyphRasterJob {
|
||||||
request: request.clone(),
|
key: key.clone(),
|
||||||
result: context.rasterize_glyph(&request.font, &request.key),
|
result: context.rasterize_glyph(&font, key),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sanity check.
|
// Sanity check.
|
||||||
|
@ -466,7 +459,7 @@ impl GlyphRasterizer {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
glyph_tx.send(jobs).unwrap();
|
glyph_tx.send(GlyphRasterJobs { font, jobs }).unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,39 +486,31 @@ impl GlyphRasterizer {
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
_texture_cache_profile: &mut TextureCacheProfileCounters,
|
_texture_cache_profile: &mut TextureCacheProfileCounters,
|
||||||
) {
|
) {
|
||||||
let mut rasterized_glyphs = Vec::with_capacity(self.pending_glyphs.len());
|
// Pull rasterized glyphs from the queue and Update the caches.
|
||||||
|
while self.pending_glyphs > 0 {
|
||||||
|
self.pending_glyphs -= 1;
|
||||||
|
|
||||||
// Pull rasterized glyphs from the queue.
|
|
||||||
|
|
||||||
while !self.pending_glyphs.is_empty() {
|
|
||||||
// TODO: rather than blocking until all pending glyphs are available
|
// TODO: rather than blocking until all pending glyphs are available
|
||||||
// we could try_recv and steal work from the thread pool to take advantage
|
// we could try_recv and steal work from the thread pool to take advantage
|
||||||
// of the fact that this thread is alive and we avoid the added latency
|
// of the fact that this thread is alive and we avoid the added latency
|
||||||
// of blocking it.
|
// of blocking it.
|
||||||
let raster_jobs = self.glyph_rx
|
let GlyphRasterJobs { font, mut jobs } = self.glyph_rx
|
||||||
.recv()
|
.recv()
|
||||||
.expect("BUG: Should be glyphs pending!");
|
.expect("BUG: Should be glyphs pending!");
|
||||||
for job in raster_jobs {
|
|
||||||
debug_assert!(self.pending_glyphs.contains(&job.request));
|
|
||||||
self.pending_glyphs.remove(&job.request);
|
|
||||||
|
|
||||||
rasterized_glyphs.push(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the glyphs are always processed in the same
|
// Ensure that the glyphs are always processed in the same
|
||||||
// order for a given text run (since iterating a hash set doesn't
|
// order for a given text run (since iterating a hash set doesn't
|
||||||
// guarantee order). This can show up as very small float inaccuacry
|
// guarantee order). This can show up as very small float inaccuacry
|
||||||
// differences in rasterizers due to the different coordinates
|
// differences in rasterizers due to the different coordinates
|
||||||
// that text runs get associated with by the texture cache allocator.
|
// that text runs get associated with by the texture cache allocator.
|
||||||
rasterized_glyphs.sort_by(|a, b| a.request.cmp(&b.request));
|
jobs.sort_by(|a, b| a.key.cmp(&b.key));
|
||||||
|
|
||||||
// Update the caches.
|
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(font);
|
||||||
for job in rasterized_glyphs {
|
|
||||||
let glyph_info = job.result
|
for GlyphRasterJob { key, result } in jobs {
|
||||||
.and_then(|glyph| if glyph.width > 0 && glyph.height > 0 {
|
let glyph_info = result.map_or(GlyphCacheEntry::Blank, |glyph| {
|
||||||
|
if glyph.width > 0 && glyph.height > 0 {
|
||||||
assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0));
|
assert_eq!((glyph.left.fract(), glyph.top.fract()), (0.0, 0.0));
|
||||||
let glyph_bytes = Arc::new(glyph.bytes);
|
|
||||||
let mut texture_cache_handle = TextureCacheHandle::new();
|
let mut texture_cache_handle = TextureCacheHandle::new();
|
||||||
texture_cache.request(&mut texture_cache_handle, gpu_cache);
|
texture_cache.request(&mut texture_cache_handle, gpu_cache);
|
||||||
texture_cache.update(
|
texture_cache.update(
|
||||||
|
@ -539,26 +524,22 @@ impl GlyphRasterizer {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
},
|
},
|
||||||
TextureFilter::Linear,
|
TextureFilter::Linear,
|
||||||
Some(ImageData::Raw(glyph_bytes.clone())),
|
Some(ImageData::Raw(Arc::new(glyph.bytes))),
|
||||||
[glyph.left, -glyph.top, glyph.scale],
|
[glyph.left, -glyph.top, glyph.scale],
|
||||||
None,
|
None,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
|
Some(glyph_key_cache.eviction_notice()),
|
||||||
);
|
);
|
||||||
Some(CachedGlyphInfo {
|
GlyphCacheEntry::Cached(CachedGlyphInfo {
|
||||||
texture_cache_handle,
|
texture_cache_handle,
|
||||||
glyph_bytes,
|
|
||||||
size: DeviceUintSize::new(glyph.width, glyph.height),
|
|
||||||
offset: DevicePoint::new(glyph.left, -glyph.top),
|
|
||||||
scale: glyph.scale,
|
|
||||||
format: glyph.format,
|
format: glyph.format,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
GlyphCacheEntry::Blank
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
glyph_key_cache.insert(key, glyph_info);
|
||||||
let glyph_key_cache = glyph_cache.get_glyph_key_cache_for_font_mut(job.request.font);
|
}
|
||||||
|
|
||||||
glyph_key_cache.insert(job.request.key, Ok(glyph_info));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we are done with the critical path (rendering the glyphs),
|
// Now that we are done with the critical path (rendering the glyphs),
|
||||||
|
@ -583,7 +564,7 @@ impl GlyphRasterizer {
|
||||||
#[cfg(feature = "replay")]
|
#[cfg(feature = "replay")]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
//TODO: any signals need to be sent to the workers?
|
//TODO: any signals need to be sent to the workers?
|
||||||
self.pending_glyphs.clear();
|
self.pending_glyphs = 0;
|
||||||
self.fonts_to_remove.clear();
|
self.fonts_to_remove.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,10 +600,15 @@ impl GlyphRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GlyphRasterJob {
|
struct GlyphRasterJob {
|
||||||
request: GlyphRequest,
|
key: GlyphKey,
|
||||||
result: Option<RasterizedGlyph>,
|
result: Option<RasterizedGlyph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GlyphRasterJobs {
|
||||||
|
font: FontInstance,
|
||||||
|
jobs: Vec<GlyphRasterJob>,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rasterize_200_glyphs() {
|
fn rasterize_200_glyphs() {
|
||||||
// This test loads a font from disc, the renders 4 requests containing
|
// This test loads a font from disc, the renders 4 requests containing
|
||||||
|
|
|
@ -222,8 +222,7 @@ pub enum BrushKind {
|
||||||
gradient_index: CachedGradientIndex,
|
gradient_index: CachedGradientIndex,
|
||||||
stops_range: ItemRange<GradientStop>,
|
stops_range: ItemRange<GradientStop>,
|
||||||
extend_mode: ExtendMode,
|
extend_mode: ExtendMode,
|
||||||
start_center: LayerPoint,
|
center: LayerPoint,
|
||||||
end_center: LayerPoint,
|
|
||||||
start_radius: f32,
|
start_radius: f32,
|
||||||
end_radius: f32,
|
end_radius: f32,
|
||||||
ratio_xy: f32,
|
ratio_xy: f32,
|
||||||
|
@ -379,18 +378,18 @@ impl BrushPrimitive {
|
||||||
0.0,
|
0.0,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
BrushKind::RadialGradient { start_center, end_center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
|
BrushKind::RadialGradient { center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
|
||||||
request.push([
|
|
||||||
start_center.x,
|
|
||||||
start_center.y,
|
|
||||||
end_center.x,
|
|
||||||
end_center.y,
|
|
||||||
]);
|
|
||||||
request.push([
|
request.push([
|
||||||
|
center.x,
|
||||||
|
center.y,
|
||||||
start_radius,
|
start_radius,
|
||||||
end_radius,
|
end_radius,
|
||||||
|
]);
|
||||||
|
request.push([
|
||||||
ratio_xy,
|
ratio_xy,
|
||||||
pack_as_float(extend_mode as u32),
|
pack_as_float(extend_mode as u32),
|
||||||
|
0.,
|
||||||
|
0.,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use api::{ApiMsg, FrameMsg};
|
use api::{ApiMsg, FrameMsg, SceneMsg};
|
||||||
use bincode::{serialize, Infinite};
|
use bincode::{serialize, Infinite};
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
@ -67,11 +67,23 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
|
||||||
ApiMsg::AddDocument { .. } |
|
ApiMsg::AddDocument { .. } |
|
||||||
ApiMsg::DeleteDocument(..) => true,
|
ApiMsg::DeleteDocument(..) => true,
|
||||||
ApiMsg::UpdateDocument(_, ref msgs) => {
|
ApiMsg::UpdateDocument(_, ref msgs) => {
|
||||||
|
if msgs.generate_frame {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for msg in &msgs.scene_ops {
|
||||||
|
match *msg {
|
||||||
|
SceneMsg::SetDisplayList { .. } |
|
||||||
|
SceneMsg::SetRootPipeline { .. } => return true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for msg in &msgs.frame_ops {
|
for msg in &msgs.frame_ops {
|
||||||
match *msg {
|
match *msg {
|
||||||
FrameMsg::GetScrollNodeState(..) |
|
FrameMsg::GetScrollNodeState(..) |
|
||||||
FrameMsg::HitTest(..) => {}
|
FrameMsg::HitTest(..) => {}
|
||||||
_ => { return true; }
|
_ => return true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -695,8 +695,9 @@ impl RenderBackend {
|
||||||
|
|
||||||
pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
|
pub fn run(&mut self, mut profile_counters: BackendProfileCounters) {
|
||||||
let mut frame_counter: u32 = 0;
|
let mut frame_counter: u32 = 0;
|
||||||
|
let mut keep_going = true;
|
||||||
|
|
||||||
loop {
|
while keep_going {
|
||||||
profile_scope!("handle_msg");
|
profile_scope!("handle_msg");
|
||||||
|
|
||||||
while let Ok(msg) = self.scene_rx.try_recv() {
|
while let Ok(msg) = self.scene_rx.try_recv() {
|
||||||
|
@ -740,7 +741,7 @@ impl RenderBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let keep_going = match self.api_rx.recv() {
|
keep_going = match self.api_rx.recv() {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
if let Some(ref mut r) = self.recorder {
|
if let Some(ref mut r) = self.recorder {
|
||||||
r.write_msg(frame_counter, &msg);
|
r.write_msg(frame_counter, &msg);
|
||||||
|
@ -749,13 +750,10 @@ impl RenderBackend {
|
||||||
}
|
}
|
||||||
Err(..) => { false }
|
Err(..) => { false }
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if !keep_going {
|
|
||||||
let _ = self.scene_tx.send(SceneBuilderRequest::Stop);
|
let _ = self.scene_tx.send(SceneBuilderRequest::Stop);
|
||||||
self.notifier.shut_down();
|
self.notifier.shut_down();
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_api_msg(
|
fn process_api_msg(
|
||||||
|
@ -965,14 +963,6 @@ impl RenderBackend {
|
||||||
|
|
||||||
let doc = self.documents.get_mut(&document_id).unwrap();
|
let doc = self.documents.get_mut(&document_id).unwrap();
|
||||||
|
|
||||||
if !doc.can_render() {
|
|
||||||
// TODO: this happens if we are building the first scene asynchronously and
|
|
||||||
// scroll at the same time. we should keep track of the fact that we skipped
|
|
||||||
// composition here and do it as soon as we receive the scene.
|
|
||||||
op.render = false;
|
|
||||||
op.composite = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if transaction_msg.generate_frame {
|
if transaction_msg.generate_frame {
|
||||||
if let Some(ref mut ros) = doc.render_on_scroll {
|
if let Some(ref mut ros) = doc.render_on_scroll {
|
||||||
*ros = true;
|
*ros = true;
|
||||||
|
@ -984,6 +974,14 @@ impl RenderBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !doc.can_render() {
|
||||||
|
// TODO: this happens if we are building the first scene asynchronously and
|
||||||
|
// scroll at the same time. we should keep track of the fact that we skipped
|
||||||
|
// composition here and do it as soon as we receive the scene.
|
||||||
|
op.render = false;
|
||||||
|
op.composite = false;
|
||||||
|
}
|
||||||
|
|
||||||
debug_assert!(op.render || !op.composite);
|
debug_assert!(op.render || !op.composite);
|
||||||
|
|
||||||
if op.render {
|
if op.render {
|
||||||
|
|
|
@ -933,6 +933,7 @@ impl RenderTaskCache {
|
||||||
[0.0; 3],
|
[0.0; 3],
|
||||||
None,
|
None,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the allocation details in the texture cache, and store
|
// Get the allocation details in the texture cache, and store
|
||||||
|
|
|
@ -35,7 +35,7 @@ use device::{ProgramCache, ReadPixelsFormat};
|
||||||
use euclid::{rect, Transform3D};
|
use euclid::{rect, Transform3D};
|
||||||
use frame_builder::FrameBuilderConfig;
|
use frame_builder::FrameBuilderConfig;
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use glyph_rasterizer::GlyphFormat;
|
use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
|
||||||
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
||||||
use gpu_types::PrimitiveInstance;
|
use gpu_types::PrimitiveInstance;
|
||||||
use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
|
use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
|
||||||
|
@ -1309,9 +1309,6 @@ impl Renderer {
|
||||||
|
|
||||||
let shaders = Shaders::new(&mut device, gl_type, &options)?;
|
let shaders = Shaders::new(&mut device, gl_type, &options)?;
|
||||||
|
|
||||||
let texture_cache = TextureCache::new(max_device_size);
|
|
||||||
let max_texture_size = texture_cache.max_texture_size();
|
|
||||||
|
|
||||||
let backend_profile_counters = BackendProfileCounters::new();
|
let backend_profile_counters = BackendProfileCounters::new();
|
||||||
|
|
||||||
let dither_matrix_texture = if options.enable_dithering {
|
let dither_matrix_texture = if options.enable_dithering {
|
||||||
|
@ -1489,11 +1486,7 @@ impl Renderer {
|
||||||
let thread_listener_for_scene_builder = thread_listener.clone();
|
let thread_listener_for_scene_builder = thread_listener.clone();
|
||||||
let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
|
let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0));
|
||||||
let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
|
let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0));
|
||||||
let resource_cache = ResourceCache::new(
|
let glyph_rasterizer = GlyphRasterizer::new(workers)?;
|
||||||
texture_cache,
|
|
||||||
workers,
|
|
||||||
blob_image_renderer,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(config, api_tx.clone());
|
let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(config, api_tx.clone());
|
||||||
thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
|
thread::Builder::new().name(scene_thread_name.clone()).spawn(move || {
|
||||||
|
@ -1515,6 +1508,14 @@ impl Renderer {
|
||||||
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
|
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
|
||||||
thread_listener.thread_started(&rb_thread_name);
|
thread_listener.thread_started(&rb_thread_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let texture_cache = TextureCache::new(max_device_size);
|
||||||
|
let resource_cache = ResourceCache::new(
|
||||||
|
texture_cache,
|
||||||
|
glyph_rasterizer,
|
||||||
|
blob_image_renderer,
|
||||||
|
);
|
||||||
|
|
||||||
let mut backend = RenderBackend::new(
|
let mut backend = RenderBackend::new(
|
||||||
api_rx,
|
api_rx,
|
||||||
payload_rx_for_backend,
|
payload_rx_for_backend,
|
||||||
|
@ -1552,7 +1553,7 @@ impl Renderer {
|
||||||
backend_profile_counters: BackendProfileCounters::new(),
|
backend_profile_counters: BackendProfileCounters::new(),
|
||||||
profile_counters: RendererProfileCounters::new(),
|
profile_counters: RendererProfileCounters::new(),
|
||||||
profiler: Profiler::new(),
|
profiler: Profiler::new(),
|
||||||
max_texture_size: max_texture_size,
|
max_texture_size: max_device_size,
|
||||||
max_recorded_profiles: options.max_recorded_profiles,
|
max_recorded_profiles: options.max_recorded_profiles,
|
||||||
clear_color: options.clear_color,
|
clear_color: options.clear_color,
|
||||||
enable_clear_scissor: options.enable_clear_scissor,
|
enable_clear_scissor: options.enable_clear_scissor,
|
||||||
|
@ -2358,14 +2359,6 @@ impl Renderer {
|
||||||
textures: &BatchTextures,
|
textures: &BatchTextures,
|
||||||
stats: &mut RendererStats,
|
stats: &mut RendererStats,
|
||||||
) {
|
) {
|
||||||
// Work around Angle bug that forgets to update sampler metadata,
|
|
||||||
// by making the use of those samplers uniform across programs.
|
|
||||||
// https://github.com/servo/webrender/wiki/Driver-issues#texturesize-in-vertex-shaders
|
|
||||||
let work_around_angle_bug = cfg!(windows);
|
|
||||||
if work_around_angle_bug {
|
|
||||||
self.device.reset_angle_sampler_metadata(&self.texture_resolver.dummy_cache_texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0 .. textures.colors.len() {
|
for i in 0 .. textures.colors.len() {
|
||||||
self.texture_resolver.bind(
|
self.texture_resolver.bind(
|
||||||
&textures.colors[i],
|
&textures.colors[i],
|
||||||
|
|
|
@ -19,16 +19,11 @@ use capture::PlainExternalImage;
|
||||||
#[cfg(any(feature = "replay", feature = "png"))]
|
#[cfg(any(feature = "replay", feature = "png"))]
|
||||||
use capture::CaptureConfig;
|
use capture::CaptureConfig;
|
||||||
use device::TextureFilter;
|
use device::TextureFilter;
|
||||||
use glyph_cache::GlyphCache;
|
use glyph_cache::{GlyphCache, GlyphCacheEntry};
|
||||||
#[cfg(feature = "capture")]
|
|
||||||
use glyph_cache::{PlainGlyphCacheRef, PlainCachedGlyphInfo};
|
|
||||||
#[cfg(feature = "replay")]
|
|
||||||
use glyph_cache::{CachedGlyphInfo, PlainGlyphCacheOwn};
|
|
||||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterizer, GlyphRequest};
|
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterizer, GlyphRequest};
|
||||||
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||||
use internal_types::{FastHashMap, FastHashSet, ResourceCacheError, SourceTexture, TextureUpdateList};
|
use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList};
|
||||||
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
|
use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
|
||||||
use rayon::ThreadPool;
|
|
||||||
use render_backend::FrameId;
|
use render_backend::FrameId;
|
||||||
use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId, RenderTaskTree};
|
use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId, RenderTaskTree};
|
||||||
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
|
use std::collections::hash_map::Entry::{self, Occupied, Vacant};
|
||||||
|
@ -143,46 +138,40 @@ struct CachedImageInfo {
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[cfg_attr(feature = "capture", derive(Clone, Serialize))]
|
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
|
||||||
pub enum ResourceClassCacheError {
|
|
||||||
OverLimitSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ResourceCacheResult<V> = Result<V, ResourceClassCacheError>;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct ResourceClassCache<K: Hash + Eq, V> {
|
pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
|
||||||
resources: FastHashMap<K, ResourceCacheResult<V>>,
|
resources: FastHashMap<K, V>,
|
||||||
|
pub user_data: U,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> ResourceClassCache<K, V>
|
impl<K, V, U> ResourceClassCache<K, V, U>
|
||||||
where
|
where
|
||||||
K: Clone + Hash + Eq + Debug,
|
K: Clone + Hash + Eq + Debug,
|
||||||
|
U: Default,
|
||||||
{
|
{
|
||||||
pub fn new() -> ResourceClassCache<K, V> {
|
pub fn new() -> ResourceClassCache<K, V, U> {
|
||||||
ResourceClassCache {
|
ResourceClassCache {
|
||||||
resources: FastHashMap::default(),
|
resources: FastHashMap::default(),
|
||||||
|
user_data: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, key: &K) -> &ResourceCacheResult<V> {
|
pub fn get(&self, key: &K) -> &V {
|
||||||
self.resources.get(key)
|
self.resources.get(key)
|
||||||
.expect("Didn't find a cached resource with that ID!")
|
.expect("Didn't find a cached resource with that ID!")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: K, value: ResourceCacheResult<V>) {
|
pub fn insert(&mut self, key: K, value: V) {
|
||||||
self.resources.insert(key, value);
|
self.resources.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, key: &K) -> &mut ResourceCacheResult<V> {
|
pub fn get_mut(&mut self, key: &K) -> &mut V {
|
||||||
self.resources.get_mut(key)
|
self.resources.get_mut(key)
|
||||||
.expect("Didn't find a cached resource with that ID!")
|
.expect("Didn't find a cached resource with that ID!")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry(&mut self, key: K) -> Entry<K, ResourceCacheResult<V>> {
|
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||||
self.resources.entry(key)
|
self.resources.entry(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +192,13 @@ where
|
||||||
let _ = self.resources.remove(&key).unwrap();
|
let _ = self.resources.remove(&key).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn retain<F>(&mut self, f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&K, &mut V) -> bool,
|
||||||
|
{
|
||||||
|
self.resources.retain(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,7 +220,14 @@ impl Into<BlobImageRequest> for ImageRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageCache = ResourceClassCache<ImageRequest, CachedImageInfo>;
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Clone, Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub enum ImageCacheError {
|
||||||
|
OverLimitSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageCache = ResourceClassCache<ImageRequest, Result<CachedImageInfo, ImageCacheError>, ()>;
|
||||||
pub type FontInstanceMap = Arc<RwLock<FastHashMap<FontInstanceKey, FontInstance>>>;
|
pub type FontInstanceMap = Arc<RwLock<FastHashMap<FontInstanceKey, FontInstance>>>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -273,12 +276,10 @@ pub struct ResourceCache {
|
||||||
impl ResourceCache {
|
impl ResourceCache {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
texture_cache: TextureCache,
|
texture_cache: TextureCache,
|
||||||
workers: Arc<ThreadPool>,
|
glyph_rasterizer: GlyphRasterizer,
|
||||||
blob_image_renderer: Option<Box<BlobImageRenderer>>,
|
blob_image_renderer: Option<Box<BlobImageRenderer>>,
|
||||||
) -> Result<Self, ResourceCacheError> {
|
) -> Self {
|
||||||
let glyph_rasterizer = GlyphRasterizer::new(workers)?;
|
ResourceCache {
|
||||||
|
|
||||||
Ok(ResourceCache {
|
|
||||||
cached_glyphs: GlyphCache::new(),
|
cached_glyphs: GlyphCache::new(),
|
||||||
cached_images: ResourceClassCache::new(),
|
cached_images: ResourceClassCache::new(),
|
||||||
cached_render_tasks: RenderTaskCache::new(),
|
cached_render_tasks: RenderTaskCache::new(),
|
||||||
|
@ -290,7 +291,7 @@ impl ResourceCache {
|
||||||
pending_image_requests: FastHashSet::default(),
|
pending_image_requests: FastHashSet::default(),
|
||||||
glyph_rasterizer,
|
glyph_rasterizer,
|
||||||
blob_image_renderer,
|
blob_image_renderer,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_texture_size(&self) -> u32 {
|
pub fn max_texture_size(&self) -> u32 {
|
||||||
|
@ -566,7 +567,7 @@ impl ResourceCache {
|
||||||
// The image or tiling size is too big for hardware texture size.
|
// The image or tiling size is too big for hardware texture size.
|
||||||
warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
|
warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
|
||||||
template.descriptor.width, template.descriptor.height, template.tiling.unwrap_or(0));
|
template.descriptor.width, template.descriptor.height, template.tiling.unwrap_or(0));
|
||||||
self.cached_images.insert(request, Err(ResourceClassCacheError::OverLimitSize));
|
self.cached_images.insert(request, Err(ImageCacheError::OverLimitSize));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +683,7 @@ impl ResourceCache {
|
||||||
debug_assert!(fetch_buffer.is_empty());
|
debug_assert!(fetch_buffer.is_empty());
|
||||||
|
|
||||||
for (loop_index, key) in glyph_keys.iter().enumerate() {
|
for (loop_index, key) in glyph_keys.iter().enumerate() {
|
||||||
if let Ok(Some(ref glyph)) = *glyph_key_cache.get(key) {
|
if let GlyphCacheEntry::Cached(ref glyph) = *glyph_key_cache.get(key) {
|
||||||
let cache_item = self.texture_cache.get(&glyph.texture_cache_handle);
|
let cache_item = self.texture_cache.get(&glyph.texture_cache_handle);
|
||||||
if current_texture_id != cache_item.texture_id ||
|
if current_texture_id != cache_item.texture_id ||
|
||||||
current_glyph_format != glyph.format {
|
current_glyph_format != glyph.format {
|
||||||
|
@ -794,6 +795,7 @@ impl ResourceCache {
|
||||||
debug_assert_eq!(self.state, State::Idle);
|
debug_assert_eq!(self.state, State::Idle);
|
||||||
self.state = State::AddResources;
|
self.state = State::AddResources;
|
||||||
self.texture_cache.begin_frame(frame_id);
|
self.texture_cache.begin_frame(frame_id);
|
||||||
|
self.cached_glyphs.begin_frame(&mut self.texture_cache);
|
||||||
self.cached_render_tasks.begin_frame(&mut self.texture_cache);
|
self.cached_render_tasks.begin_frame(&mut self.texture_cache);
|
||||||
self.current_frame_id = frame_id;
|
self.current_frame_id = frame_id;
|
||||||
}
|
}
|
||||||
|
@ -928,6 +930,7 @@ impl ResourceCache {
|
||||||
[0.0; 3],
|
[0.0; 3],
|
||||||
image_template.dirty_rect,
|
image_template.dirty_rect,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
image_template.dirty_rect = None;
|
image_template.dirty_rect = None;
|
||||||
}
|
}
|
||||||
|
@ -1035,7 +1038,7 @@ pub struct PlainResources {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct PlainCacheRef<'a> {
|
pub struct PlainCacheRef<'a> {
|
||||||
current_frame_id: FrameId,
|
current_frame_id: FrameId,
|
||||||
glyphs: PlainGlyphCacheRef<'a>,
|
glyphs: &'a GlyphCache,
|
||||||
glyph_dimensions: &'a GlyphDimensionsCache,
|
glyph_dimensions: &'a GlyphDimensionsCache,
|
||||||
images: &'a ImageCache,
|
images: &'a ImageCache,
|
||||||
render_tasks: &'a RenderTaskCache,
|
render_tasks: &'a RenderTaskCache,
|
||||||
|
@ -1046,7 +1049,7 @@ pub struct PlainCacheRef<'a> {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct PlainCacheOwn {
|
pub struct PlainCacheOwn {
|
||||||
current_frame_id: FrameId,
|
current_frame_id: FrameId,
|
||||||
glyphs: PlainGlyphCacheOwn,
|
glyphs: GlyphCache,
|
||||||
glyph_dimensions: GlyphDimensionsCache,
|
glyph_dimensions: GlyphDimensionsCache,
|
||||||
images: ImageCache,
|
images: ImageCache,
|
||||||
render_tasks: RenderTaskCache,
|
render_tasks: RenderTaskCache,
|
||||||
|
@ -1228,64 +1231,10 @@ impl ResourceCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "capture")]
|
#[cfg(feature = "capture")]
|
||||||
pub fn save_caches(&self, root: &PathBuf) -> PlainCacheRef {
|
pub fn save_caches(&self, _root: &PathBuf) -> PlainCacheRef {
|
||||||
use std::io::Write;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
let path_glyphs = root.join("glyphs");
|
|
||||||
if !path_glyphs.is_dir() {
|
|
||||||
fs::create_dir(&path_glyphs).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("\tcached glyphs");
|
|
||||||
let mut glyph_paths = FastHashMap::default();
|
|
||||||
for cache in self.cached_glyphs.glyph_key_caches.values() {
|
|
||||||
for result in cache.resources.values() {
|
|
||||||
let arc = match *result {
|
|
||||||
Ok(Some(ref info)) => &info.glyph_bytes,
|
|
||||||
Ok(None) | Err(_) => continue,
|
|
||||||
};
|
|
||||||
let glyph_id = glyph_paths.len() + 1;
|
|
||||||
let entry = match glyph_paths.entry(arc.as_ptr()) {
|
|
||||||
Entry::Occupied(_) => continue,
|
|
||||||
Entry::Vacant(e) => e,
|
|
||||||
};
|
|
||||||
|
|
||||||
let file_name = format!("{}.raw", glyph_id);
|
|
||||||
let short_path = format!("glyphs/{}", file_name);
|
|
||||||
fs::File::create(path_glyphs.join(&file_name))
|
|
||||||
.expect(&format!("Unable to create {}", short_path))
|
|
||||||
.write_all(&*arc)
|
|
||||||
.unwrap();
|
|
||||||
entry.insert(short_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PlainCacheRef {
|
PlainCacheRef {
|
||||||
current_frame_id: self.current_frame_id,
|
current_frame_id: self.current_frame_id,
|
||||||
glyphs: self.cached_glyphs.glyph_key_caches
|
glyphs: &self.cached_glyphs,
|
||||||
.iter()
|
|
||||||
.map(|(font_instance, cache)| {
|
|
||||||
let resources = cache.resources
|
|
||||||
.iter()
|
|
||||||
.map(|(key, result)| {
|
|
||||||
(key.clone(), match *result {
|
|
||||||
Ok(Some(ref info)) => Ok(Some(PlainCachedGlyphInfo {
|
|
||||||
texture_cache_handle: info.texture_cache_handle.clone(),
|
|
||||||
glyph_bytes: glyph_paths[&info.glyph_bytes.as_ptr()].clone(),
|
|
||||||
size: info.size,
|
|
||||||
offset: info.offset,
|
|
||||||
scale: info.scale,
|
|
||||||
format: info.format,
|
|
||||||
})),
|
|
||||||
Ok(None) => Ok(None),
|
|
||||||
Err(ref e) => Err(e.clone()),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
(font_instance, ResourceClassCache { resources })
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
glyph_dimensions: &self.cached_glyph_dimensions,
|
glyph_dimensions: &self.cached_glyph_dimensions,
|
||||||
images: &self.cached_images,
|
images: &self.cached_images,
|
||||||
render_tasks: &self.cached_render_tasks,
|
render_tasks: &self.cached_render_tasks,
|
||||||
|
@ -1311,47 +1260,8 @@ impl ResourceCache {
|
||||||
|
|
||||||
match caches {
|
match caches {
|
||||||
Some(cached) => {
|
Some(cached) => {
|
||||||
let glyph_key_caches = cached.glyphs
|
|
||||||
.into_iter()
|
|
||||||
.map(|(font_instance, rcc)| {
|
|
||||||
let resources = rcc.resources
|
|
||||||
.into_iter()
|
|
||||||
.map(|(key, result)| {
|
|
||||||
(key, match result {
|
|
||||||
Ok(Some(info)) => {
|
|
||||||
let glyph_bytes = match raw_map.entry(info.glyph_bytes) {
|
|
||||||
Entry::Occupied(e) => {
|
|
||||||
e.get().clone()
|
|
||||||
}
|
|
||||||
Entry::Vacant(e) => {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
File::open(root.join(e.key()))
|
|
||||||
.expect(&format!("Unable to open {}", e.key()))
|
|
||||||
.read_to_end(&mut buffer)
|
|
||||||
.unwrap();
|
|
||||||
e.insert(Arc::new(buffer))
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Some(CachedGlyphInfo {
|
|
||||||
texture_cache_handle: info.texture_cache_handle,
|
|
||||||
glyph_bytes,
|
|
||||||
size: info.size,
|
|
||||||
offset: info.offset,
|
|
||||||
scale: info.scale,
|
|
||||||
format: info.format,
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
Ok(None) => Ok(None),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
(font_instance, ResourceClassCache { resources })
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
self.current_frame_id = cached.current_frame_id;
|
self.current_frame_id = cached.current_frame_id;
|
||||||
self.cached_glyphs = GlyphCache { glyph_key_caches };
|
self.cached_glyphs = cached.glyphs;
|
||||||
self.cached_glyph_dimensions = cached.glyph_dimensions;
|
self.cached_glyph_dimensions = cached.glyph_dimensions;
|
||||||
self.cached_images = cached.images;
|
self.cached_images = cached.images;
|
||||||
self.cached_render_tasks = cached.render_tasks;
|
self.cached_render_tasks = cached.render_tasks;
|
||||||
|
|
|
@ -14,8 +14,10 @@ use internal_types::{RenderTargetInfo, SourceTexture, TextureUpdate, TextureUpda
|
||||||
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
|
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
|
||||||
use render_backend::FrameId;
|
use render_backend::FrameId;
|
||||||
use resource_cache::CacheItem;
|
use resource_cache::CacheItem;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
// The fixed number of layers for the shared texture cache.
|
// The fixed number of layers for the shared texture cache.
|
||||||
// There is one array texture per image format, allocated lazily.
|
// There is one array texture per image format, allocated lazily.
|
||||||
|
@ -103,6 +105,8 @@ struct CacheEntry {
|
||||||
filter: TextureFilter,
|
filter: TextureFilter,
|
||||||
// The actual device texture ID this is part of.
|
// The actual device texture ID this is part of.
|
||||||
texture_id: CacheTextureId,
|
texture_id: CacheTextureId,
|
||||||
|
// Optional notice when the entry is evicted from the cache.
|
||||||
|
eviction_notice: Option<EvictionNotice>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CacheEntry {
|
impl CacheEntry {
|
||||||
|
@ -124,6 +128,7 @@ impl CacheEntry {
|
||||||
format,
|
format,
|
||||||
filter,
|
filter,
|
||||||
uv_rect_handle: GpuCacheHandle::new(),
|
uv_rect_handle: GpuCacheHandle::new(),
|
||||||
|
eviction_notice: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +155,12 @@ impl CacheEntry {
|
||||||
image_source.write_gpu_blocks(&mut request);
|
image_source.write_gpu_blocks(&mut request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn evict(&self) {
|
||||||
|
if let Some(eviction_notice) = self.eviction_notice.as_ref() {
|
||||||
|
eviction_notice.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type WeakCacheEntryHandle = WeakFreeListHandle<CacheEntry>;
|
type WeakCacheEntryHandle = WeakFreeListHandle<CacheEntry>;
|
||||||
|
@ -173,6 +184,34 @@ impl TextureCacheHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An eviction notice is a shared condition useful for detecting
|
||||||
|
// when a TextureCacheHandle gets evicted from the TextureCache.
|
||||||
|
// It is optionally installed to the TextureCache when an update()
|
||||||
|
// is scheduled. A single notice may be shared among any number of
|
||||||
|
// TextureCacheHandle updates. The notice may then be subsequently
|
||||||
|
// checked to see if any of the updates using it have been evicted.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct EvictionNotice {
|
||||||
|
evicted: Rc<Cell<bool>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EvictionNotice {
|
||||||
|
fn notify(&self) {
|
||||||
|
self.evicted.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(&self) -> bool {
|
||||||
|
if self.evicted.get() {
|
||||||
|
self.evicted.set(false);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct TextureCache {
|
pub struct TextureCache {
|
||||||
|
@ -301,6 +340,7 @@ impl TextureCache {
|
||||||
user_data: [f32; 3],
|
user_data: [f32; 3],
|
||||||
mut dirty_rect: Option<DeviceUintRect>,
|
mut dirty_rect: Option<DeviceUintRect>,
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
|
eviction_notice: Option<&EvictionNotice>,
|
||||||
) {
|
) {
|
||||||
// Determine if we need to allocate texture cache memory
|
// Determine if we need to allocate texture cache memory
|
||||||
// for this item. We need to reallocate if any of the following
|
// for this item. We need to reallocate if any of the following
|
||||||
|
@ -339,6 +379,9 @@ impl TextureCache {
|
||||||
.get_opt_mut(handle.entry.as_ref().unwrap())
|
.get_opt_mut(handle.entry.as_ref().unwrap())
|
||||||
.expect("BUG: handle must be valid now");
|
.expect("BUG: handle must be valid now");
|
||||||
|
|
||||||
|
// Install the new eviction notice for this update, if applicable.
|
||||||
|
entry.eviction_notice = eviction_notice.cloned();
|
||||||
|
|
||||||
// Invalidate the contents of the resource rect in the GPU cache.
|
// Invalidate the contents of the resource rect in the GPU cache.
|
||||||
// This ensures that the update_gpu_cache below will add
|
// This ensures that the update_gpu_cache below will add
|
||||||
// the new information to the GPU cache.
|
// the new information to the GPU cache.
|
||||||
|
@ -498,6 +541,7 @@ impl TextureCache {
|
||||||
// Free the selected items
|
// Free the selected items
|
||||||
for handle in eviction_candidates {
|
for handle in eviction_candidates {
|
||||||
let entry = self.entries.free(handle);
|
let entry = self.entries.free(handle);
|
||||||
|
entry.evict();
|
||||||
self.free(entry);
|
self.free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,6 +596,7 @@ impl TextureCache {
|
||||||
retained_entries.push(handle);
|
retained_entries.push(handle);
|
||||||
} else {
|
} else {
|
||||||
let entry = self.entries.free(handle);
|
let entry = self.entries.free(handle);
|
||||||
|
entry.evict();
|
||||||
if let Some(region) = self.free(entry) {
|
if let Some(region) = self.free(entry) {
|
||||||
found_matching_slab |= region.slab_size == needed_slab_size;
|
found_matching_slab |= region.slab_size == needed_slab_size;
|
||||||
freed_complete_page |= region.is_empty();
|
freed_complete_page |= region.is_empty();
|
||||||
|
@ -1069,6 +1114,7 @@ impl TextureArray {
|
||||||
format: self.format,
|
format: self.format,
|
||||||
filter: self.filter,
|
filter: self.filter,
|
||||||
texture_id: self.texture_id.unwrap(),
|
texture_id: self.texture_id.unwrap(),
|
||||||
|
eviction_notice: None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -418,11 +418,10 @@ pub struct GradientStop {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct RadialGradient {
|
pub struct RadialGradient {
|
||||||
pub start_center: LayoutPoint,
|
pub center: LayoutPoint,
|
||||||
|
pub radius: LayoutSize,
|
||||||
pub start_radius: f32,
|
pub start_radius: f32,
|
||||||
pub end_center: LayoutPoint,
|
|
||||||
pub end_radius: f32,
|
pub end_radius: f32,
|
||||||
pub ratio_xy: f32,
|
|
||||||
pub extend_mode: ExtendMode,
|
pub extend_mode: ExtendMode,
|
||||||
} // IMPLICIT stops: Vec<GradientStop>
|
} // IMPLICIT stops: Vec<GradientStop>
|
||||||
|
|
||||||
|
|
|
@ -1188,11 +1188,10 @@ impl DisplayListBuilder {
|
||||||
self.push_stops(&stops);
|
self.push_stops(&stops);
|
||||||
|
|
||||||
return RadialGradient {
|
return RadialGradient {
|
||||||
start_center: center,
|
center,
|
||||||
|
radius: LayoutSize::new(1.0, 1.0),
|
||||||
start_radius: 0.0,
|
start_radius: 0.0,
|
||||||
end_center: center,
|
|
||||||
end_radius: 1.0,
|
end_radius: 1.0,
|
||||||
ratio_xy: 1.0,
|
|
||||||
extend_mode,
|
extend_mode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1203,11 +1202,10 @@ impl DisplayListBuilder {
|
||||||
self.push_stops(&stops);
|
self.push_stops(&stops);
|
||||||
|
|
||||||
RadialGradient {
|
RadialGradient {
|
||||||
start_center: center,
|
center,
|
||||||
|
radius,
|
||||||
start_radius: radius.width * start_offset,
|
start_radius: radius.width * start_offset,
|
||||||
end_center: center,
|
|
||||||
end_radius: radius.width * end_offset,
|
end_radius: radius.width * end_offset,
|
||||||
ratio_xy: radius.width / radius.height,
|
|
||||||
extend_mode,
|
extend_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1216,22 +1214,20 @@ impl DisplayListBuilder {
|
||||||
// because create_gradient stores the stops in anticipation
|
// because create_gradient stores the stops in anticipation
|
||||||
pub fn create_complex_radial_gradient(
|
pub fn create_complex_radial_gradient(
|
||||||
&mut self,
|
&mut self,
|
||||||
start_center: LayoutPoint,
|
center: LayoutPoint,
|
||||||
|
radius: LayoutSize,
|
||||||
start_radius: f32,
|
start_radius: f32,
|
||||||
end_center: LayoutPoint,
|
|
||||||
end_radius: f32,
|
end_radius: f32,
|
||||||
ratio_xy: f32,
|
|
||||||
stops: Vec<GradientStop>,
|
stops: Vec<GradientStop>,
|
||||||
extend_mode: ExtendMode,
|
extend_mode: ExtendMode,
|
||||||
) -> RadialGradient {
|
) -> RadialGradient {
|
||||||
self.push_stops(&stops);
|
self.push_stops(&stops);
|
||||||
|
|
||||||
RadialGradient {
|
RadialGradient {
|
||||||
start_center,
|
center,
|
||||||
|
radius,
|
||||||
start_radius,
|
start_radius,
|
||||||
end_center,
|
|
||||||
end_radius,
|
end_radius,
|
||||||
ratio_xy,
|
|
||||||
extend_mode,
|
extend_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
486ee5f3aefb0172c2c5703e19f833e63eb295b9
|
2083e83d958dd4a230ccae5c518e4bc8fbf88009
|
||||||
|
|
|
@ -6,7 +6,7 @@ build = "build.rs"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.3"
|
base64 = "0.6"
|
||||||
bincode = "0.9"
|
bincode = "0.9"
|
||||||
byteorder = "1.0"
|
byteorder = "1.0"
|
||||||
env_logger = { version = "0.5", optional = true }
|
env_logger = { version = "0.5", optional = true }
|
||||||
|
@ -14,7 +14,7 @@ euclid = "0.17"
|
||||||
gleam = "0.4"
|
gleam = "0.4"
|
||||||
glutin = "0.12"
|
glutin = "0.12"
|
||||||
app_units = "0.6"
|
app_units = "0.6"
|
||||||
image = "0.17"
|
image = "0.18"
|
||||||
clap = { version = "2", features = ["yaml"] }
|
clap = { version = "2", features = ["yaml"] }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -38,6 +38,7 @@ headless = [ "osmesa-sys", "osmesa-src" ]
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
dwrote = "0.4.1"
|
dwrote = "0.4.1"
|
||||||
|
mozangle = {version = "0.1.5", features = ["egl"]}
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||||
font-loader = "0.6"
|
font-loader = "0.6"
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
use glutin;
|
||||||
|
use glutin::{WindowBuilder, ContextBuilder, EventsLoop, Window, CreationError};
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub enum Context {}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use ::egl::Context;
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn with_window(
|
||||||
|
_: WindowBuilder,
|
||||||
|
_: ContextBuilder,
|
||||||
|
_: &EventsLoop,
|
||||||
|
) -> Result<(Window, Self), CreationError> {
|
||||||
|
Err(CreationError::PlatformSpecific("ANGLE rendering is only supported on Windows".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn with_window(
|
||||||
|
window_builder: WindowBuilder,
|
||||||
|
context_builder: ContextBuilder,
|
||||||
|
events_loop: &EventsLoop,
|
||||||
|
) -> Result<(Window, Self), CreationError> {
|
||||||
|
use glutin::os::windows::WindowExt;
|
||||||
|
|
||||||
|
// FIXME: &context_builder.pf_reqs https://github.com/tomaka/glutin/pull/1002
|
||||||
|
let pf_reqs = &glutin::PixelFormatRequirements::default();
|
||||||
|
let gl_attr = &context_builder.gl_attr.map_sharing(|_| unimplemented!());
|
||||||
|
let window = window_builder.build(events_loop)?;
|
||||||
|
Self::new(pf_reqs, gl_attr)
|
||||||
|
.and_then(|p| p.finish(window.get_hwnd() as _))
|
||||||
|
.map(|context| (window, context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
impl glutin::GlContext for Context {
|
||||||
|
unsafe fn make_current(&self) -> Result<(), glutin::ContextError> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_current(&self) -> bool {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proc_address(&self, _: &str) -> *const () {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn swap_buffers(&self) -> Result<(), glutin::ContextError> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_api(&self) -> glutin::Api {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pixel_format(&self) -> glutin::PixelFormat {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&self, _: u32, _: u32) {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ args:
|
||||||
short: h
|
short: h
|
||||||
long: headless
|
long: headless
|
||||||
help: Enable headless rendering
|
help: Enable headless rendering
|
||||||
|
- angle:
|
||||||
|
long: angle
|
||||||
|
help: Enable ANGLE rendering (on Windows only)
|
||||||
- dp_ratio:
|
- dp_ratio:
|
||||||
short: p
|
short: p
|
||||||
long: device-pixel-ratio
|
long: device-pixel-ratio
|
||||||
|
|
|
@ -0,0 +1,617 @@
|
||||||
|
// Licensed under the Apache License, Version 2.0.
|
||||||
|
// This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
//! Based on https://github.com/tomaka/glutin/blob/1b2d62c0e9/src/api/egl/mod.rs
|
||||||
|
#![cfg(windows)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
use glutin::ContextError;
|
||||||
|
use glutin::CreationError;
|
||||||
|
use glutin::GlAttributes;
|
||||||
|
use glutin::GlContext;
|
||||||
|
use glutin::GlRequest;
|
||||||
|
use glutin::PixelFormat;
|
||||||
|
use glutin::PixelFormatRequirements;
|
||||||
|
use glutin::ReleaseBehavior;
|
||||||
|
use glutin::Robustness;
|
||||||
|
use glutin::Api;
|
||||||
|
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
use std::{mem, ptr};
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
use mozangle::egl::ffi as egl;
|
||||||
|
mod ffi {
|
||||||
|
pub use mozangle::egl::ffi as egl;
|
||||||
|
pub use mozangle::egl::ffi::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Context {
|
||||||
|
display: ffi::egl::types::EGLDisplay,
|
||||||
|
context: ffi::egl::types::EGLContext,
|
||||||
|
surface: Cell<ffi::egl::types::EGLSurface>,
|
||||||
|
api: Api,
|
||||||
|
pixel_format: PixelFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
/// Start building an EGL context.
|
||||||
|
///
|
||||||
|
/// This function initializes some things and chooses the pixel format.
|
||||||
|
///
|
||||||
|
/// To finish the process, you must call `.finish(window)` on the `ContextPrototype`.
|
||||||
|
pub fn new<'a>(
|
||||||
|
pf_reqs: &PixelFormatRequirements,
|
||||||
|
opengl: &'a GlAttributes<&'a Context>,
|
||||||
|
) -> Result<ContextPrototype<'a>, CreationError>
|
||||||
|
{
|
||||||
|
if opengl.sharing.is_some() {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling `eglGetDisplay` or equivalent
|
||||||
|
let display = unsafe { egl::GetDisplay(ptr::null_mut()) };
|
||||||
|
|
||||||
|
if display.is_null() {
|
||||||
|
return Err(CreationError::OsError("Could not create EGL display object".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let egl_version = unsafe {
|
||||||
|
let mut major: ffi::egl::types::EGLint = mem::uninitialized();
|
||||||
|
let mut minor: ffi::egl::types::EGLint = mem::uninitialized();
|
||||||
|
|
||||||
|
if egl::Initialize(display, &mut major, &mut minor) == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("eglInitialize failed")))
|
||||||
|
}
|
||||||
|
|
||||||
|
(major, minor)
|
||||||
|
};
|
||||||
|
|
||||||
|
// the list of extensions supported by the client once initialized is different from the
|
||||||
|
// list of extensions obtained earlier
|
||||||
|
let extensions = if egl_version >= (1, 2) {
|
||||||
|
let p = unsafe { CStr::from_ptr(egl::QueryString(display, ffi::egl::EXTENSIONS as i32)) };
|
||||||
|
let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| format!(""));
|
||||||
|
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
// binding the right API and choosing the version
|
||||||
|
let (version, api) = unsafe {
|
||||||
|
match opengl.version {
|
||||||
|
GlRequest::Latest => {
|
||||||
|
if egl_version >= (1, 4) {
|
||||||
|
if egl::BindAPI(ffi::egl::OPENGL_API) != 0 {
|
||||||
|
(None, Api::OpenGl)
|
||||||
|
} else if egl::BindAPI(ffi::egl::OPENGL_ES_API) != 0 {
|
||||||
|
(None, Api::OpenGlEs)
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(None, Api::OpenGlEs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GlRequest::Specific(Api::OpenGlEs, version) => {
|
||||||
|
if egl_version >= (1, 2) {
|
||||||
|
if egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(version), Api::OpenGlEs)
|
||||||
|
},
|
||||||
|
GlRequest::Specific(Api::OpenGl, version) => {
|
||||||
|
if egl_version < (1, 4) {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
if egl::BindAPI(ffi::egl::OPENGL_API) == 0 {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
(Some(version), Api::OpenGl)
|
||||||
|
},
|
||||||
|
GlRequest::Specific(_, _) => return Err(CreationError::OpenGlVersionNotSupported),
|
||||||
|
GlRequest::GlThenGles { opengles_version, opengl_version } => {
|
||||||
|
if egl_version >= (1, 4) {
|
||||||
|
if egl::BindAPI(ffi::egl::OPENGL_API) != 0 {
|
||||||
|
(Some(opengl_version), Api::OpenGl)
|
||||||
|
} else if egl::BindAPI(ffi::egl::OPENGL_ES_API) != 0 {
|
||||||
|
(Some(opengles_version), Api::OpenGlEs)
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(Some(opengles_version), Api::OpenGlEs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (config_id, pixel_format) = unsafe {
|
||||||
|
try!(choose_fbconfig(display, &egl_version, api, version, pf_reqs))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ContextPrototype {
|
||||||
|
opengl: opengl,
|
||||||
|
display: display,
|
||||||
|
egl_version: egl_version,
|
||||||
|
extensions: extensions,
|
||||||
|
api: api,
|
||||||
|
version: version,
|
||||||
|
config_id: config_id,
|
||||||
|
pixel_format: pixel_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlContext for Context {
|
||||||
|
unsafe fn make_current(&self) -> Result<(), ContextError> {
|
||||||
|
let ret = egl::MakeCurrent(self.display, self.surface.get(), self.surface.get(), self.context);
|
||||||
|
|
||||||
|
if ret == 0 {
|
||||||
|
match egl::GetError() as u32 {
|
||||||
|
ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost),
|
||||||
|
err => panic!("eglMakeCurrent failed (eglGetError returned 0x{:x})", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_current(&self) -> bool {
|
||||||
|
unsafe { egl::GetCurrentContext() == self.context }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_proc_address(&self, addr: &str) -> *const () {
|
||||||
|
let addr = CString::new(addr.as_bytes()).unwrap();
|
||||||
|
let addr = addr.as_ptr();
|
||||||
|
unsafe {
|
||||||
|
egl::GetProcAddress(addr) as *const _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn swap_buffers(&self) -> Result<(), ContextError> {
|
||||||
|
if self.surface.get() == ffi::egl::NO_SURFACE {
|
||||||
|
return Err(ContextError::ContextLost);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = unsafe {
|
||||||
|
egl::SwapBuffers(self.display, self.surface.get())
|
||||||
|
};
|
||||||
|
|
||||||
|
if ret == 0 {
|
||||||
|
match unsafe { egl::GetError() } as u32 {
|
||||||
|
ffi::egl::CONTEXT_LOST => return Err(ContextError::ContextLost),
|
||||||
|
err => panic!("eglSwapBuffers failed (eglGetError returned 0x{:x})", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_api(&self) -> Api {
|
||||||
|
self.api
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_pixel_format(&self) -> PixelFormat {
|
||||||
|
self.pixel_format.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn resize(&self, _: u32, _: u32) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Context {}
|
||||||
|
unsafe impl Sync for Context {}
|
||||||
|
|
||||||
|
impl Drop for Context {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
// we don't call MakeCurrent(0, 0) because we are not sure that the context
|
||||||
|
// is still the current one
|
||||||
|
egl::DestroyContext(self.display, self.context);
|
||||||
|
egl::DestroySurface(self.display, self.surface.get());
|
||||||
|
egl::Terminate(self.display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ContextPrototype<'a> {
|
||||||
|
opengl: &'a GlAttributes<&'a Context>,
|
||||||
|
display: ffi::egl::types::EGLDisplay,
|
||||||
|
egl_version: (ffi::egl::types::EGLint, ffi::egl::types::EGLint),
|
||||||
|
extensions: Vec<String>,
|
||||||
|
api: Api,
|
||||||
|
version: Option<(u8, u8)>,
|
||||||
|
config_id: ffi::egl::types::EGLConfig,
|
||||||
|
pixel_format: PixelFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ContextPrototype<'a> {
|
||||||
|
pub fn get_native_visual_id(&self) -> ffi::egl::types::EGLint {
|
||||||
|
let mut value = unsafe { mem::uninitialized() };
|
||||||
|
let ret = unsafe { egl::GetConfigAttrib(self.display, self.config_id,
|
||||||
|
ffi::egl::NATIVE_VISUAL_ID
|
||||||
|
as ffi::egl::types::EGLint, &mut value) };
|
||||||
|
if ret == 0 { panic!("eglGetConfigAttrib failed") };
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self, native_window: ffi::EGLNativeWindowType)
|
||||||
|
-> Result<Context, CreationError>
|
||||||
|
{
|
||||||
|
let surface = unsafe {
|
||||||
|
let surface = egl::CreateWindowSurface(self.display, self.config_id, native_window,
|
||||||
|
ptr::null());
|
||||||
|
if surface.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("eglCreateWindowSurface failed")))
|
||||||
|
}
|
||||||
|
surface
|
||||||
|
};
|
||||||
|
|
||||||
|
self.finish_impl(surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish_pbuffer(self, dimensions: (u32, u32)) -> Result<Context, CreationError> {
|
||||||
|
let attrs = &[
|
||||||
|
ffi::egl::WIDTH as c_int, dimensions.0 as c_int,
|
||||||
|
ffi::egl::HEIGHT as c_int, dimensions.1 as c_int,
|
||||||
|
ffi::egl::NONE as c_int,
|
||||||
|
];
|
||||||
|
|
||||||
|
let surface = unsafe {
|
||||||
|
let surface = egl::CreatePbufferSurface(self.display, self.config_id,
|
||||||
|
attrs.as_ptr());
|
||||||
|
if surface.is_null() {
|
||||||
|
return Err(CreationError::OsError(format!("eglCreatePbufferSurface failed")))
|
||||||
|
}
|
||||||
|
surface
|
||||||
|
};
|
||||||
|
|
||||||
|
self.finish_impl(surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_impl(self, surface: ffi::egl::types::EGLSurface)
|
||||||
|
-> Result<Context, CreationError>
|
||||||
|
{
|
||||||
|
let context = unsafe {
|
||||||
|
if let Some(version) = self.version {
|
||||||
|
try!(create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, version, self.config_id,
|
||||||
|
self.opengl.debug, self.opengl.robustness))
|
||||||
|
|
||||||
|
} else if self.api == Api::OpenGlEs {
|
||||||
|
if let Ok(ctxt) = create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, (2, 0), self.config_id,
|
||||||
|
self.opengl.debug, self.opengl.robustness)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else if let Ok(ctxt) = create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, (1, 0),
|
||||||
|
self.config_id, self.opengl.debug,
|
||||||
|
self.opengl.robustness)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if let Ok(ctxt) = create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, (3, 2), self.config_id,
|
||||||
|
self.opengl.debug, self.opengl.robustness)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else if let Ok(ctxt) = create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, (3, 1),
|
||||||
|
self.config_id, self.opengl.debug,
|
||||||
|
self.opengl.robustness)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else if let Ok(ctxt) = create_context(self.display, &self.egl_version,
|
||||||
|
&self.extensions, self.api, (1, 0),
|
||||||
|
self.config_id, self.opengl.debug,
|
||||||
|
self.opengl.robustness)
|
||||||
|
{
|
||||||
|
ctxt
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::OpenGlVersionNotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Context {
|
||||||
|
display: self.display,
|
||||||
|
context: context,
|
||||||
|
surface: Cell::new(surface),
|
||||||
|
api: self.api,
|
||||||
|
pixel_format: self.pixel_format,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn choose_fbconfig(display: ffi::egl::types::EGLDisplay,
|
||||||
|
egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint),
|
||||||
|
api: Api, version: Option<(u8, u8)>, reqs: &PixelFormatRequirements)
|
||||||
|
-> Result<(ffi::egl::types::EGLConfig, PixelFormat), CreationError>
|
||||||
|
{
|
||||||
|
let descriptor = {
|
||||||
|
let mut out: Vec<c_int> = Vec::with_capacity(37);
|
||||||
|
|
||||||
|
if egl_version >= &(1, 2) {
|
||||||
|
out.push(ffi::egl::COLOR_BUFFER_TYPE as c_int);
|
||||||
|
out.push(ffi::egl::RGB_BUFFER as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push(ffi::egl::SURFACE_TYPE as c_int);
|
||||||
|
// TODO: Some versions of Mesa report a BAD_ATTRIBUTE error
|
||||||
|
// if we ask for PBUFFER_BIT as well as WINDOW_BIT
|
||||||
|
out.push((ffi::egl::WINDOW_BIT) as c_int);
|
||||||
|
|
||||||
|
match (api, version) {
|
||||||
|
(Api::OpenGlEs, Some((3, _))) => {
|
||||||
|
if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); }
|
||||||
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES3_BIT as c_int);
|
||||||
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES3_BIT as c_int);
|
||||||
|
},
|
||||||
|
(Api::OpenGlEs, Some((2, _))) => {
|
||||||
|
if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); }
|
||||||
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES2_BIT as c_int);
|
||||||
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES2_BIT as c_int);
|
||||||
|
},
|
||||||
|
(Api::OpenGlEs, Some((1, _))) => {
|
||||||
|
if egl_version >= &(1, 3) {
|
||||||
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES_BIT as c_int);
|
||||||
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_ES_BIT as c_int);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Api::OpenGlEs, _) => unimplemented!(),
|
||||||
|
(Api::OpenGl, _) => {
|
||||||
|
if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); }
|
||||||
|
out.push(ffi::egl::RENDERABLE_TYPE as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_BIT as c_int);
|
||||||
|
out.push(ffi::egl::CONFORMANT as c_int);
|
||||||
|
out.push(ffi::egl::OPENGL_BIT as c_int);
|
||||||
|
},
|
||||||
|
(_, _) => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(hardware_accelerated) = reqs.hardware_accelerated {
|
||||||
|
out.push(ffi::egl::CONFIG_CAVEAT as c_int);
|
||||||
|
out.push(if hardware_accelerated {
|
||||||
|
ffi::egl::NONE as c_int
|
||||||
|
} else {
|
||||||
|
ffi::egl::SLOW_CONFIG as c_int
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(color) = reqs.color_bits {
|
||||||
|
out.push(ffi::egl::RED_SIZE as c_int);
|
||||||
|
out.push((color / 3) as c_int);
|
||||||
|
out.push(ffi::egl::GREEN_SIZE as c_int);
|
||||||
|
out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int);
|
||||||
|
out.push(ffi::egl::BLUE_SIZE as c_int);
|
||||||
|
out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(alpha) = reqs.alpha_bits {
|
||||||
|
out.push(ffi::egl::ALPHA_SIZE as c_int);
|
||||||
|
out.push(alpha as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(depth) = reqs.depth_bits {
|
||||||
|
out.push(ffi::egl::DEPTH_SIZE as c_int);
|
||||||
|
out.push(depth as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(stencil) = reqs.stencil_bits {
|
||||||
|
out.push(ffi::egl::STENCIL_SIZE as c_int);
|
||||||
|
out.push(stencil as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(true) = reqs.double_buffer {
|
||||||
|
return Err(CreationError::NoAvailablePixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(multisampling) = reqs.multisampling {
|
||||||
|
out.push(ffi::egl::SAMPLES as c_int);
|
||||||
|
out.push(multisampling as c_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqs.stereoscopy {
|
||||||
|
return Err(CreationError::NoAvailablePixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: srgb is not taken into account
|
||||||
|
|
||||||
|
match reqs.release_behavior {
|
||||||
|
ReleaseBehavior::Flush => (),
|
||||||
|
ReleaseBehavior::None => {
|
||||||
|
// TODO: with EGL you need to manually set the behavior
|
||||||
|
unimplemented!()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
out.push(ffi::egl::NONE as c_int);
|
||||||
|
out
|
||||||
|
};
|
||||||
|
|
||||||
|
// calling `eglChooseConfig`
|
||||||
|
let mut config_id = mem::uninitialized();
|
||||||
|
let mut num_configs = mem::uninitialized();
|
||||||
|
if egl::ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("eglChooseConfig failed")));
|
||||||
|
}
|
||||||
|
if num_configs == 0 {
|
||||||
|
return Err(CreationError::NoAvailablePixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// analyzing each config
|
||||||
|
macro_rules! attrib {
|
||||||
|
($display:expr, $config:expr, $attr:expr) => (
|
||||||
|
{
|
||||||
|
let mut value = mem::uninitialized();
|
||||||
|
let res = egl::GetConfigAttrib($display, $config,
|
||||||
|
$attr as ffi::egl::types::EGLint, &mut value);
|
||||||
|
if res == 0 {
|
||||||
|
return Err(CreationError::OsError(format!("eglGetConfigAttrib failed")));
|
||||||
|
}
|
||||||
|
value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let desc = PixelFormat {
|
||||||
|
hardware_accelerated: attrib!(display, config_id, ffi::egl::CONFIG_CAVEAT)
|
||||||
|
!= ffi::egl::SLOW_CONFIG as i32,
|
||||||
|
color_bits: attrib!(display, config_id, ffi::egl::RED_SIZE) as u8 +
|
||||||
|
attrib!(display, config_id, ffi::egl::BLUE_SIZE) as u8 +
|
||||||
|
attrib!(display, config_id, ffi::egl::GREEN_SIZE) as u8,
|
||||||
|
alpha_bits: attrib!(display, config_id, ffi::egl::ALPHA_SIZE) as u8,
|
||||||
|
depth_bits: attrib!(display, config_id, ffi::egl::DEPTH_SIZE) as u8,
|
||||||
|
stencil_bits: attrib!(display, config_id, ffi::egl::STENCIL_SIZE) as u8,
|
||||||
|
stereoscopy: false,
|
||||||
|
double_buffer: true,
|
||||||
|
multisampling: match attrib!(display, config_id, ffi::egl::SAMPLES) {
|
||||||
|
0 | 1 => None,
|
||||||
|
a => Some(a as u16),
|
||||||
|
},
|
||||||
|
srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((config_id, desc))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn create_context(display: ffi::egl::types::EGLDisplay,
|
||||||
|
egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint),
|
||||||
|
extensions: &[String], api: Api, version: (u8, u8),
|
||||||
|
config_id: ffi::egl::types::EGLConfig, gl_debug: bool,
|
||||||
|
gl_robustness: Robustness)
|
||||||
|
-> Result<ffi::egl::types::EGLContext, CreationError>
|
||||||
|
{
|
||||||
|
let mut context_attributes = Vec::with_capacity(10);
|
||||||
|
let mut flags = 0;
|
||||||
|
|
||||||
|
if egl_version >= &(1, 5) || extensions.iter().find(|s| s == &"EGL_KHR_create_context")
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_MAJOR_VERSION as i32);
|
||||||
|
context_attributes.push(version.0 as i32);
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32);
|
||||||
|
context_attributes.push(version.1 as i32);
|
||||||
|
|
||||||
|
// handling robustness
|
||||||
|
let supports_robustness = egl_version >= &(1, 5) ||
|
||||||
|
extensions.iter()
|
||||||
|
.find(|s| s == &"EGL_EXT_create_context_robustness")
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
match gl_robustness {
|
||||||
|
Robustness::NotRobust => (),
|
||||||
|
|
||||||
|
Robustness::NoError => {
|
||||||
|
if extensions.iter().find(|s| s == &"EGL_KHR_create_context_no_error").is_some() {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_NO_ERROR_KHR as c_int);
|
||||||
|
context_attributes.push(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Robustness::RobustNoResetNotification => {
|
||||||
|
if supports_robustness {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
|
||||||
|
as c_int);
|
||||||
|
context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int);
|
||||||
|
flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int;
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::RobustnessNotSupported);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Robustness::TryRobustNoResetNotification => {
|
||||||
|
if supports_robustness {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
|
||||||
|
as c_int);
|
||||||
|
context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as c_int);
|
||||||
|
flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Robustness::RobustLoseContextOnReset => {
|
||||||
|
if supports_robustness {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
|
||||||
|
as c_int);
|
||||||
|
context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int);
|
||||||
|
flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int;
|
||||||
|
} else {
|
||||||
|
return Err(CreationError::RobustnessNotSupported);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Robustness::TryRobustLoseContextOnReset => {
|
||||||
|
if supports_robustness {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
|
||||||
|
as c_int);
|
||||||
|
context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as c_int);
|
||||||
|
flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as c_int;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if gl_debug {
|
||||||
|
if egl_version >= &(1, 5) {
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32);
|
||||||
|
context_attributes.push(ffi::egl::TRUE as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: using this flag sometimes generates an error
|
||||||
|
// there was a change in the specs that added this flag, so it may not be
|
||||||
|
// supported everywhere ; however it is not possible to know whether it is
|
||||||
|
// supported or not
|
||||||
|
//flags = flags | ffi::egl::CONTEXT_OPENGL_DEBUG_BIT_KHR as i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32);
|
||||||
|
context_attributes.push(flags);
|
||||||
|
|
||||||
|
} else if egl_version >= &(1, 3) && api == Api::OpenGlEs {
|
||||||
|
// robustness is not supported
|
||||||
|
match gl_robustness {
|
||||||
|
Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
|
||||||
|
return Err(CreationError::RobustnessNotSupported);
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
|
||||||
|
context_attributes.push(version.0 as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
context_attributes.push(ffi::egl::NONE as i32);
|
||||||
|
|
||||||
|
let context = egl::CreateContext(display, config_id, ptr::null(),
|
||||||
|
context_attributes.as_ptr());
|
||||||
|
|
||||||
|
if context.is_null() {
|
||||||
|
match egl::GetError() as u32 {
|
||||||
|
ffi::egl::BAD_ATTRIBUTE => return Err(CreationError::OpenGlVersionNotSupported),
|
||||||
|
e => panic!("eglCreateContext failed: 0x{:x}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ extern crate image;
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
extern crate mozangle;
|
||||||
#[cfg(feature = "headless")]
|
#[cfg(feature = "headless")]
|
||||||
extern crate osmesa_sys;
|
extern crate osmesa_sys;
|
||||||
extern crate ron;
|
extern crate ron;
|
||||||
|
@ -37,8 +39,10 @@ extern crate time;
|
||||||
extern crate webrender;
|
extern crate webrender;
|
||||||
extern crate yaml_rust;
|
extern crate yaml_rust;
|
||||||
|
|
||||||
|
mod angle;
|
||||||
mod binary_frame_reader;
|
mod binary_frame_reader;
|
||||||
mod blob;
|
mod blob;
|
||||||
|
mod egl;
|
||||||
mod json_frame_writer;
|
mod json_frame_writer;
|
||||||
mod parse_function;
|
mod parse_function;
|
||||||
mod perf;
|
mod perf;
|
||||||
|
@ -159,6 +163,7 @@ impl HeadlessContext {
|
||||||
|
|
||||||
pub enum WindowWrapper {
|
pub enum WindowWrapper {
|
||||||
Window(glutin::GlWindow, Rc<gl::Gl>),
|
Window(glutin::GlWindow, Rc<gl::Gl>),
|
||||||
|
Angle(glutin::Window, angle::Context, Rc<gl::Gl>),
|
||||||
Headless(HeadlessContext, Rc<gl::Gl>),
|
Headless(HeadlessContext, Rc<gl::Gl>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,21 +173,26 @@ impl WindowWrapper {
|
||||||
fn swap_buffers(&self) {
|
fn swap_buffers(&self) {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(ref window, _) => window.swap_buffers().unwrap(),
|
WindowWrapper::Window(ref window, _) => window.swap_buffers().unwrap(),
|
||||||
|
WindowWrapper::Angle(_, ref context, _) => context.swap_buffers().unwrap(),
|
||||||
WindowWrapper::Headless(_, _) => {}
|
WindowWrapper::Headless(_, _) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_inner_size(&self) -> DeviceUintSize {
|
fn get_inner_size(&self) -> DeviceUintSize {
|
||||||
let (w, h) = match *self {
|
|
||||||
//HACK: `winit` needs to figure out its hidpi story...
|
//HACK: `winit` needs to figure out its hidpi story...
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
WindowWrapper::Window(ref window, _) => {
|
fn inner_size(window: &glutin::Window) -> (u32, u32) {
|
||||||
let (w, h) = window.get_inner_size().unwrap();
|
let (w, h) = window.get_inner_size().unwrap();
|
||||||
let factor = window.hidpi_factor();
|
let factor = window.hidpi_factor();
|
||||||
((w as f32 * factor) as _, (h as f32 * factor) as _)
|
((w as f32 * factor) as _, (h as f32 * factor) as _)
|
||||||
},
|
}
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
WindowWrapper::Window(ref window, _) => window.get_inner_size().unwrap(),
|
fn inner_size(window: &glutin::Window) -> (u32, u32) {
|
||||||
|
window.get_inner_size().unwrap()
|
||||||
|
}
|
||||||
|
let (w, h) = match *self {
|
||||||
|
WindowWrapper::Window(ref window, _) => inner_size(window.window()),
|
||||||
|
WindowWrapper::Angle(ref window, ..) => inner_size(window),
|
||||||
WindowWrapper::Headless(ref context, _) => (context.width, context.height),
|
WindowWrapper::Headless(ref context, _) => (context.width, context.height),
|
||||||
};
|
};
|
||||||
DeviceUintSize::new(w, h)
|
DeviceUintSize::new(w, h)
|
||||||
|
@ -191,6 +201,7 @@ impl WindowWrapper {
|
||||||
fn hidpi_factor(&self) -> f32 {
|
fn hidpi_factor(&self) -> f32 {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(ref window, _) => window.hidpi_factor(),
|
WindowWrapper::Window(ref window, _) => window.hidpi_factor(),
|
||||||
|
WindowWrapper::Angle(ref window, ..) => window.hidpi_factor(),
|
||||||
WindowWrapper::Headless(_, _) => 1.0,
|
WindowWrapper::Headless(_, _) => 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,6 +209,7 @@ impl WindowWrapper {
|
||||||
fn resize(&mut self, size: DeviceUintSize) {
|
fn resize(&mut self, size: DeviceUintSize) {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(ref mut window, _) => window.set_inner_size(size.width, size.height),
|
WindowWrapper::Window(ref mut window, _) => window.set_inner_size(size.width, size.height),
|
||||||
|
WindowWrapper::Angle(ref mut window, ..) => window.set_inner_size(size.width, size.height),
|
||||||
WindowWrapper::Headless(_, _) => unimplemented!(), // requites Glutin update
|
WindowWrapper::Headless(_, _) => unimplemented!(), // requites Glutin update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,19 +217,24 @@ impl WindowWrapper {
|
||||||
fn set_title(&mut self, title: &str) {
|
fn set_title(&mut self, title: &str) {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(ref window, _) => window.set_title(title),
|
WindowWrapper::Window(ref window, _) => window.set_title(title),
|
||||||
|
WindowWrapper::Angle(ref window, ..) => window.set_title(title),
|
||||||
WindowWrapper::Headless(_, _) => (),
|
WindowWrapper::Headless(_, _) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gl(&self) -> &gl::Gl {
|
pub fn gl(&self) -> &gl::Gl {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(_, ref gl) | WindowWrapper::Headless(_, ref gl) => &**gl,
|
WindowWrapper::Window(_, ref gl) |
|
||||||
|
WindowWrapper::Angle(_, _, ref gl) |
|
||||||
|
WindowWrapper::Headless(_, ref gl) => &**gl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_gl(&self) -> Rc<gl::Gl> {
|
pub fn clone_gl(&self) -> Rc<gl::Gl> {
|
||||||
match *self {
|
match *self {
|
||||||
WindowWrapper::Window(_, ref gl) | WindowWrapper::Headless(_, ref gl) => gl.clone(),
|
WindowWrapper::Window(_, ref gl) |
|
||||||
|
WindowWrapper::Angle(_, _, ref gl) |
|
||||||
|
WindowWrapper::Headless(_, ref gl) => gl.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,6 +244,7 @@ fn make_window(
|
||||||
dp_ratio: Option<f32>,
|
dp_ratio: Option<f32>,
|
||||||
vsync: bool,
|
vsync: bool,
|
||||||
events_loop: &Option<glutin::EventsLoop>,
|
events_loop: &Option<glutin::EventsLoop>,
|
||||||
|
angle: bool,
|
||||||
) -> WindowWrapper {
|
) -> WindowWrapper {
|
||||||
let wrapper = match *events_loop {
|
let wrapper = match *events_loop {
|
||||||
Some(ref events_loop) => {
|
Some(ref events_loop) => {
|
||||||
|
@ -240,26 +258,38 @@ fn make_window(
|
||||||
.with_title("WRech")
|
.with_title("WRech")
|
||||||
.with_multitouch()
|
.with_multitouch()
|
||||||
.with_dimensions(size.width, size.height);
|
.with_dimensions(size.width, size.height);
|
||||||
let window = glutin::GlWindow::new(window_builder, context_builder, events_loop)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
|
let init = |context: &glutin::GlContext| {
|
||||||
unsafe {
|
unsafe {
|
||||||
window
|
context
|
||||||
.make_current()
|
.make_current()
|
||||||
.expect("unable to make context current!");
|
.expect("unable to make context current!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let gl = match window.get_api() {
|
match context.get_api() {
|
||||||
glutin::Api::OpenGl => unsafe {
|
glutin::Api::OpenGl => unsafe {
|
||||||
gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
|
gl::GlFns::load_with(|symbol| context.get_proc_address(symbol) as *const _)
|
||||||
},
|
},
|
||||||
glutin::Api::OpenGlEs => unsafe {
|
glutin::Api::OpenGlEs => unsafe {
|
||||||
gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
|
gl::GlesFns::load_with(|symbol| context.get_proc_address(symbol) as *const _)
|
||||||
},
|
},
|
||||||
glutin::Api::WebGl => unimplemented!(),
|
glutin::Api::WebGl => unimplemented!(),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if angle {
|
||||||
|
let (window, context) = angle::Context::with_window(
|
||||||
|
window_builder, context_builder, events_loop
|
||||||
|
).unwrap();
|
||||||
|
let gl = init(&context);
|
||||||
|
WindowWrapper::Angle(window, context, gl)
|
||||||
|
} else {
|
||||||
|
let window = glutin::GlWindow::new(window_builder, context_builder, events_loop)
|
||||||
|
.unwrap();
|
||||||
|
let gl = init(&window);
|
||||||
WindowWrapper::Window(window, gl)
|
WindowWrapper::Window(window, gl)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
let gl = match gl::GlType::default() {
|
let gl = match gl::GlType::default() {
|
||||||
gl::GlType::Gl => unsafe {
|
gl::GlType::Gl => unsafe {
|
||||||
|
@ -293,8 +323,14 @@ fn make_window(
|
||||||
wrapper
|
wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum NotifierEvent {
|
||||||
|
WakeUp,
|
||||||
|
ShutDown,
|
||||||
|
}
|
||||||
|
|
||||||
struct Notifier {
|
struct Notifier {
|
||||||
tx: Sender<()>,
|
tx: Sender<NotifierEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup a notifier so we can wait for frames to be finished
|
// setup a notifier so we can wait for frames to be finished
|
||||||
|
@ -306,7 +342,11 @@ impl RenderNotifier for Notifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wake_up(&self) {
|
fn wake_up(&self) {
|
||||||
self.tx.send(()).unwrap();
|
self.tx.send(NotifierEvent::WakeUp).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shut_down(&self) {
|
||||||
|
self.tx.send(NotifierEvent::ShutDown).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_document_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
|
fn new_document_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
|
||||||
|
@ -316,7 +356,7 @@ impl RenderNotifier for Notifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_notifier() -> (Box<RenderNotifier>, Receiver<()>) {
|
fn create_notifier() -> (Box<RenderNotifier>, Receiver<NotifierEvent>) {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
(Box::new(Notifier { tx: tx }), rx)
|
(Box::new(Notifier { tx: tx }), rx)
|
||||||
}
|
}
|
||||||
|
@ -364,7 +404,9 @@ fn main() {
|
||||||
Some(glutin::EventsLoop::new())
|
Some(glutin::EventsLoop::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut window = make_window(size, dp_ratio, args.is_present("vsync"), &events_loop);
|
let mut window = make_window(
|
||||||
|
size, dp_ratio, args.is_present("vsync"), &events_loop, args.is_present("angle"),
|
||||||
|
);
|
||||||
let dp_ratio = dp_ratio.unwrap_or(window.hidpi_factor());
|
let dp_ratio = dp_ratio.unwrap_or(window.hidpi_factor());
|
||||||
let dim = window.get_inner_size();
|
let dim = window.get_inner_size();
|
||||||
|
|
||||||
|
@ -420,17 +462,19 @@ fn main() {
|
||||||
reftest_options.allow_max_difference = allow_max_diff.parse().unwrap_or(1);
|
reftest_options.allow_max_difference = allow_max_diff.parse().unwrap_or(1);
|
||||||
reftest_options.allow_num_differences = dim.width as usize * dim.height as usize;
|
reftest_options.allow_num_differences = dim.width as usize * dim.height as usize;
|
||||||
}
|
}
|
||||||
let num_failures = ReftestHarness::new(&mut wrench, &mut window, rx.unwrap())
|
let rx = rx.unwrap();
|
||||||
|
let num_failures = ReftestHarness::new(&mut wrench, &mut window, &rx)
|
||||||
.run(base_manifest, specific_reftest, &reftest_options);
|
.run(base_manifest, specific_reftest, &reftest_options);
|
||||||
wrench.renderer.deinit();
|
wrench.shut_down(rx);
|
||||||
// exit with an error code to fail on CI
|
// exit with an error code to fail on CI
|
||||||
process::exit(num_failures as _);
|
process::exit(num_failures as _);
|
||||||
} else if let Some(_) = args.subcommand_matches("rawtest") {
|
} else if let Some(_) = args.subcommand_matches("rawtest") {
|
||||||
|
let rx = rx.unwrap();
|
||||||
{
|
{
|
||||||
let harness = RawtestHarness::new(&mut wrench, &mut window, rx.unwrap());
|
let harness = RawtestHarness::new(&mut wrench, &mut window, &rx);
|
||||||
harness.run();
|
harness.run();
|
||||||
}
|
}
|
||||||
wrench.renderer.deinit();
|
wrench.shut_down(rx);
|
||||||
return;
|
return;
|
||||||
} else if let Some(subargs) = args.subcommand_matches("perf") {
|
} else if let Some(subargs) = args.subcommand_matches("perf") {
|
||||||
// Perf mode wants to benchmark the total cost of drawing
|
// Perf mode wants to benchmark the total cost of drawing
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use NotifierEvent;
|
||||||
use WindowWrapper;
|
use WindowWrapper;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
@ -123,11 +124,11 @@ impl Profile {
|
||||||
pub struct PerfHarness<'a> {
|
pub struct PerfHarness<'a> {
|
||||||
wrench: &'a mut Wrench,
|
wrench: &'a mut Wrench,
|
||||||
window: &'a mut WindowWrapper,
|
window: &'a mut WindowWrapper,
|
||||||
rx: Receiver<()>,
|
rx: Receiver<NotifierEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PerfHarness<'a> {
|
impl<'a> PerfHarness<'a> {
|
||||||
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<()>) -> Self {
|
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<NotifierEvent>) -> Self {
|
||||||
PerfHarness { wrench, window, rx }
|
PerfHarness { wrench, window, rx }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use WindowWrapper;
|
use {WindowWrapper, NotifierEvent};
|
||||||
use image::png::PNGEncoder;
|
use image::png::PNGEncoder;
|
||||||
use image::{self, ColorType, GenericImage};
|
use image::{self, ColorType, GenericImage};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -77,7 +77,7 @@ pub fn png(
|
||||||
surface: ReadSurface,
|
surface: ReadSurface,
|
||||||
window: &mut WindowWrapper,
|
window: &mut WindowWrapper,
|
||||||
mut reader: YamlFrameReader,
|
mut reader: YamlFrameReader,
|
||||||
rx: Receiver<()>,
|
rx: Receiver<NotifierEvent>,
|
||||||
) {
|
) {
|
||||||
reader.do_frame(wrench);
|
reader.do_frame(wrench);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use WindowWrapper;
|
use {WindowWrapper, NotifierEvent};
|
||||||
use blob;
|
use blob;
|
||||||
use euclid::{TypedRect, TypedSize2D, TypedPoint2D};
|
use euclid::{TypedRect, TypedSize2D, TypedPoint2D};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -13,7 +13,7 @@ use wrench::Wrench;
|
||||||
|
|
||||||
pub struct RawtestHarness<'a> {
|
pub struct RawtestHarness<'a> {
|
||||||
wrench: &'a mut Wrench,
|
wrench: &'a mut Wrench,
|
||||||
rx: Receiver<()>,
|
rx: &'a Receiver<NotifierEvent>,
|
||||||
window: &'a mut WindowWrapper,
|
window: &'a mut WindowWrapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ fn rect<T: Copy, U>(x: T, y: T, width: T, height: T) -> TypedRect<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RawtestHarness<'a> {
|
impl<'a> RawtestHarness<'a> {
|
||||||
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<()>) -> Self {
|
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: &'a Receiver<NotifierEvent>) -> Self {
|
||||||
RawtestHarness {
|
RawtestHarness {
|
||||||
wrench,
|
wrench,
|
||||||
rx,
|
rx,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use WindowWrapper;
|
use {WindowWrapper, NotifierEvent};
|
||||||
use base64;
|
use base64;
|
||||||
use image::load as load_piston_image;
|
use image::load as load_piston_image;
|
||||||
use image::png::PNGEncoder;
|
use image::png::PNGEncoder;
|
||||||
|
@ -292,10 +292,10 @@ impl ReftestManifest {
|
||||||
pub struct ReftestHarness<'a> {
|
pub struct ReftestHarness<'a> {
|
||||||
wrench: &'a mut Wrench,
|
wrench: &'a mut Wrench,
|
||||||
window: &'a mut WindowWrapper,
|
window: &'a mut WindowWrapper,
|
||||||
rx: Receiver<()>,
|
rx: &'a Receiver<NotifierEvent>,
|
||||||
}
|
}
|
||||||
impl<'a> ReftestHarness<'a> {
|
impl<'a> ReftestHarness<'a> {
|
||||||
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<()>) -> Self {
|
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: &'a Receiver<NotifierEvent>) -> Self {
|
||||||
ReftestHarness { wrench, window, rx }
|
ReftestHarness { wrench, window, rx }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,13 @@ use ron_frame_writer::RonFrameWriter;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::sync::mpsc::Receiver;
|
||||||
use time;
|
use time;
|
||||||
use webrender;
|
use webrender;
|
||||||
use webrender::api::*;
|
use webrender::api::*;
|
||||||
use webrender::{DebugFlags, RendererStats};
|
use webrender::{DebugFlags, RendererStats};
|
||||||
use yaml_frame_writer::YamlFrameWriterReceiver;
|
use yaml_frame_writer::YamlFrameWriterReceiver;
|
||||||
use {WindowWrapper, BLACK_COLOR, WHITE_COLOR};
|
use {WindowWrapper, NotifierEvent, BLACK_COLOR, WHITE_COLOR};
|
||||||
|
|
||||||
// TODO(gw): This descriptor matches what we currently support for fonts
|
// TODO(gw): This descriptor matches what we currently support for fonts
|
||||||
// but is quite a mess. We should at least document and
|
// but is quite a mess. We should at least document and
|
||||||
|
@ -590,4 +591,18 @@ impl Wrench {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shut_down(self, rx: Receiver<NotifierEvent>) {
|
||||||
|
self.api.shut_down();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match rx.recv() {
|
||||||
|
Ok(NotifierEvent::ShutDown) => { break; }
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => { panic!("Did not shut down properly: {:?}.", e); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.renderer.deinit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,13 +599,10 @@ impl YamlFrameReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_radial_gradient(&mut self, dl: &mut DisplayListBuilder, item: &Yaml) -> RadialGradient {
|
fn to_radial_gradient(&mut self, dl: &mut DisplayListBuilder, item: &Yaml) -> RadialGradient {
|
||||||
if item["start-center"].is_badvalue() {
|
let center = item["center"].as_point().expect("radial gradient must have center");
|
||||||
let center = item["center"]
|
let radius = item["radius"].as_size().expect("radial gradient must have a radius");
|
||||||
.as_point()
|
|
||||||
.expect("radial gradient must have start center");
|
if item["start-radius"].is_badvalue() {
|
||||||
let radius = item["radius"]
|
|
||||||
.as_size()
|
|
||||||
.expect("radial gradient must have start radius");
|
|
||||||
let stops = item["stops"]
|
let stops = item["stops"]
|
||||||
.as_vec()
|
.as_vec()
|
||||||
.expect("radial gradient must have stops")
|
.expect("radial gradient must have stops")
|
||||||
|
@ -629,19 +626,12 @@ impl YamlFrameReader {
|
||||||
|
|
||||||
dl.create_radial_gradient(center, radius, stops, extend_mode)
|
dl.create_radial_gradient(center, radius, stops, extend_mode)
|
||||||
} else {
|
} else {
|
||||||
let start_center = item["start-center"]
|
|
||||||
.as_point()
|
|
||||||
.expect("radial gradient must have start center");
|
|
||||||
let start_radius = item["start-radius"]
|
let start_radius = item["start-radius"]
|
||||||
.as_force_f32()
|
.as_force_f32()
|
||||||
.expect("radial gradient must have start radius");
|
.expect("radial gradient must have start radius");
|
||||||
let end_center = item["end-center"]
|
|
||||||
.as_point()
|
|
||||||
.expect("radial gradient must have end center");
|
|
||||||
let end_radius = item["end-radius"]
|
let end_radius = item["end-radius"]
|
||||||
.as_force_f32()
|
.as_force_f32()
|
||||||
.expect("radial gradient must have end radius");
|
.expect("radial gradient must have end radius");
|
||||||
let ratio_xy = item["ratio-xy"].as_force_f32().unwrap_or(1.0);
|
|
||||||
let stops = item["stops"]
|
let stops = item["stops"]
|
||||||
.as_vec()
|
.as_vec()
|
||||||
.expect("radial gradient must have stops")
|
.expect("radial gradient must have stops")
|
||||||
|
@ -664,11 +654,10 @@ impl YamlFrameReader {
|
||||||
};
|
};
|
||||||
|
|
||||||
dl.create_complex_radial_gradient(
|
dl.create_complex_radial_gradient(
|
||||||
start_center,
|
center,
|
||||||
|
radius,
|
||||||
start_radius,
|
start_radius,
|
||||||
end_center,
|
|
||||||
end_radius,
|
end_radius,
|
||||||
ratio_xy,
|
|
||||||
stops,
|
stops,
|
||||||
extend_mode,
|
extend_mode,
|
||||||
)
|
)
|
||||||
|
|
|
@ -905,11 +905,10 @@ impl YamlFrameWriter {
|
||||||
];
|
];
|
||||||
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
||||||
str_node(&mut v, "border-type", "radial-gradient");
|
str_node(&mut v, "border-type", "radial-gradient");
|
||||||
point_node(&mut v, "start-center", &details.gradient.start_center);
|
point_node(&mut v, "center", &details.gradient.center);
|
||||||
|
size_node(&mut v, "radius", &details.gradient.radius);
|
||||||
f32_node(&mut v, "start-radius", details.gradient.start_radius);
|
f32_node(&mut v, "start-radius", details.gradient.start_radius);
|
||||||
point_node(&mut v, "end-center", &details.gradient.end_center);
|
|
||||||
f32_node(&mut v, "end-radius", details.gradient.end_radius);
|
f32_node(&mut v, "end-radius", details.gradient.end_radius);
|
||||||
f32_node(&mut v, "ratio-xy", details.gradient.ratio_xy);
|
|
||||||
let mut stops = vec![];
|
let mut stops = vec![];
|
||||||
for stop in display_list.get(base.gradient_stops()) {
|
for stop in display_list.get(base.gradient_stops()) {
|
||||||
stops.push(Yaml::Real(stop.offset.to_string()));
|
stops.push(Yaml::Real(stop.offset.to_string()));
|
||||||
|
@ -961,11 +960,10 @@ impl YamlFrameWriter {
|
||||||
}
|
}
|
||||||
RadialGradient(item) => {
|
RadialGradient(item) => {
|
||||||
str_node(&mut v, "type", "radial-gradient");
|
str_node(&mut v, "type", "radial-gradient");
|
||||||
point_node(&mut v, "start-center", &item.gradient.start_center);
|
point_node(&mut v, "center", &item.gradient.center);
|
||||||
|
size_node(&mut v, "center", &item.gradient.radius);
|
||||||
f32_node(&mut v, "start-radius", item.gradient.start_radius);
|
f32_node(&mut v, "start-radius", item.gradient.start_radius);
|
||||||
point_node(&mut v, "end-center", &item.gradient.end_center);
|
|
||||||
f32_node(&mut v, "end-radius", item.gradient.end_radius);
|
f32_node(&mut v, "end-radius", item.gradient.end_radius);
|
||||||
f32_node(&mut v, "ratio-xy", item.gradient.ratio_xy);
|
|
||||||
size_node(&mut v, "tile-size", &item.tile_size);
|
size_node(&mut v, "tile-size", &item.tile_size);
|
||||||
size_node(&mut v, "tile-spacing", &item.tile_spacing);
|
size_node(&mut v, "tile-spacing", &item.tile_spacing);
|
||||||
let mut stops = vec![];
|
let mut stops = vec![];
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "AudioSegment.h"
|
#include "AudioSegment.h"
|
||||||
|
#include "AudioConverter.h"
|
||||||
#include "AutoTaskQueue.h"
|
#include "AutoTaskQueue.h"
|
||||||
#include "CSFLog.h"
|
#include "CSFLog.h"
|
||||||
#include "DOMMediaStream.h"
|
#include "DOMMediaStream.h"
|
||||||
|
@ -487,76 +488,156 @@ public:
|
||||||
, mTaskQueue(
|
, mTaskQueue(
|
||||||
new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::WEBRTC_DECODER),
|
new AutoTaskQueue(GetMediaThreadPool(MediaThreadType::WEBRTC_DECODER),
|
||||||
"AudioProxy"))
|
"AudioProxy"))
|
||||||
|
, mAudioConverter(nullptr)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mConduit);
|
MOZ_ASSERT(mConduit);
|
||||||
MOZ_COUNT_CTOR(AudioProxyThread);
|
MOZ_COUNT_CTOR(AudioProxyThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InternalProcessAudioChunk(TrackRate rate,
|
// This function is the identity if aInputRate is supported.
|
||||||
const AudioChunk& chunk,
|
// Else, it returns a rate that is supported, that ensure no loss in audio
|
||||||
bool enabled)
|
// quality: the sampling rate returned is always greater to the inputed
|
||||||
|
// sampling-rate, if they differ..
|
||||||
|
uint32_t AppropriateSendingRateForInputRate(uint32_t aInputRate)
|
||||||
|
{
|
||||||
|
AudioSessionConduit* conduit =
|
||||||
|
static_cast<AudioSessionConduit*>(mConduit.get());
|
||||||
|
if (conduit->IsSamplingFreqSupported(aInputRate)) {
|
||||||
|
return aInputRate;
|
||||||
|
}
|
||||||
|
if (aInputRate < 16000) {
|
||||||
|
return 16000;
|
||||||
|
} else if (aInputRate < 32000) {
|
||||||
|
return 32000;
|
||||||
|
} else if (aInputRate < 44100) {
|
||||||
|
return 44100;
|
||||||
|
} else {
|
||||||
|
return 48000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From an arbitrary AudioChunk at sampling-rate aRate, process the audio into
|
||||||
|
// something the conduit can work with (or send silence if the track is not
|
||||||
|
// enabled), and send the audio in 10ms chunks to the conduit.
|
||||||
|
void InternalProcessAudioChunk(TrackRate aRate,
|
||||||
|
const AudioChunk& aChunk,
|
||||||
|
bool aEnabled)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||||
|
|
||||||
// Convert to interleaved, 16-bits integer audio, with a maximum of two
|
// Convert to interleaved 16-bits integer audio, with a maximum of two
|
||||||
// channels (since the WebRTC.org code below makes the assumption that the
|
// channels (since the WebRTC.org code below makes the assumption that the
|
||||||
// input audio is either mono or stereo).
|
// input audio is either mono or stereo), with a sample-rate rate that is
|
||||||
uint32_t outputChannels = chunk.ChannelCount() == 1 ? 1 : 2;
|
// 16, 32, 44.1, or 48kHz.
|
||||||
const int16_t* samples = nullptr;
|
uint32_t outputChannels = aChunk.ChannelCount() == 1 ? 1 : 2;
|
||||||
UniquePtr<int16_t[]> convertedSamples;
|
int32_t transmissionRate = AppropriateSendingRateForInputRate(aRate);
|
||||||
|
|
||||||
// We take advantage of the fact that the common case (microphone directly
|
// We take advantage of the fact that the common case (microphone directly
|
||||||
// to PeerConnection, that is, a normal call), the samples are already
|
// to PeerConnection, that is, a normal call), the samples are already
|
||||||
// 16-bits mono, so the representation in interleaved and planar is the
|
// 16-bits mono, so the representation in interleaved and planar is the
|
||||||
// same, and we can just use that.
|
// same, and we can just use that.
|
||||||
if (enabled && outputChannels == 1 &&
|
if (aEnabled &&
|
||||||
chunk.mBufferFormat == AUDIO_FORMAT_S16) {
|
outputChannels == 1 &&
|
||||||
samples = chunk.ChannelData<int16_t>().Elements()[0];
|
aChunk.mBufferFormat == AUDIO_FORMAT_S16 &&
|
||||||
|
transmissionRate == aRate) {
|
||||||
|
const int16_t* samples = aChunk.ChannelData<int16_t>().Elements()[0];
|
||||||
|
PacketizeAndSend(samples,
|
||||||
|
transmissionRate,
|
||||||
|
outputChannels,
|
||||||
|
aChunk.mDuration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sampleCount = aChunk.mDuration * outputChannels;
|
||||||
|
if (mInterleavedAudio.Length() < sampleCount) {
|
||||||
|
mInterleavedAudio.SetLength(sampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aEnabled || aChunk.mBufferFormat == AUDIO_FORMAT_SILENCE) {
|
||||||
|
PodZero(mInterleavedAudio.Elements(), sampleCount);
|
||||||
|
} else if (aChunk.mBufferFormat == AUDIO_FORMAT_FLOAT32) {
|
||||||
|
DownmixAndInterleave(aChunk.ChannelData<float>(),
|
||||||
|
aChunk.mDuration,
|
||||||
|
aChunk.mVolume,
|
||||||
|
outputChannels,
|
||||||
|
mInterleavedAudio.Elements());
|
||||||
|
} else if (aChunk.mBufferFormat == AUDIO_FORMAT_S16) {
|
||||||
|
DownmixAndInterleave(aChunk.ChannelData<int16_t>(),
|
||||||
|
aChunk.mDuration,
|
||||||
|
aChunk.mVolume,
|
||||||
|
outputChannels,
|
||||||
|
mInterleavedAudio.Elements());
|
||||||
|
}
|
||||||
|
int16_t* inputAudio = mInterleavedAudio.Elements();
|
||||||
|
size_t inputAudioFrameCount = aChunk.mDuration;
|
||||||
|
|
||||||
|
AudioConfig inputConfig(AudioConfig::ChannelLayout(outputChannels),
|
||||||
|
aRate,
|
||||||
|
AudioConfig::FORMAT_S16);
|
||||||
|
AudioConfig outputConfig(AudioConfig::ChannelLayout(outputChannels),
|
||||||
|
transmissionRate,
|
||||||
|
AudioConfig::FORMAT_S16);
|
||||||
|
// Resample to an acceptable sample-rate for the sending side
|
||||||
|
if (!mAudioConverter ||
|
||||||
|
mAudioConverter->InputConfig() != inputConfig ||
|
||||||
|
mAudioConverter->OutputConfig() != outputConfig) {
|
||||||
|
mAudioConverter = MakeUnique<AudioConverter>(inputConfig, outputConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t* processedAudio = nullptr;
|
||||||
|
size_t framesProcessed =
|
||||||
|
mAudioConverter->Process(inputAudio, inputAudioFrameCount);
|
||||||
|
|
||||||
|
if (framesProcessed == 0) {
|
||||||
|
// In place conversion not possible, use a buffer.
|
||||||
|
framesProcessed =
|
||||||
|
mAudioConverter->Process(mOutputAudio,
|
||||||
|
inputAudio,
|
||||||
|
inputAudioFrameCount);
|
||||||
|
processedAudio = mOutputAudio.Data();
|
||||||
} else {
|
} else {
|
||||||
convertedSamples =
|
processedAudio = inputAudio;
|
||||||
MakeUnique<int16_t[]>(chunk.mDuration * outputChannels);
|
|
||||||
|
|
||||||
if (!enabled || chunk.mBufferFormat == AUDIO_FORMAT_SILENCE) {
|
|
||||||
PodZero(convertedSamples.get(), chunk.mDuration * outputChannels);
|
|
||||||
} else if (chunk.mBufferFormat == AUDIO_FORMAT_FLOAT32) {
|
|
||||||
DownmixAndInterleave(chunk.ChannelData<float>(),
|
|
||||||
chunk.mDuration,
|
|
||||||
chunk.mVolume,
|
|
||||||
outputChannels,
|
|
||||||
convertedSamples.get());
|
|
||||||
} else if (chunk.mBufferFormat == AUDIO_FORMAT_S16) {
|
|
||||||
DownmixAndInterleave(chunk.ChannelData<int16_t>(),
|
|
||||||
chunk.mDuration,
|
|
||||||
chunk.mVolume,
|
|
||||||
outputChannels,
|
|
||||||
convertedSamples.get());
|
|
||||||
}
|
|
||||||
samples = convertedSamples.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(!(rate % 100)); // rate should be a multiple of 100
|
PacketizeAndSend(processedAudio,
|
||||||
|
transmissionRate,
|
||||||
|
outputChannels,
|
||||||
|
framesProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the rate or the number of channels has changed since the last
|
// This packetizes aAudioData in 10ms chunks and sends it.
|
||||||
// time we came through. I realize it may be overkill to check if the rate
|
// aAudioData is interleaved audio data at a rate and with a channel count
|
||||||
// has changed, but I believe it is possible (e.g. if we change sources) and
|
// that is appropriate to send with the conduit.
|
||||||
// it costs us very little to handle this case.
|
void PacketizeAndSend(const int16_t* aAudioData,
|
||||||
|
uint32_t aRate,
|
||||||
|
uint32_t aChannels,
|
||||||
|
uint32_t aFrameCount)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(AppropriateSendingRateForInputRate(aRate) == aRate);
|
||||||
|
MOZ_ASSERT(aChannels == 1 || aChannels == 2);
|
||||||
|
MOZ_ASSERT(aAudioData);
|
||||||
|
|
||||||
uint32_t audio_10ms = rate / 100;
|
uint32_t audio_10ms = aRate / 100;
|
||||||
|
|
||||||
if (!mPacketizer || mPacketizer->PacketSize() != audio_10ms ||
|
if (!mPacketizer || mPacketizer->PacketSize() != audio_10ms ||
|
||||||
mPacketizer->Channels() != outputChannels) {
|
mPacketizer->Channels() != aChannels) {
|
||||||
// It's ok to drop the audio still in the packetizer here.
|
// It's the right thing to drop the bit of audio still in the packetizer:
|
||||||
|
// we don't want to send to the conduit audio that has two different
|
||||||
|
// rates while telling it that it has a constante rate.
|
||||||
mPacketizer = MakeUnique<AudioPacketizer<int16_t, int16_t>>(
|
mPacketizer = MakeUnique<AudioPacketizer<int16_t, int16_t>>(
|
||||||
audio_10ms, outputChannels);
|
audio_10ms, aChannels);
|
||||||
mPacket = MakeUnique<int16_t[]>(audio_10ms * outputChannels);
|
mPacket = MakeUnique<int16_t[]>(audio_10ms * aChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
mPacketizer->Input(samples, chunk.mDuration);
|
mPacketizer->Input(aAudioData, aFrameCount);
|
||||||
|
|
||||||
while (mPacketizer->PacketsAvailable()) {
|
while (mPacketizer->PacketsAvailable()) {
|
||||||
mPacketizer->Output(mPacket.get());
|
mPacketizer->Output(mPacket.get());
|
||||||
mConduit->SendAudioFrame(
|
mConduit->SendAudioFrame(mPacket.get(),
|
||||||
mPacket.get(), mPacketizer->PacketSize(), rate, mPacketizer->Channels(), 0);
|
mPacketizer->PacketSize(),
|
||||||
|
aRate,
|
||||||
|
mPacketizer->Channels(),
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,6 +669,9 @@ protected:
|
||||||
UniquePtr<AudioPacketizer<int16_t, int16_t>> mPacketizer;
|
UniquePtr<AudioPacketizer<int16_t, int16_t>> mPacketizer;
|
||||||
// A buffer to hold a single packet of audio.
|
// A buffer to hold a single packet of audio.
|
||||||
UniquePtr<int16_t[]> mPacket;
|
UniquePtr<int16_t[]> mPacket;
|
||||||
|
nsTArray<int16_t> mInterleavedAudio;
|
||||||
|
AlignedShortBuffer mOutputAudio;
|
||||||
|
UniquePtr<AudioConverter> mAudioConverter;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
|
||||||
|
@ -1965,14 +2049,24 @@ public:
|
||||||
, mMaybeTrackNeedsUnmute(true)
|
, mMaybeTrackNeedsUnmute(true)
|
||||||
{
|
{
|
||||||
MOZ_RELEASE_ASSERT(mSource, "Must be used with a SourceMediaStream");
|
MOZ_RELEASE_ASSERT(mSource, "Must be used with a SourceMediaStream");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~GenericReceiveListener()
|
||||||
|
{
|
||||||
|
NS_ReleaseOnMainThreadSystemGroup(
|
||||||
|
"GenericReceiveListener::track_", mTrack.forget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTrackToSource(uint32_t aRate = 0)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT((aRate != 0 && mTrack->AsAudioStreamTrack()) ||
|
||||||
|
mTrack->AsVideoStreamTrack());
|
||||||
|
|
||||||
if (mTrack->AsAudioStreamTrack()) {
|
if (mTrack->AsAudioStreamTrack()) {
|
||||||
mSource->AddAudioTrack(
|
mSource->AddAudioTrack(
|
||||||
mTrackId, mSource->GraphRate(), 0, new AudioSegment());
|
mTrackId, aRate, 0, new AudioSegment());
|
||||||
} else if (mTrack->AsVideoStreamTrack()) {
|
} else if (mTrack->AsVideoStreamTrack()) {
|
||||||
mSource->AddTrack(mTrackId, 0, new VideoSegment());
|
mSource->AddTrack(mTrackId, 0, new VideoSegment());
|
||||||
} else {
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Unknown track type");
|
|
||||||
}
|
}
|
||||||
CSFLogDebug(
|
CSFLogDebug(
|
||||||
LOGTAG,
|
LOGTAG,
|
||||||
|
@ -1986,12 +2080,6 @@ public:
|
||||||
mSource->AddListener(this);
|
mSource->AddListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GenericReceiveListener()
|
|
||||||
{
|
|
||||||
NS_ReleaseOnMainThreadSystemGroup(
|
|
||||||
"GenericReceiveListener::track_", mTrack.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddSelf()
|
void AddSelf()
|
||||||
{
|
{
|
||||||
if (!mListening) {
|
if (!mListening) {
|
||||||
|
@ -2115,6 +2203,7 @@ public:
|
||||||
"AudioPipelineListener"))
|
"AudioPipelineListener"))
|
||||||
, mLastLog(0)
|
, mLastLog(0)
|
||||||
{
|
{
|
||||||
|
AddTrackToSource(mRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement MediaStreamListener
|
// Implement MediaStreamListener
|
||||||
|
@ -2146,10 +2235,13 @@ private:
|
||||||
void NotifyPullImpl(StreamTime aDesiredTime)
|
void NotifyPullImpl(StreamTime aDesiredTime)
|
||||||
{
|
{
|
||||||
uint32_t samplesPer10ms = mRate / 100;
|
uint32_t samplesPer10ms = mRate / 100;
|
||||||
// Determine how many frames we need.
|
|
||||||
// As we get frames from conduit_ at the same rate as the graph's rate,
|
// mSource's rate is not necessarily the same as the graph rate, since there
|
||||||
// the number of frames needed straightfully determined.
|
// are sample-rate constraints on the inbound audio: only 16, 32, 44.1 and
|
||||||
TrackTicks framesNeeded = aDesiredTime - mPlayedTicks;
|
// 48kHz are supported. The audio frames we get here is going to be
|
||||||
|
// resampled when inserted into the graph.
|
||||||
|
TrackTicks desired = mSource->TimeToTicksRoundUp(mRate, aDesiredTime);
|
||||||
|
TrackTicks framesNeeded = desired - mPlayedTicks;
|
||||||
|
|
||||||
while (framesNeeded >= 0) {
|
while (framesNeeded >= 0) {
|
||||||
const int scratchBufferLength =
|
const int scratchBufferLength =
|
||||||
|
@ -2313,6 +2405,7 @@ public:
|
||||||
LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS))
|
LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS))
|
||||||
, mMutex("Video PipelineListener")
|
, mMutex("Video PipelineListener")
|
||||||
{
|
{
|
||||||
|
AddTrackToSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement MediaStreamListener
|
// Implement MediaStreamListener
|
||||||
|
|
|
@ -2312,7 +2312,7 @@ DataChannelConnection::ReceiveCallback(struct socket* sock, void *data, size_t d
|
||||||
ASSERT_WEBRTC(!NS_IsMainThread());
|
ASSERT_WEBRTC(!NS_IsMainThread());
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
usrsctp_close(sock); // SCTP has finished shutting down
|
LOG(("ReceiveCallback: SCTP has finished shutting down"));
|
||||||
} else {
|
} else {
|
||||||
mLock.AssertCurrentThreadOwns();
|
mLock.AssertCurrentThreadOwns();
|
||||||
if (flags & MSG_NOTIFICATION) {
|
if (flags & MSG_NOTIFICATION) {
|
||||||
|
|
|
@ -1163,4 +1163,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
||||||
|
|
||||||
static const int32_t kUnknownId = -1;
|
static const int32_t kUnknownId = -1;
|
||||||
|
|
||||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1529957232408000);
|
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1530043637929000);
|
||||||
|
|
|
@ -1015,6 +1015,23 @@ LoadLoadableRootsTask::Dispatch()
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
LoadLoadableRootsTask::Run()
|
LoadLoadableRootsTask::Run()
|
||||||
{
|
{
|
||||||
|
// First we Run() on the "LoadRoots" thread, do our work, and then we Run()
|
||||||
|
// again on the main thread so we can shut down the thread (since we don't
|
||||||
|
// need it any more). We can't shut down the thread while we're *on* the
|
||||||
|
// thread, which is why we do the dispatch to the main thread. CryptoTask.cpp
|
||||||
|
// (which informs this code) says that we can't null out mThread. This appears
|
||||||
|
// to be because its refcount could be decreased while this dispatch is being
|
||||||
|
// processed, so it might get prematurely destroyed. I'm not sure this makes
|
||||||
|
// sense but it'll get cleaned up in our destructor anyway, so it's fine to
|
||||||
|
// not null it out here (as long as we don't run twice on the main thread,
|
||||||
|
// which shouldn't be possible).
|
||||||
|
if (NS_IsMainThread()) {
|
||||||
|
if (mThread) {
|
||||||
|
mThread->Shutdown();
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = LoadLoadableRoots();
|
nsresult rv = LoadLoadableRoots();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("LoadLoadableRoots failed"));
|
MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("LoadLoadableRoots failed"));
|
||||||
|
@ -1042,7 +1059,9 @@ LoadLoadableRootsTask::Run()
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NS_OK;
|
|
||||||
|
// Go back to the main thread to clean up this worker thread.
|
||||||
|
return NS_DispatchToMainThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,7 @@
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
const PRTime gPreloadListExpirationTime = INT64_C(1532462824852000);
|
||||||
%%
|
%%
|
||||||
0-1.party, 1
|
0-1.party, 1
|
||||||
0.me.uk, 1
|
0.me.uk, 1
|
||||||
|
@ -152,7 +152,6 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
0xabe.io, 1
|
0xabe.io, 1
|
||||||
0xacab.org, 1
|
0xacab.org, 1
|
||||||
0xda.de, 1
|
0xda.de, 1
|
||||||
0xdc.io, 0
|
|
||||||
0xdefaced.de, 1
|
0xdefaced.de, 1
|
||||||
0xee.eu, 1
|
0xee.eu, 1
|
||||||
0xf00.ch, 1
|
0xf00.ch, 1
|
||||||
|
@ -232,6 +231,7 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
130978.com, 1
|
130978.com, 1
|
||||||
132kv.ch, 1
|
132kv.ch, 1
|
||||||
13318522.com, 1
|
13318522.com, 1
|
||||||
|
1359826938.rsc.cdn77.org, 1
|
||||||
135vv.com, 1
|
135vv.com, 1
|
||||||
13826145000.com, 1
|
13826145000.com, 1
|
||||||
1391kj.com, 1
|
1391kj.com, 1
|
||||||
|
@ -275,6 +275,7 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
1600esplanade.com, 1
|
1600esplanade.com, 1
|
||||||
160887.com, 1
|
160887.com, 1
|
||||||
16164f.com, 1
|
16164f.com, 1
|
||||||
|
1644091933.rsc.cdn77.org, 1
|
||||||
1661237.com, 1
|
1661237.com, 1
|
||||||
166166.com, 1
|
166166.com, 1
|
||||||
168bet9.com, 1
|
168bet9.com, 1
|
||||||
|
@ -293,7 +294,6 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
1888zr.com, 1
|
1888zr.com, 1
|
||||||
188da.com, 1
|
188da.com, 1
|
||||||
188dv.com, 1
|
188dv.com, 1
|
||||||
189dv.com, 1
|
|
||||||
18celebration.com, 1
|
18celebration.com, 1
|
||||||
18celebration.org, 1
|
18celebration.org, 1
|
||||||
18f.gov, 1
|
18f.gov, 1
|
||||||
|
@ -557,6 +557,7 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
394922.com, 1
|
394922.com, 1
|
||||||
396422.com, 1
|
396422.com, 1
|
||||||
398.info, 1
|
398.info, 1
|
||||||
|
3ags.de, 1
|
||||||
3bakayottu.com, 1
|
3bakayottu.com, 1
|
||||||
3bigking.com, 1
|
3bigking.com, 1
|
||||||
3c-d.de, 1
|
3c-d.de, 1
|
||||||
|
@ -830,7 +831,6 @@ const PRTime gPreloadListExpirationTime = INT64_C(1532376418718000);
|
||||||
645722.com, 1
|
645722.com, 1
|
||||||
645822.com, 1
|
645822.com, 1
|
||||||
645922.com, 1
|
645922.com, 1
|
||||||
645ds.cn, 1
|
|
||||||
646.io, 0
|
646.io, 0
|
||||||
646022.com, 1
|
646022.com, 1
|
||||||
646322.com, 1
|
646322.com, 1
|
||||||
|
@ -1222,6 +1222,7 @@ ac.milan.it, 1
|
||||||
ac0g.dyndns.org, 1
|
ac0g.dyndns.org, 1
|
||||||
academicexperts.us, 1
|
academicexperts.us, 1
|
||||||
academie-de-police.ch, 1
|
academie-de-police.ch, 1
|
||||||
|
academy4.net, 1
|
||||||
academytv.com.au, 1
|
academytv.com.au, 1
|
||||||
acaeum.com, 1
|
acaeum.com, 1
|
||||||
acampar.com.br, 1
|
acampar.com.br, 1
|
||||||
|
@ -1667,7 +1668,6 @@ ahmadly.com, 1
|
||||||
ahmedabadflowermall.com, 1
|
ahmedabadflowermall.com, 1
|
||||||
ahmedcharles.com, 1
|
ahmedcharles.com, 1
|
||||||
ahmerjamilkhan.org, 1
|
ahmerjamilkhan.org, 1
|
||||||
aholic.co, 1
|
|
||||||
ahoy.travel, 1
|
ahoy.travel, 1
|
||||||
ahoyconference.com, 1
|
ahoyconference.com, 1
|
||||||
ahrq.gov, 0
|
ahrq.gov, 0
|
||||||
|
@ -2189,10 +2189,10 @@ amello.de, 1
|
||||||
america.gov, 1
|
america.gov, 1
|
||||||
americafamilylawcenter.org, 1
|
americafamilylawcenter.org, 1
|
||||||
american.dating, 1
|
american.dating, 1
|
||||||
americanbio.com, 1
|
|
||||||
americandistribuidora.com, 1
|
americandistribuidora.com, 1
|
||||||
americanfoundationbr.com, 1
|
americanfoundationbr.com, 1
|
||||||
americanmediainstitute.com, 1
|
americanmediainstitute.com, 1
|
||||||
|
americanoutlawjeepparts.com, 1
|
||||||
americasbasementcontractor.com, 1
|
americasbasementcontractor.com, 1
|
||||||
americkykongres.cz, 1
|
americkykongres.cz, 1
|
||||||
amerigroup.com, 1
|
amerigroup.com, 1
|
||||||
|
@ -2370,7 +2370,6 @@ anduril.de, 1
|
||||||
anduril.eu, 1
|
anduril.eu, 1
|
||||||
andybrett.com, 1
|
andybrett.com, 1
|
||||||
andycloud.dynu.net, 1
|
andycloud.dynu.net, 1
|
||||||
andycraftz.eu, 1
|
|
||||||
andycrockett.io, 1
|
andycrockett.io, 1
|
||||||
andymoore.info, 1
|
andymoore.info, 1
|
||||||
andys-place.co.uk, 1
|
andys-place.co.uk, 1
|
||||||
|
@ -2877,6 +2876,7 @@ arnor.org, 1
|
||||||
arnoudraeven.nl, 1
|
arnoudraeven.nl, 1
|
||||||
arnoudvandalen.nl, 1
|
arnoudvandalen.nl, 1
|
||||||
arocloud.de, 0
|
arocloud.de, 0
|
||||||
|
arod.tk, 1
|
||||||
arokha.com, 1
|
arokha.com, 1
|
||||||
aromacos.ch, 1
|
aromacos.ch, 1
|
||||||
aroonchande.com, 1
|
aroonchande.com, 1
|
||||||
|
@ -3878,6 +3878,7 @@ baugeldspezi.de, 1
|
||||||
baugemeinschaftbernstein.de, 1
|
baugemeinschaftbernstein.de, 1
|
||||||
baumannfabrice.com, 1
|
baumannfabrice.com, 1
|
||||||
bausep.de, 1
|
bausep.de, 1
|
||||||
|
baustils.com, 1
|
||||||
bauthier-occasions.be, 1
|
bauthier-occasions.be, 1
|
||||||
bautied.de, 1
|
bautied.de, 1
|
||||||
bauunternehmen-herr.de, 1
|
bauunternehmen-herr.de, 1
|
||||||
|
@ -5132,7 +5133,6 @@ botlab.ch, 1
|
||||||
botmanager.pl, 1
|
botmanager.pl, 1
|
||||||
botserver.de, 1
|
botserver.de, 1
|
||||||
bottaerisposta.net, 1
|
bottaerisposta.net, 1
|
||||||
bottineauneighborhood.org, 1
|
|
||||||
bottke.berlin, 1
|
bottke.berlin, 1
|
||||||
bou.lt, 1
|
bou.lt, 1
|
||||||
bouah.net, 1
|
bouah.net, 1
|
||||||
|
@ -6024,7 +6024,7 @@ canadiantouristboard.com, 1
|
||||||
canalsidehouse.be, 1
|
canalsidehouse.be, 1
|
||||||
canalsidehouse.com, 1
|
canalsidehouse.com, 1
|
||||||
canarianlegalalliance.com, 1
|
canarianlegalalliance.com, 1
|
||||||
canarymod.net, 0
|
canarymod.net, 1
|
||||||
cancelmyprofile.com, 1
|
cancelmyprofile.com, 1
|
||||||
cancerdata.nhs.uk, 1
|
cancerdata.nhs.uk, 1
|
||||||
candicecity.com, 1
|
candicecity.com, 1
|
||||||
|
@ -6424,6 +6424,7 @@ centos.pub, 1
|
||||||
centos.tips, 1
|
centos.tips, 1
|
||||||
central4.me, 1
|
central4.me, 1
|
||||||
centralbank.ae, 1
|
centralbank.ae, 1
|
||||||
|
centralcountiesservices.org, 1
|
||||||
centralebigmat.eu, 1
|
centralebigmat.eu, 1
|
||||||
centralegedimat.eu, 1
|
centralegedimat.eu, 1
|
||||||
centralfor.me, 1
|
centralfor.me, 1
|
||||||
|
@ -7074,7 +7075,6 @@ clairescastles.co.uk, 1
|
||||||
clanebouncycastles.com, 1
|
clanebouncycastles.com, 1
|
||||||
clanrose.org.uk, 1
|
clanrose.org.uk, 1
|
||||||
clanthor.com, 1
|
clanthor.com, 1
|
||||||
clanwarz.com, 1
|
|
||||||
clapping-rhymes.com, 1
|
clapping-rhymes.com, 1
|
||||||
claretandbanter.uk, 1
|
claretandbanter.uk, 1
|
||||||
claritysrv.com, 1
|
claritysrv.com, 1
|
||||||
|
@ -7566,6 +7566,7 @@ common.io, 1
|
||||||
commoncode.com.au, 1
|
commoncode.com.au, 1
|
||||||
commoncode.io, 1
|
commoncode.io, 1
|
||||||
commoncore4kids.com, 1
|
commoncore4kids.com, 1
|
||||||
|
community-cupboard.org, 1
|
||||||
communityblog.fedoraproject.org, 1
|
communityblog.fedoraproject.org, 1
|
||||||
communitycodeofconduct.com, 1
|
communitycodeofconduct.com, 1
|
||||||
communityflow.info, 1
|
communityflow.info, 1
|
||||||
|
@ -7698,7 +7699,6 @@ consciousbrand.co, 1
|
||||||
consciouschoices.net, 1
|
consciouschoices.net, 1
|
||||||
consec-systems.de, 1
|
consec-systems.de, 1
|
||||||
conseil-gli.fr, 1
|
conseil-gli.fr, 1
|
||||||
consejosdehogar.com, 1
|
|
||||||
consejosdenutricion.com, 1
|
consejosdenutricion.com, 1
|
||||||
conservados.com.br, 1
|
conservados.com.br, 1
|
||||||
conservatoriesincornwall.com, 1
|
conservatoriesincornwall.com, 1
|
||||||
|
@ -7785,12 +7785,10 @@ coole-fete.de, 1
|
||||||
coolerssr.space, 1
|
coolerssr.space, 1
|
||||||
coolgifs.de, 1
|
coolgifs.de, 1
|
||||||
cooljs.me, 1
|
cooljs.me, 1
|
||||||
coolkidsbouncycastles.co.uk, 1
|
|
||||||
coolpickz.com, 1
|
coolpickz.com, 1
|
||||||
coolprylar.se, 1
|
coolprylar.se, 1
|
||||||
coolrc.me, 1
|
coolrc.me, 1
|
||||||
coolviewthermostat.com, 1
|
coolviewthermostat.com, 1
|
||||||
coolvox.com, 1
|
|
||||||
coopens.com, 1
|
coopens.com, 1
|
||||||
coore.jp, 1
|
coore.jp, 1
|
||||||
coorpacademy.com, 1
|
coorpacademy.com, 1
|
||||||
|
@ -8247,10 +8245,11 @@ ctyi.me, 1
|
||||||
cub-bouncingcastles.co.uk, 1
|
cub-bouncingcastles.co.uk, 1
|
||||||
cube-cloud.com, 1
|
cube-cloud.com, 1
|
||||||
cube.de, 1
|
cube.de, 1
|
||||||
|
cubecart-demo.co.uk, 1
|
||||||
|
cubecart-hosting.co.uk, 1
|
||||||
cubecraft.net, 1
|
cubecraft.net, 1
|
||||||
cubecraftstore.com, 1
|
cubecraftstore.com, 1
|
||||||
cubecraftstore.net, 1
|
cubecraftstore.net, 1
|
||||||
cubekrowd.net, 1
|
|
||||||
cubela.tech, 1
|
cubela.tech, 1
|
||||||
cubia.de, 1
|
cubia.de, 1
|
||||||
cubia3.com, 1
|
cubia3.com, 1
|
||||||
|
@ -8277,7 +8276,6 @@ cultofperf.org.uk, 1
|
||||||
culture-school.top, 1
|
culture-school.top, 1
|
||||||
culturedcode.com, 1
|
culturedcode.com, 1
|
||||||
cultureroll.com, 1
|
cultureroll.com, 1
|
||||||
cumparama.com, 1
|
|
||||||
cumplegenial.com, 1
|
cumplegenial.com, 1
|
||||||
cunha.be, 1
|
cunha.be, 1
|
||||||
cuni-cuni-club.com, 1
|
cuni-cuni-club.com, 1
|
||||||
|
@ -8671,6 +8669,7 @@ darkside.re, 1
|
||||||
darktime.ru, 1
|
darktime.ru, 1
|
||||||
darkwater.info, 1
|
darkwater.info, 1
|
||||||
darkx.me, 1
|
darkx.me, 1
|
||||||
|
darlastudio66.com, 1
|
||||||
darlo.co.uk, 0
|
darlo.co.uk, 0
|
||||||
darom.jp, 1
|
darom.jp, 1
|
||||||
darookee.net, 1
|
darookee.net, 1
|
||||||
|
@ -9282,6 +9281,7 @@ devzero.io, 1
|
||||||
dewaard.de, 1
|
dewaard.de, 1
|
||||||
dewalch.net, 1
|
dewalch.net, 1
|
||||||
dewapress.com, 1
|
dewapress.com, 1
|
||||||
|
dewebwerf.nl, 1
|
||||||
dewinter.com, 1
|
dewinter.com, 1
|
||||||
dexalo.de, 1
|
dexalo.de, 1
|
||||||
dezeregio.nl, 1
|
dezeregio.nl, 1
|
||||||
|
@ -9302,7 +9302,6 @@ dgblaw.com.au, 1
|
||||||
dgbouncycastlehire.com, 1
|
dgbouncycastlehire.com, 1
|
||||||
dgby.org, 1
|
dgby.org, 1
|
||||||
dgeex.eu, 1
|
dgeex.eu, 1
|
||||||
dggm.ru, 1
|
|
||||||
dggwp.de, 1
|
dggwp.de, 1
|
||||||
dgitup.com, 1
|
dgitup.com, 1
|
||||||
dgportals.co.uk, 1
|
dgportals.co.uk, 1
|
||||||
|
@ -9550,6 +9549,7 @@ discha.net, 1
|
||||||
dischempharmacie.com, 1
|
dischempharmacie.com, 1
|
||||||
disciples.io, 1
|
disciples.io, 1
|
||||||
discipul.nl, 1
|
discipul.nl, 1
|
||||||
|
disclosure.io, 1
|
||||||
disco-crazy-world.de, 1
|
disco-crazy-world.de, 1
|
||||||
discofitta.com, 1
|
discofitta.com, 1
|
||||||
disconformity.net, 1
|
disconformity.net, 1
|
||||||
|
@ -9710,6 +9710,7 @@ dnplegal.com, 1
|
||||||
dns-control.eu, 1
|
dns-control.eu, 1
|
||||||
dns-manager.info, 1
|
dns-manager.info, 1
|
||||||
dns.google.com, 1
|
dns.google.com, 1
|
||||||
|
dns8.online, 1
|
||||||
dnsbird.org, 1
|
dnsbird.org, 1
|
||||||
dnscrawler.com, 1
|
dnscrawler.com, 1
|
||||||
dnscurve.io, 1
|
dnscurve.io, 1
|
||||||
|
@ -10268,6 +10269,7 @@ dustygroove.com, 1
|
||||||
dustyspokesbnb.ca, 1
|
dustyspokesbnb.ca, 1
|
||||||
dutch.desi, 1
|
dutch.desi, 1
|
||||||
dutch1.nl, 1
|
dutch1.nl, 1
|
||||||
|
dutchessuganda.com, 1
|
||||||
dutchrank.nl, 1
|
dutchrank.nl, 1
|
||||||
dutchwanderers.nl, 1
|
dutchwanderers.nl, 1
|
||||||
dutchweballiance.nl, 1
|
dutchweballiance.nl, 1
|
||||||
|
@ -10333,7 +10335,6 @@ dzomo.org, 1
|
||||||
dzsibi.com, 1
|
dzsibi.com, 1
|
||||||
dzsula.hu, 1
|
dzsula.hu, 1
|
||||||
dzyabchenko.com, 1
|
dzyabchenko.com, 1
|
||||||
dzytdl.com, 1
|
|
||||||
e-apack.com.br, 1
|
e-apack.com.br, 1
|
||||||
e-baraxolka.ru, 1
|
e-baraxolka.ru, 1
|
||||||
e-biografias.net, 1
|
e-biografias.net, 1
|
||||||
|
@ -10852,7 +10853,6 @@ elexprimidor.com, 1
|
||||||
elfe.de, 1
|
elfe.de, 1
|
||||||
elgosblanc.com, 0
|
elgosblanc.com, 0
|
||||||
elguadia.faith, 1
|
elguadia.faith, 1
|
||||||
elguillatun.cl, 1
|
|
||||||
elhall.pro, 1
|
elhall.pro, 1
|
||||||
elhall.ru, 1
|
elhall.ru, 1
|
||||||
elhamadimi.com, 1
|
elhamadimi.com, 1
|
||||||
|
@ -11558,6 +11558,7 @@ estcequejailaflemme.fr, 1
|
||||||
estcequonmetenprodaujourdhui.info, 1
|
estcequonmetenprodaujourdhui.info, 1
|
||||||
esteam.se, 1
|
esteam.se, 1
|
||||||
estedafah.com, 1
|
estedafah.com, 1
|
||||||
|
estespr.com, 1
|
||||||
esteticanorte.com.br, 1
|
esteticanorte.com.br, 1
|
||||||
estetista.net, 1
|
estetista.net, 1
|
||||||
estilopack-loja.com.br, 1
|
estilopack-loja.com.br, 1
|
||||||
|
@ -11824,7 +11825,6 @@ exebouncycastles.co.uk, 1
|
||||||
exehack.net, 1
|
exehack.net, 1
|
||||||
exeintel.com, 1
|
exeintel.com, 1
|
||||||
exekutori.com, 1
|
exekutori.com, 1
|
||||||
exembit.com, 1
|
|
||||||
exemples-de-stands.com, 1
|
exemples-de-stands.com, 1
|
||||||
exeria.de, 1
|
exeria.de, 1
|
||||||
exgaywatch.com, 1
|
exgaywatch.com, 1
|
||||||
|
@ -11993,7 +11993,6 @@ facepunch.org, 1
|
||||||
facerepo.com, 1
|
facerepo.com, 1
|
||||||
facesnf.com, 1
|
facesnf.com, 1
|
||||||
fach-journalist.de, 1
|
fach-journalist.de, 1
|
||||||
fachschaft-informatik.de, 1
|
|
||||||
fachschaftslisten.at, 1
|
fachschaftslisten.at, 1
|
||||||
fachschaftslisten.org, 1
|
fachschaftslisten.org, 1
|
||||||
facialexercising.com, 1
|
facialexercising.com, 1
|
||||||
|
@ -12092,7 +12091,6 @@ famoushostels.com, 1
|
||||||
famvangelder.nl, 1
|
famvangelder.nl, 1
|
||||||
famvsomeren.nl, 1
|
famvsomeren.nl, 1
|
||||||
fan.gov, 1
|
fan.gov, 1
|
||||||
fanboi.ch, 1
|
|
||||||
fancy-bridge.com, 1
|
fancy-bridge.com, 1
|
||||||
fander.it, 1
|
fander.it, 1
|
||||||
fandler.cz, 1
|
fandler.cz, 1
|
||||||
|
@ -12556,7 +12554,6 @@ fistu.la, 1
|
||||||
fit-4u.ch, 1
|
fit-4u.ch, 1
|
||||||
fit365.jp, 1
|
fit365.jp, 1
|
||||||
fitchannel.com, 1
|
fitchannel.com, 1
|
||||||
fitfitup.com, 1
|
|
||||||
fitkram.cz, 1
|
fitkram.cz, 1
|
||||||
fitness-challenge.co.uk, 1
|
fitness-challenge.co.uk, 1
|
||||||
fitness.gov, 1
|
fitness.gov, 1
|
||||||
|
@ -12782,7 +12779,6 @@ fol.tf, 1
|
||||||
foljeton.dk, 1
|
foljeton.dk, 1
|
||||||
folkadelic.de, 1
|
folkadelic.de, 1
|
||||||
folkfests.org, 1
|
folkfests.org, 1
|
||||||
follandviolins.com, 1
|
|
||||||
followerrocket.com, 1
|
followerrocket.com, 1
|
||||||
followersya.com, 1
|
followersya.com, 1
|
||||||
followthatpage.com, 1
|
followthatpage.com, 1
|
||||||
|
@ -13991,7 +13987,6 @@ gillyscastles.co.uk, 1
|
||||||
gilmoreid.com.au, 1
|
gilmoreid.com.au, 1
|
||||||
gilnet.be, 1
|
gilnet.be, 1
|
||||||
gina-architektur.design, 1
|
gina-architektur.design, 1
|
||||||
ginie.de, 1
|
|
||||||
ginionusedcars.be, 1
|
ginionusedcars.be, 1
|
||||||
ginja.co.th, 1
|
ginja.co.th, 1
|
||||||
ginkel.com, 1
|
ginkel.com, 1
|
||||||
|
@ -14215,6 +14210,7 @@ gokhankesici.com, 1
|
||||||
gokmenguresci.com, 1
|
gokmenguresci.com, 1
|
||||||
gold24.ru, 1
|
gold24.ru, 1
|
||||||
goldclubcasino.com, 1
|
goldclubcasino.com, 1
|
||||||
|
goldcoasthypnotherapyhypnosis.com.au, 1
|
||||||
goldcoaststumpbusters.com, 1
|
goldcoaststumpbusters.com, 1
|
||||||
goldenbadger.de, 1
|
goldenbadger.de, 1
|
||||||
goldendawnapersonalaffair.com, 1
|
goldendawnapersonalaffair.com, 1
|
||||||
|
@ -14760,7 +14756,6 @@ habarisoft.com, 1
|
||||||
habbixed.tk, 1
|
habbixed.tk, 1
|
||||||
habbos.es, 1
|
habbos.es, 1
|
||||||
habeo.si, 1
|
habeo.si, 1
|
||||||
habitat-domotique.fr, 1
|
|
||||||
habtium.com, 1
|
habtium.com, 1
|
||||||
habtium.es, 1
|
habtium.es, 1
|
||||||
habview.net, 1
|
habview.net, 1
|
||||||
|
@ -14800,7 +14795,7 @@ hackerpoints.com, 1
|
||||||
hackerschat.net, 1
|
hackerschat.net, 1
|
||||||
hackerstxt.org, 1
|
hackerstxt.org, 1
|
||||||
hackgins.com, 1
|
hackgins.com, 1
|
||||||
hackingand.coffee, 1
|
hackingand.coffee, 0
|
||||||
hackingdh.com, 1
|
hackingdh.com, 1
|
||||||
hackingsafe.com, 1
|
hackingsafe.com, 1
|
||||||
hackmd.io, 1
|
hackmd.io, 1
|
||||||
|
@ -15460,7 +15455,6 @@ himekomi.com, 1
|
||||||
himens.com, 1
|
himens.com, 1
|
||||||
hingle.me, 1
|
hingle.me, 1
|
||||||
hinrich.de, 1
|
hinrich.de, 1
|
||||||
hintergrundbewegung.de, 1
|
|
||||||
hinterhofbu.de, 1
|
hinterhofbu.de, 1
|
||||||
hintermeier-rae.at, 1
|
hintermeier-rae.at, 1
|
||||||
hinterposemuckel.de, 1
|
hinterposemuckel.de, 1
|
||||||
|
@ -15603,6 +15597,7 @@ holidaysportugal.eu, 1
|
||||||
holisticacupuncture.com.au, 1
|
holisticacupuncture.com.au, 1
|
||||||
holistichealer.in, 1
|
holistichealer.in, 1
|
||||||
holisticon.de, 1
|
holisticon.de, 1
|
||||||
|
hollandguns.com, 1
|
||||||
hollermann.eu, 1
|
hollermann.eu, 1
|
||||||
hollo.me, 1
|
hollo.me, 1
|
||||||
hollowrap.com, 1
|
hollowrap.com, 1
|
||||||
|
@ -15689,7 +15684,6 @@ hookbin.com, 1
|
||||||
hooowl.com, 1
|
hooowl.com, 1
|
||||||
hoopertechnicalsolutions.com, 1
|
hoopertechnicalsolutions.com, 1
|
||||||
hooray.beer, 1
|
hooray.beer, 1
|
||||||
hoorr.com, 1
|
|
||||||
hootworld.net, 1
|
hootworld.net, 1
|
||||||
hoowhen.cn, 1
|
hoowhen.cn, 1
|
||||||
hopconseils.ch, 1
|
hopconseils.ch, 1
|
||||||
|
@ -16001,6 +15995,7 @@ huskyinc.us, 1
|
||||||
hussam.eu.org, 1
|
hussam.eu.org, 1
|
||||||
hustle.com, 1
|
hustle.com, 1
|
||||||
hustle.life, 1
|
hustle.life, 1
|
||||||
|
hustlehope.com, 1
|
||||||
hustunique.com, 1
|
hustunique.com, 1
|
||||||
huto.ml, 1
|
huto.ml, 1
|
||||||
huutonauru.net, 1
|
huutonauru.net, 1
|
||||||
|
@ -16390,7 +16385,6 @@ iltisim.ch, 1
|
||||||
ilweb.es, 1
|
ilweb.es, 1
|
||||||
ilya.pp.ua, 1
|
ilya.pp.ua, 1
|
||||||
im-c-shop.com, 1
|
im-c-shop.com, 1
|
||||||
im-design.com.ua, 1
|
|
||||||
im2net.com, 1
|
im2net.com, 1
|
||||||
im66.net, 0
|
im66.net, 0
|
||||||
ima-tourcoing.fr, 1
|
ima-tourcoing.fr, 1
|
||||||
|
@ -16413,7 +16407,6 @@ imanesdeviaje.com, 1
|
||||||
imanolbarba.net, 1
|
imanolbarba.net, 1
|
||||||
imanudin.net, 1
|
imanudin.net, 1
|
||||||
imarkethost.co.uk, 1
|
imarkethost.co.uk, 1
|
||||||
imask.ml, 1
|
|
||||||
imawhale.com, 1
|
imawhale.com, 1
|
||||||
imbianchino.roma.it, 1
|
imbianchino.roma.it, 1
|
||||||
imbrian.org, 1
|
imbrian.org, 1
|
||||||
|
@ -16558,6 +16551,7 @@ indianaberry.com, 1
|
||||||
indianaffairs.gov, 0
|
indianaffairs.gov, 0
|
||||||
indiawise.co.uk, 1
|
indiawise.co.uk, 1
|
||||||
indicateurs-flash.fr, 1
|
indicateurs-flash.fr, 1
|
||||||
|
indieethos.com, 1
|
||||||
indiegame.space, 1
|
indiegame.space, 1
|
||||||
indievelopment.nl, 1
|
indievelopment.nl, 1
|
||||||
indigoinflatables.com, 1
|
indigoinflatables.com, 1
|
||||||
|
@ -16873,6 +16867,7 @@ intmissioncenter.org, 1
|
||||||
into.technology, 1
|
into.technology, 1
|
||||||
inton.biz, 1
|
inton.biz, 1
|
||||||
intoparking.com, 0
|
intoparking.com, 0
|
||||||
|
intpforum.com, 1
|
||||||
intracom.com, 1
|
intracom.com, 1
|
||||||
intradayseasonals.com, 1
|
intradayseasonals.com, 1
|
||||||
intranetsec-regionra.fr, 1
|
intranetsec-regionra.fr, 1
|
||||||
|
@ -16906,7 +16901,6 @@ investigazionimoretti.it, 1
|
||||||
investingdiary.cn, 1
|
investingdiary.cn, 1
|
||||||
investingtrader.net, 1
|
investingtrader.net, 1
|
||||||
investir.ch, 1
|
investir.ch, 1
|
||||||
investor.gov, 1
|
|
||||||
investoren-beteiligung.de, 1
|
investoren-beteiligung.de, 1
|
||||||
investorforms.com, 1
|
investorforms.com, 1
|
||||||
investorloanshub.com, 1
|
investorloanshub.com, 1
|
||||||
|
@ -17087,6 +17081,7 @@ iskogen.nu, 1
|
||||||
islam.si, 1
|
islam.si, 1
|
||||||
islandhosting.com, 1
|
islandhosting.com, 1
|
||||||
islandinthenet.com, 1
|
islandinthenet.com, 1
|
||||||
|
islandpumpandtank.com, 1
|
||||||
islazia.fr, 1
|
islazia.fr, 1
|
||||||
isletech.net, 1
|
isletech.net, 1
|
||||||
isliada.org, 1
|
isliada.org, 1
|
||||||
|
@ -17511,7 +17506,6 @@ javamilk.com, 1
|
||||||
javascriptlab.fr, 1
|
javascriptlab.fr, 1
|
||||||
javfree.me, 1
|
javfree.me, 1
|
||||||
jawn.ca, 1
|
jawn.ca, 1
|
||||||
jawnelodzkie.org.pl, 1
|
|
||||||
jaxageto.de, 1
|
jaxageto.de, 1
|
||||||
jaycouture.com, 1
|
jaycouture.com, 1
|
||||||
jayf.de, 1
|
jayf.de, 1
|
||||||
|
@ -17653,7 +17647,6 @@ jessekaufman.com, 1
|
||||||
jessesjumpingcastles.co.uk, 1
|
jessesjumpingcastles.co.uk, 1
|
||||||
jessevictors.com, 1
|
jessevictors.com, 1
|
||||||
jessgranger.com, 1
|
jessgranger.com, 1
|
||||||
jessicabenedictus.nl, 0
|
|
||||||
jesters-court.net, 1
|
jesters-court.net, 1
|
||||||
jesuisadmin.fr, 1
|
jesuisadmin.fr, 1
|
||||||
jet-stream.fr, 1
|
jet-stream.fr, 1
|
||||||
|
@ -17832,7 +17825,6 @@ joellombardo.com, 1
|
||||||
joelmarkhamphotography.com.au, 1
|
joelmarkhamphotography.com.au, 1
|
||||||
joelmunch.com, 1
|
joelmunch.com, 1
|
||||||
joepitt.co.uk, 0
|
joepitt.co.uk, 0
|
||||||
joerg-wellpott.de, 1
|
|
||||||
joerss.at, 1
|
joerss.at, 1
|
||||||
joeskup.com, 1
|
joeskup.com, 1
|
||||||
joespaintingpgh.com, 1
|
joespaintingpgh.com, 1
|
||||||
|
@ -19056,6 +19048,7 @@ korea.dating, 1
|
||||||
koreaboo.com, 1
|
koreaboo.com, 1
|
||||||
koretech.nl, 1
|
koretech.nl, 1
|
||||||
korinar.com, 1
|
korinar.com, 1
|
||||||
|
korni22.org, 0
|
||||||
korobi.io, 1
|
korobi.io, 1
|
||||||
korobkovsky.ru, 1
|
korobkovsky.ru, 1
|
||||||
korono.de, 1
|
korono.de, 1
|
||||||
|
@ -19229,7 +19222,7 @@ kuchenschock.de, 1
|
||||||
kuchentraum.eu, 1
|
kuchentraum.eu, 1
|
||||||
kucheryavenkovn.ru, 1
|
kucheryavenkovn.ru, 1
|
||||||
kucnibudzet.com, 1
|
kucnibudzet.com, 1
|
||||||
kudo.co.id, 0
|
kudo.co.id, 1
|
||||||
kueche-co.de, 1
|
kueche-co.de, 1
|
||||||
kuechenprofi-group.de, 1
|
kuechenprofi-group.de, 1
|
||||||
kuehndel.org, 1
|
kuehndel.org, 1
|
||||||
|
@ -19396,6 +19389,7 @@ lacledelareussite.com, 1
|
||||||
lacledeslan.com, 0
|
lacledeslan.com, 0
|
||||||
lacledor.ch, 1
|
lacledor.ch, 1
|
||||||
laclefdor.ch, 1
|
laclefdor.ch, 1
|
||||||
|
lacliniquefinanciere.com, 1
|
||||||
lacuevadechauvet.com, 1
|
lacuevadechauvet.com, 1
|
||||||
lacyc3.eu, 1
|
lacyc3.eu, 1
|
||||||
ladbroke.net, 1
|
ladbroke.net, 1
|
||||||
|
@ -19874,6 +19868,7 @@ leowkahman.com, 1
|
||||||
lep.gov, 1
|
lep.gov, 1
|
||||||
lepenetapeti.com, 1
|
lepenetapeti.com, 1
|
||||||
lepiquillo.fr, 1
|
lepiquillo.fr, 1
|
||||||
|
leppis-it.de, 1
|
||||||
leprado.com, 1
|
leprado.com, 1
|
||||||
lepsos.com, 1
|
lepsos.com, 1
|
||||||
lereporter.ma, 1
|
lereporter.ma, 1
|
||||||
|
@ -20074,6 +20069,7 @@ liehuojun.com, 1
|
||||||
lietaer.eu, 1
|
lietaer.eu, 1
|
||||||
lieuu.com, 1
|
lieuu.com, 1
|
||||||
lifanov.com, 1
|
lifanov.com, 1
|
||||||
|
lifebetweenlives.com.au, 1
|
||||||
lifecism.com, 1
|
lifecism.com, 1
|
||||||
lifecoach.tw, 0
|
lifecoach.tw, 0
|
||||||
lifeinhex.com, 1
|
lifeinhex.com, 1
|
||||||
|
@ -20434,7 +20430,6 @@ lofttravel.com, 1
|
||||||
log.my, 0
|
log.my, 0
|
||||||
logaldeveloper.com, 1
|
logaldeveloper.com, 1
|
||||||
loganmarchione.com, 1
|
loganmarchione.com, 1
|
||||||
loganparkneighborhood.org, 1
|
|
||||||
logbook.ch, 1
|
logbook.ch, 1
|
||||||
logbot.info, 1
|
logbot.info, 1
|
||||||
logcat.info, 1
|
logcat.info, 1
|
||||||
|
@ -21067,7 +21062,6 @@ maktoob.search.yahoo.com, 0
|
||||||
maku.edu.tr, 1
|
maku.edu.tr, 1
|
||||||
malachiteauth.com, 1
|
malachiteauth.com, 1
|
||||||
malamutedoalasca.com.br, 1
|
malamutedoalasca.com.br, 1
|
||||||
malash.me, 1
|
|
||||||
malasuk.com, 1
|
malasuk.com, 1
|
||||||
malaysia.search.yahoo.com, 0
|
malaysia.search.yahoo.com, 0
|
||||||
malaysian.dating, 1
|
malaysian.dating, 1
|
||||||
|
@ -22865,6 +22859,7 @@ mrkapowski.com, 1
|
||||||
mrketolocksmith.com, 1
|
mrketolocksmith.com, 1
|
||||||
mrknee.gr, 1
|
mrknee.gr, 1
|
||||||
mrksk.com, 1
|
mrksk.com, 1
|
||||||
|
mrleonardo.com, 1
|
||||||
mrliu.me, 1
|
mrliu.me, 1
|
||||||
mrmoregame.de, 1
|
mrmoregame.de, 1
|
||||||
mrnh.de, 1
|
mrnh.de, 1
|
||||||
|
@ -22959,6 +22954,7 @@ mukka.ch, 1
|
||||||
mulaccosmetics.com, 1
|
mulaccosmetics.com, 1
|
||||||
mulaisehat.com, 1
|
mulaisehat.com, 1
|
||||||
mulej.net, 1
|
mulej.net, 1
|
||||||
|
mulenvo.com, 1
|
||||||
mulheres18.com, 1
|
mulheres18.com, 1
|
||||||
muling.lu, 1
|
muling.lu, 1
|
||||||
mullens-usedcars.be, 1
|
mullens-usedcars.be, 1
|
||||||
|
@ -23445,6 +23441,7 @@ nanami.moe, 1
|
||||||
nanarose.ch, 1
|
nanarose.ch, 1
|
||||||
nanch.com, 1
|
nanch.com, 1
|
||||||
nanderson.me, 1
|
nanderson.me, 1
|
||||||
|
nandex.org, 1
|
||||||
nanfangstone.com, 1
|
nanfangstone.com, 1
|
||||||
nani.io, 1
|
nani.io, 1
|
||||||
nankiseamansclub.com, 1
|
nankiseamansclub.com, 1
|
||||||
|
@ -24306,7 +24303,6 @@ northern-lakes.com, 1
|
||||||
northernhamsterclub.com, 1
|
northernhamsterclub.com, 1
|
||||||
northernmuscle.ca, 1
|
northernmuscle.ca, 1
|
||||||
northernselfstorage.co.za, 1
|
northernselfstorage.co.za, 1
|
||||||
northfieldyarn.com, 1
|
|
||||||
northokanaganbookkeeping.com, 1
|
northokanaganbookkeeping.com, 1
|
||||||
northpole.dance, 1
|
northpole.dance, 1
|
||||||
northridgeelectrical.com, 1
|
northridgeelectrical.com, 1
|
||||||
|
@ -24385,6 +24381,7 @@ novelvyretraite.fr, 1
|
||||||
novfishing.ru, 1
|
novfishing.ru, 1
|
||||||
novgorod-avia.ru, 1
|
novgorod-avia.ru, 1
|
||||||
novilaw.com, 1
|
novilaw.com, 1
|
||||||
|
novinivo.com, 1
|
||||||
novojet.cl, 1
|
novojet.cl, 1
|
||||||
novoresume.com, 0
|
novoresume.com, 0
|
||||||
novosibavia.ru, 1
|
novosibavia.ru, 1
|
||||||
|
@ -25344,7 +25341,6 @@ page-builders.com, 1
|
||||||
pageantsnews.com, 0
|
pageantsnews.com, 0
|
||||||
pagedesignhub.com, 1
|
pagedesignhub.com, 1
|
||||||
pagedesignpro.com, 1
|
pagedesignpro.com, 1
|
||||||
pagedesignshop.com, 1
|
|
||||||
pagedesignweb.com, 1
|
pagedesignweb.com, 1
|
||||||
pagefulloflies.io, 1
|
pagefulloflies.io, 1
|
||||||
pages-tocaven.com, 1
|
pages-tocaven.com, 1
|
||||||
|
@ -25539,7 +25535,6 @@ partypearl.de, 1
|
||||||
partyrocksbounce.co.uk, 1
|
partyrocksbounce.co.uk, 1
|
||||||
partyschnaps.com, 1
|
partyschnaps.com, 1
|
||||||
partyspaces.co.uk, 1
|
partyspaces.co.uk, 1
|
||||||
partyspecialists.com, 1
|
|
||||||
partytime-uk.co.uk, 1
|
partytime-uk.co.uk, 1
|
||||||
partytimeltd.ie, 1
|
partytimeltd.ie, 1
|
||||||
partytownireland.co.uk, 1
|
partytownireland.co.uk, 1
|
||||||
|
@ -26349,7 +26344,6 @@ planetau2.com, 1
|
||||||
planetbeauty.com, 1
|
planetbeauty.com, 1
|
||||||
planetbreath.ch, 1
|
planetbreath.ch, 1
|
||||||
planete-cocoon.com, 0
|
planete-cocoon.com, 0
|
||||||
planete-lira.fr, 1
|
|
||||||
planete-secu.com, 1
|
planete-secu.com, 1
|
||||||
planeteroliste.com, 1
|
planeteroliste.com, 1
|
||||||
planeteroliste.fr, 1
|
planeteroliste.fr, 1
|
||||||
|
@ -26464,6 +26458,7 @@ plushev.com, 1
|
||||||
pluslink.co.jp, 1
|
pluslink.co.jp, 1
|
||||||
plussizereviews.com, 1
|
plussizereviews.com, 1
|
||||||
plusstreamfeed.appspot.com, 1
|
plusstreamfeed.appspot.com, 1
|
||||||
|
plustech.id, 1
|
||||||
pluta.net, 1
|
pluta.net, 1
|
||||||
pluto.life, 1
|
pluto.life, 1
|
||||||
plutokorea.com, 1
|
plutokorea.com, 1
|
||||||
|
@ -26721,7 +26716,6 @@ postblue.info, 1
|
||||||
postbox.life, 1
|
postbox.life, 1
|
||||||
postcardpayment.com, 1
|
postcardpayment.com, 1
|
||||||
postcode.nl, 1
|
postcode.nl, 1
|
||||||
postcodegarant.nl, 1
|
|
||||||
postdarwinian.com, 1
|
postdarwinian.com, 1
|
||||||
postdarwinism.com, 1
|
postdarwinism.com, 1
|
||||||
postdeck.de, 1
|
postdeck.de, 1
|
||||||
|
@ -26758,6 +26752,7 @@ pouet.it, 1
|
||||||
pouets.ovh, 1
|
pouets.ovh, 1
|
||||||
poupatempo.org, 1
|
poupatempo.org, 1
|
||||||
pourlesenfants.info, 1
|
pourlesenfants.info, 1
|
||||||
|
pourout.org, 1
|
||||||
povareschka.ru, 1
|
povareschka.ru, 1
|
||||||
povesham.tk, 1
|
povesham.tk, 1
|
||||||
powaclub.com, 1
|
powaclub.com, 1
|
||||||
|
@ -27237,6 +27232,7 @@ psychoco.net, 1
|
||||||
psychotherapie-kp.de, 1
|
psychotherapie-kp.de, 1
|
||||||
psydix.org, 1
|
psydix.org, 1
|
||||||
psyk.yt, 1
|
psyk.yt, 1
|
||||||
|
psylab.re, 1
|
||||||
psylab.vip, 1
|
psylab.vip, 1
|
||||||
psynapse.net.au, 1
|
psynapse.net.au, 1
|
||||||
psytrance-pro.com, 1
|
psytrance-pro.com, 1
|
||||||
|
@ -27482,6 +27478,7 @@ quanwuji.com, 1
|
||||||
quanyin.eu.org, 1
|
quanyin.eu.org, 1
|
||||||
quareal.ru, 1
|
quareal.ru, 1
|
||||||
quarkdose.de, 1
|
quarkdose.de, 1
|
||||||
|
quarryhillrentals.com, 1
|
||||||
quarterfull.com, 1
|
quarterfull.com, 1
|
||||||
quartix.com, 1
|
quartix.com, 1
|
||||||
quartzclinical.com, 1
|
quartzclinical.com, 1
|
||||||
|
@ -27917,10 +27914,12 @@ red-t-shirt.ru, 1
|
||||||
red-trigger.net, 1
|
red-trigger.net, 1
|
||||||
red2fred2.com, 1
|
red2fred2.com, 1
|
||||||
redable.hosting, 1
|
redable.hosting, 1
|
||||||
|
redable.nl, 1
|
||||||
redactieco.nl, 1
|
redactieco.nl, 1
|
||||||
redb.cz, 1
|
redb.cz, 1
|
||||||
redballoonsecurity.com, 1
|
redballoonsecurity.com, 1
|
||||||
redburn.com, 1
|
redburn.com, 1
|
||||||
|
redcomet.org, 1
|
||||||
redcone.net, 1
|
redcone.net, 1
|
||||||
redcorus.com, 1
|
redcorus.com, 1
|
||||||
redd.it, 1
|
redd.it, 1
|
||||||
|
@ -27960,6 +27959,7 @@ redlink.de, 1
|
||||||
redneragenturen.org, 1
|
redneragenturen.org, 1
|
||||||
rednoseday.com, 1
|
rednoseday.com, 1
|
||||||
rednsx.org, 1
|
rednsx.org, 1
|
||||||
|
redperegrine.com, 1
|
||||||
redporno.cz, 1
|
redporno.cz, 1
|
||||||
redprice.by, 1
|
redprice.by, 1
|
||||||
redshield.co, 1
|
redshield.co, 1
|
||||||
|
@ -28672,7 +28672,6 @@ rosewoodranch.com, 1
|
||||||
rosi-royal.com, 1
|
rosi-royal.com, 1
|
||||||
roslynpad.net, 1
|
roslynpad.net, 1
|
||||||
rospa100.com, 1
|
rospa100.com, 1
|
||||||
rossclark.com, 1
|
|
||||||
rosset.me, 1
|
rosset.me, 1
|
||||||
rosset.net, 1
|
rosset.net, 1
|
||||||
rossiworld.com, 1
|
rossiworld.com, 1
|
||||||
|
@ -28828,6 +28827,7 @@ ruhrmobil-e.de, 1
|
||||||
ruhrnalist.de, 1
|
ruhrnalist.de, 1
|
||||||
ruht.ro, 1
|
ruht.ro, 1
|
||||||
ruigomes.me, 1
|
ruigomes.me, 1
|
||||||
|
ruiming.me, 1
|
||||||
ruja.dk, 1
|
ruja.dk, 1
|
||||||
ruk.ca, 1
|
ruk.ca, 1
|
||||||
rukhaiyar.com, 1
|
rukhaiyar.com, 1
|
||||||
|
@ -28835,6 +28835,7 @@ rullzer.com, 1
|
||||||
rulu.co, 1
|
rulu.co, 1
|
||||||
rulu.tv, 1
|
rulu.tv, 1
|
||||||
rulutv.com, 1
|
rulutv.com, 1
|
||||||
|
rumlager.de, 1
|
||||||
rummel-platz.de, 1
|
rummel-platz.de, 1
|
||||||
rumplesinflatables.co.uk, 1
|
rumplesinflatables.co.uk, 1
|
||||||
rumtaste.com, 1
|
rumtaste.com, 1
|
||||||
|
@ -29224,7 +29225,6 @@ saskpension.com, 1
|
||||||
sasrobotics.xyz, 1
|
sasrobotics.xyz, 1
|
||||||
sastd.com, 1
|
sastd.com, 1
|
||||||
sasyabapi.com, 1
|
sasyabapi.com, 1
|
||||||
sat.rent, 1
|
|
||||||
sat4all.com, 1
|
sat4all.com, 1
|
||||||
sat7a-riyadh.com, 1
|
sat7a-riyadh.com, 1
|
||||||
satai.dk, 1
|
satai.dk, 1
|
||||||
|
@ -29234,7 +29234,6 @@ satinn.pl, 1
|
||||||
sativatunja.com, 1
|
sativatunja.com, 1
|
||||||
satmd.de, 1
|
satmd.de, 1
|
||||||
satrent.com, 1
|
satrent.com, 1
|
||||||
satrent.se, 1
|
|
||||||
saturn.pl, 1
|
saturn.pl, 1
|
||||||
saudavel.com.vc, 1
|
saudavel.com.vc, 1
|
||||||
saudeealimentos.com, 1
|
saudeealimentos.com, 1
|
||||||
|
@ -29546,7 +29545,6 @@ scwilliams.uk, 1
|
||||||
sd.af, 1
|
sd.af, 1
|
||||||
sdcardrecovery.de, 1
|
sdcardrecovery.de, 1
|
||||||
sdg-tracker.org, 1
|
sdg-tracker.org, 1
|
||||||
sdho.org, 1
|
|
||||||
sdns.fr, 1
|
sdns.fr, 1
|
||||||
sdsi.us, 1
|
sdsi.us, 1
|
||||||
sdsmanagement.me, 1
|
sdsmanagement.me, 1
|
||||||
|
@ -29797,7 +29795,6 @@ semianalog.com, 1
|
||||||
seminariruum.ee, 1
|
seminariruum.ee, 1
|
||||||
semiocast.com, 1
|
semiocast.com, 1
|
||||||
semjonov.de, 1
|
semjonov.de, 1
|
||||||
semmlers.com, 1
|
|
||||||
semox.de, 1
|
semox.de, 1
|
||||||
semps-2fa.de, 1
|
semps-2fa.de, 1
|
||||||
semps-threema.de, 1
|
semps-threema.de, 1
|
||||||
|
@ -30100,6 +30097,7 @@ shavegazette.com, 1
|
||||||
shavingks.com, 1
|
shavingks.com, 1
|
||||||
shawcentral.ca, 0
|
shawcentral.ca, 0
|
||||||
shawnhogan.com, 1
|
shawnhogan.com, 1
|
||||||
|
shawnstarrcustomhomes.com, 1
|
||||||
shawnwilkerson.com, 1
|
shawnwilkerson.com, 1
|
||||||
shawnwilson.info, 1
|
shawnwilson.info, 1
|
||||||
shazbots.org, 1
|
shazbots.org, 1
|
||||||
|
@ -30429,6 +30427,7 @@ silverlinkz.net, 1
|
||||||
silverseen.com, 1
|
silverseen.com, 1
|
||||||
silverstartup.sk, 1
|
silverstartup.sk, 1
|
||||||
silverwind.io, 1
|
silverwind.io, 1
|
||||||
|
silviamacallister.com, 1
|
||||||
silvine.xyz, 1
|
silvine.xyz, 1
|
||||||
silvistefi.com, 1
|
silvistefi.com, 1
|
||||||
silvobeat.blog, 1
|
silvobeat.blog, 1
|
||||||
|
@ -30884,6 +30883,7 @@ smutba.se, 1
|
||||||
smutek.net, 1
|
smutek.net, 1
|
||||||
smx.net.br, 1
|
smx.net.br, 1
|
||||||
snackbesteld.nl, 1
|
snackbesteld.nl, 1
|
||||||
|
snafarms.com, 1
|
||||||
snafu.cz, 1
|
snafu.cz, 1
|
||||||
snakafya.com, 1
|
snakafya.com, 1
|
||||||
snake.dog, 1
|
snake.dog, 1
|
||||||
|
@ -31327,6 +31327,7 @@ spirella-shop.ch, 1
|
||||||
spiritbionic.ro, 1
|
spiritbionic.ro, 1
|
||||||
spiritual.dating, 1
|
spiritual.dating, 1
|
||||||
spiritualife.net, 1
|
spiritualife.net, 1
|
||||||
|
spiritualregression.com.au, 1
|
||||||
spisbilligt.dk, 1
|
spisbilligt.dk, 1
|
||||||
spitfireuav.com, 1
|
spitfireuav.com, 1
|
||||||
spittank.info, 1
|
spittank.info, 1
|
||||||
|
@ -31546,7 +31547,6 @@ stainedglass.net.au, 1
|
||||||
stair.ch, 1
|
stair.ch, 1
|
||||||
stairfallgames.com, 1
|
stairfallgames.com, 1
|
||||||
stairlin.com, 1
|
stairlin.com, 1
|
||||||
staklim-malang.info, 1
|
|
||||||
staktrace.com, 1
|
staktrace.com, 1
|
||||||
stalder.work, 1
|
stalder.work, 1
|
||||||
stalker-shop.com, 1
|
stalker-shop.com, 1
|
||||||
|
@ -31618,7 +31618,9 @@ statecollegemortgages.com, 1
|
||||||
statgram.me, 1
|
statgram.me, 1
|
||||||
static-692b8c32.de, 1
|
static-692b8c32.de, 1
|
||||||
static-assets.io, 1
|
static-assets.io, 1
|
||||||
|
static-myfxee-808795.c.cdn77.org, 1
|
||||||
static-myfxoau-808795.c.cdn77.org, 1
|
static-myfxoau-808795.c.cdn77.org, 1
|
||||||
|
static-myfxouk-808795.c.cdn77.org, 1
|
||||||
static.hosting, 1
|
static.hosting, 1
|
||||||
static.wepay.com, 0
|
static.wepay.com, 0
|
||||||
staticisnoise.com, 1
|
staticisnoise.com, 1
|
||||||
|
@ -31640,7 +31642,7 @@ stayschemingco.com, 1
|
||||||
stb-schefczyk.de, 1
|
stb-schefczyk.de, 1
|
||||||
stb-strzyzewski.de, 1
|
stb-strzyzewski.de, 1
|
||||||
stbennett.org, 1
|
stbennett.org, 1
|
||||||
stcu.org, 1
|
stcu.org, 0
|
||||||
std-home-test.com, 1
|
std-home-test.com, 1
|
||||||
stderr.cc, 1
|
stderr.cc, 1
|
||||||
stdev.org, 1
|
stdev.org, 1
|
||||||
|
@ -31819,6 +31821,7 @@ stoianlawfirm.com, 1
|
||||||
stolina.de, 0
|
stolina.de, 0
|
||||||
stolkpotplanten.nl, 1
|
stolkpotplanten.nl, 1
|
||||||
stolkschepen.nl, 1
|
stolkschepen.nl, 1
|
||||||
|
stomadental.com, 1
|
||||||
stomt.com, 1
|
stomt.com, 1
|
||||||
stonedworms.de, 1
|
stonedworms.de, 1
|
||||||
stonefusion.org.uk, 1
|
stonefusion.org.uk, 1
|
||||||
|
@ -31829,6 +31832,7 @@ stonewuu.com, 1
|
||||||
stony.com, 1
|
stony.com, 1
|
||||||
stonystratford.org, 1
|
stonystratford.org, 1
|
||||||
stopakwardhandshakes.org, 1
|
stopakwardhandshakes.org, 1
|
||||||
|
stopbreakupnow.org, 1
|
||||||
stopbullying.gov, 1
|
stopbullying.gov, 1
|
||||||
stopfraud.gov, 1
|
stopfraud.gov, 1
|
||||||
stopthethyroidmadness.com, 1
|
stopthethyroidmadness.com, 1
|
||||||
|
@ -32201,6 +32205,7 @@ svendubbeld.nl, 1
|
||||||
sveneckelmann.de, 1
|
sveneckelmann.de, 1
|
||||||
svenjaundchristian.de, 1
|
svenjaundchristian.de, 1
|
||||||
svennd.be, 1
|
svennd.be, 1
|
||||||
|
svenskacasino.com, 1
|
||||||
svetandroida.cz, 1
|
svetandroida.cz, 1
|
||||||
svetlilo.com, 1
|
svetlilo.com, 1
|
||||||
svetzitrka.cz, 0
|
svetzitrka.cz, 0
|
||||||
|
@ -32404,7 +32409,6 @@ ta-sports.net, 1
|
||||||
ta65.com, 1
|
ta65.com, 1
|
||||||
taabe.net, 1
|
taabe.net, 1
|
||||||
taartbesteld.nl, 1
|
taartbesteld.nl, 1
|
||||||
taartenfeesies.nl, 1
|
|
||||||
tab.watch, 1
|
tab.watch, 1
|
||||||
tabarnak.ga, 1
|
tabarnak.ga, 1
|
||||||
tabernadovinho.com.br, 1
|
tabernadovinho.com.br, 1
|
||||||
|
@ -32668,7 +32672,6 @@ teamupturn.org, 1
|
||||||
teamusec.de, 1
|
teamusec.de, 1
|
||||||
teamx-gaming.de, 1
|
teamx-gaming.de, 1
|
||||||
teaparty.id, 1
|
teaparty.id, 1
|
||||||
tearoy.faith, 1
|
|
||||||
teasenetwork.com, 1
|
teasenetwork.com, 1
|
||||||
teaser-trailer.com, 1
|
teaser-trailer.com, 1
|
||||||
teatrarium.com, 1
|
teatrarium.com, 1
|
||||||
|
@ -32984,7 +32987,6 @@ thackbarth.net, 1
|
||||||
thackert.myfirewall.org, 1
|
thackert.myfirewall.org, 1
|
||||||
thaedal.net, 1
|
thaedal.net, 1
|
||||||
thai.dating, 1
|
thai.dating, 1
|
||||||
thai.land, 0
|
|
||||||
thaianthro.com, 1
|
thaianthro.com, 1
|
||||||
thaicyberpoint.com, 1
|
thaicyberpoint.com, 1
|
||||||
thaiforest.ch, 1
|
thaiforest.ch, 1
|
||||||
|
@ -33291,7 +33293,6 @@ thetrendspotter.net, 1
|
||||||
thetruthhurvitz.com, 1
|
thetruthhurvitz.com, 1
|
||||||
thetuxkeeper.de, 0
|
thetuxkeeper.de, 0
|
||||||
theunitedstates.io, 1
|
theunitedstates.io, 1
|
||||||
theuucc.org, 1
|
|
||||||
thevacweb.com, 1
|
thevacweb.com, 1
|
||||||
thevalentineconstitution.com, 1
|
thevalentineconstitution.com, 1
|
||||||
thevgg.com, 0
|
thevgg.com, 0
|
||||||
|
@ -33526,6 +33527,7 @@ timmersgems.com, 1
|
||||||
timmy.im, 1
|
timmy.im, 1
|
||||||
timmy.ws, 1
|
timmy.ws, 1
|
||||||
timmyrs.de, 1
|
timmyrs.de, 1
|
||||||
|
timnash.co.uk, 1
|
||||||
timonengelke.de, 1
|
timonengelke.de, 1
|
||||||
timoso.de, 1
|
timoso.de, 1
|
||||||
timothybjacobs.com, 1
|
timothybjacobs.com, 1
|
||||||
|
@ -33555,7 +33557,6 @@ tintencenter.com, 1
|
||||||
tintenfix.net, 1
|
tintenfix.net, 1
|
||||||
tintenfux.de, 1
|
tintenfux.de, 1
|
||||||
tintenland.de, 1
|
tintenland.de, 1
|
||||||
tintenprofi.de, 1
|
|
||||||
tiny.ee, 1
|
tiny.ee, 1
|
||||||
tinyhousefinance.com.au, 1
|
tinyhousefinance.com.au, 1
|
||||||
tinylan.com, 1
|
tinylan.com, 1
|
||||||
|
@ -33617,7 +33618,6 @@ tkn.tokyo, 1
|
||||||
tkts.cl, 1
|
tkts.cl, 1
|
||||||
tkusano.jp, 1
|
tkusano.jp, 1
|
||||||
tkw01536.de, 1
|
tkw01536.de, 1
|
||||||
tlach.cz, 1
|
|
||||||
tlca.org, 1
|
tlca.org, 1
|
||||||
tlcnet.info, 1
|
tlcnet.info, 1
|
||||||
tlehseasyads.com, 1
|
tlehseasyads.com, 1
|
||||||
|
@ -34572,7 +34572,6 @@ ubalert.com, 1
|
||||||
ubanquity.com, 1
|
ubanquity.com, 1
|
||||||
uberbkk.com, 1
|
uberbkk.com, 1
|
||||||
uberboxen.net, 1
|
uberboxen.net, 1
|
||||||
ubercalculator.com, 1
|
|
||||||
uberestimator.com, 1
|
uberestimator.com, 1
|
||||||
ubermail.me, 1
|
ubermail.me, 1
|
||||||
ubertt.org, 1
|
ubertt.org, 1
|
||||||
|
@ -35104,6 +35103,7 @@ vantagepointpreneed.com, 1
|
||||||
vante.me, 1
|
vante.me, 1
|
||||||
vantien.com, 1
|
vantien.com, 1
|
||||||
vantru.is, 1
|
vantru.is, 1
|
||||||
|
vanvoro.us, 0
|
||||||
vanwunnik.com, 1
|
vanwunnik.com, 1
|
||||||
vapecom-shop.com, 1
|
vapecom-shop.com, 1
|
||||||
vapecrunch.com, 1
|
vapecrunch.com, 1
|
||||||
|
@ -35441,6 +35441,7 @@ vinicius.sl, 1
|
||||||
vinilosdecorativos.net, 1
|
vinilosdecorativos.net, 1
|
||||||
vinner.com.au, 1
|
vinner.com.au, 1
|
||||||
vinnie.gq, 1
|
vinnie.gq, 1
|
||||||
|
vinogradovka.com, 1
|
||||||
vinolli.de, 1
|
vinolli.de, 1
|
||||||
vinovum.net, 1
|
vinovum.net, 1
|
||||||
vintagebandfestival.org, 1
|
vintagebandfestival.org, 1
|
||||||
|
@ -35526,6 +35527,7 @@ vitalityscience.com, 1
|
||||||
vitalthings.de, 1
|
vitalthings.de, 1
|
||||||
vitalware.com, 1
|
vitalware.com, 1
|
||||||
vitalyzhukphoto.com, 1
|
vitalyzhukphoto.com, 1
|
||||||
|
vitamaxxi.com.br, 1
|
||||||
vitaminler.com, 1
|
vitaminler.com, 1
|
||||||
vitapingu.de, 1
|
vitapingu.de, 1
|
||||||
vitastic.nl, 1
|
vitastic.nl, 1
|
||||||
|
@ -35562,7 +35564,6 @@ vkino.com, 0
|
||||||
vkirichenko.name, 1
|
vkirichenko.name, 1
|
||||||
vkox.com, 1
|
vkox.com, 1
|
||||||
vksportphoto.com, 1
|
vksportphoto.com, 1
|
||||||
vladimiroff.org, 1
|
|
||||||
vladislavstoyanov.com, 1
|
vladislavstoyanov.com, 1
|
||||||
vlastimilburian.cz, 1
|
vlastimilburian.cz, 1
|
||||||
vldkn.net, 1
|
vldkn.net, 1
|
||||||
|
@ -35622,10 +35623,10 @@ volcain.io, 1
|
||||||
volcanconcretos.com, 1
|
volcanconcretos.com, 1
|
||||||
volga.us, 1
|
volga.us, 1
|
||||||
volgavibes.ru, 0
|
volgavibes.ru, 0
|
||||||
|
voliere-info.nl, 0
|
||||||
volker-gropp.de, 1
|
volker-gropp.de, 1
|
||||||
volkergropp.de, 1
|
volkergropp.de, 1
|
||||||
volkerwesselstransfer.nl, 1
|
volkerwesselstransfer.nl, 1
|
||||||
volkerwesselswave.nl, 1
|
|
||||||
volkswurst.de, 1
|
volkswurst.de, 1
|
||||||
vollans.id.au, 1
|
vollans.id.au, 1
|
||||||
voloevents.com, 1
|
voloevents.com, 1
|
||||||
|
@ -35917,7 +35918,6 @@ wavesoftime.com, 1
|
||||||
waveum.com, 1
|
waveum.com, 1
|
||||||
wawak.pl, 1
|
wawak.pl, 1
|
||||||
waxdramatic.com, 1
|
waxdramatic.com, 1
|
||||||
waylaydesign.com, 1
|
|
||||||
wayne.cloud, 0
|
wayne.cloud, 0
|
||||||
wayohoo.com, 1
|
wayohoo.com, 1
|
||||||
wayohoo.net, 1
|
wayohoo.net, 1
|
||||||
|
@ -36038,7 +36038,6 @@ webliberty.ru, 1
|
||||||
weblogic.pl, 1
|
weblogic.pl, 1
|
||||||
weblogzwolle.nl, 1
|
weblogzwolle.nl, 1
|
||||||
webmail.gigahost.dk, 0
|
webmail.gigahost.dk, 0
|
||||||
webmail.info, 1
|
|
||||||
webmail.onlime.ch, 0
|
webmail.onlime.ch, 0
|
||||||
webmail.schokokeks.org, 0
|
webmail.schokokeks.org, 0
|
||||||
webmail.xalqbank.az, 1
|
webmail.xalqbank.az, 1
|
||||||
|
@ -36361,7 +36360,6 @@ whisperinghoperanch.org, 1
|
||||||
whisperlab.org, 1
|
whisperlab.org, 1
|
||||||
whistleb.com, 1
|
whistleb.com, 1
|
||||||
whistleblower.gov, 1
|
whistleblower.gov, 1
|
||||||
whistler-transfers.com, 1
|
|
||||||
whitby-brewery.com, 1
|
whitby-brewery.com, 1
|
||||||
whitealps.at, 1
|
whitealps.at, 1
|
||||||
whitealps.be, 1
|
whitealps.be, 1
|
||||||
|
@ -36685,7 +36683,6 @@ wonderhost.info, 1
|
||||||
wonderhowto.com, 1
|
wonderhowto.com, 1
|
||||||
wonderlandmovies.de, 1
|
wonderlandmovies.de, 1
|
||||||
wondermags.com, 1
|
wondermags.com, 1
|
||||||
wondershift.biz, 1
|
|
||||||
wonghome.net, 1
|
wonghome.net, 1
|
||||||
woodbury.io, 1
|
woodbury.io, 1
|
||||||
woodcoin.org, 1
|
woodcoin.org, 1
|
||||||
|
@ -36733,6 +36730,7 @@ workray.com, 1
|
||||||
works-ginan.jp, 1
|
works-ginan.jp, 1
|
||||||
workshopszwolle.nl, 1
|
workshopszwolle.nl, 1
|
||||||
workshopzwolle.com, 1
|
workshopzwolle.com, 1
|
||||||
|
worksofwyoming.org, 1
|
||||||
workwithgo.com, 1
|
workwithgo.com, 1
|
||||||
world-education-association.org, 1
|
world-education-association.org, 1
|
||||||
world-in-my-eyes.com, 1
|
world-in-my-eyes.com, 1
|
||||||
|
@ -36796,6 +36794,7 @@ wpdirecto.com, 1
|
||||||
wpdublin.com, 1
|
wpdublin.com, 1
|
||||||
wpenhance.com, 1
|
wpenhance.com, 1
|
||||||
wpformation.com, 1
|
wpformation.com, 1
|
||||||
|
wpg-inc.com, 1
|
||||||
wphelpwithhomework.tk, 1
|
wphelpwithhomework.tk, 1
|
||||||
wphostingblog.nl, 1
|
wphostingblog.nl, 1
|
||||||
wpinfos.de, 1
|
wpinfos.de, 1
|
||||||
|
@ -36848,7 +36847,6 @@ writingcities.net, 1
|
||||||
writingtoserve.net, 1
|
writingtoserve.net, 1
|
||||||
wrksheet.com, 1
|
wrksheet.com, 1
|
||||||
wrmea.org, 1
|
wrmea.org, 1
|
||||||
wroffle.com, 1
|
|
||||||
wromeapp.com, 1
|
wromeapp.com, 1
|
||||||
wrongware.cz, 1
|
wrongware.cz, 1
|
||||||
wrp-timber-mouldings.co.uk, 1
|
wrp-timber-mouldings.co.uk, 1
|
||||||
|
@ -37109,9 +37107,9 @@ xin-in.com, 1
|
||||||
xin-in.net, 1
|
xin-in.net, 1
|
||||||
xing-in.net, 1
|
xing-in.net, 1
|
||||||
xing.ml, 1
|
xing.ml, 1
|
||||||
|
xingiahanvisa.net, 1
|
||||||
xiqi.us, 1
|
xiqi.us, 1
|
||||||
xirion.net, 1
|
xirion.net, 1
|
||||||
xiyu.it, 0
|
|
||||||
xj8876.com, 1
|
xj8876.com, 1
|
||||||
xjd.vision, 1
|
xjd.vision, 1
|
||||||
xjjeeps.com, 1
|
xjjeeps.com, 1
|
||||||
|
@ -37819,7 +37817,6 @@ zargaripour.com, 1
|
||||||
zargescases.co.uk, 1
|
zargescases.co.uk, 1
|
||||||
zarmarket.org, 1
|
zarmarket.org, 1
|
||||||
zarpo.com.br, 1
|
zarpo.com.br, 1
|
||||||
zary.me, 1
|
|
||||||
zatsepin.by, 1
|
zatsepin.by, 1
|
||||||
zaufanatrzeciastrona.pl, 1
|
zaufanatrzeciastrona.pl, 1
|
||||||
zavec.com.ec, 1
|
zavec.com.ec, 1
|
||||||
|
@ -38052,6 +38049,7 @@ zorium.org, 1
|
||||||
zorki.nl, 1
|
zorki.nl, 1
|
||||||
zorntt.fr, 1
|
zorntt.fr, 1
|
||||||
zorz.info, 1
|
zorz.info, 1
|
||||||
|
zotero.org, 1
|
||||||
zouk.info, 1
|
zouk.info, 1
|
||||||
zouyaoji.top, 1
|
zouyaoji.top, 1
|
||||||
zravypapir.cz, 1
|
zravypapir.cz, 1
|
||||||
|
|
|
@ -132,7 +132,7 @@ use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::media_queries::{Device, MediaList, MediaType};
|
use style::media_queries::{Device, MediaList, MediaType};
|
||||||
use style::selector_parser::{RestyleDamage, Snapshot};
|
use style::selector_parser::{RestyleDamage, Snapshot};
|
||||||
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
|
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
|
||||||
use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
|
use style::str::{split_html_space_chars, str_join};
|
||||||
use style::stylesheet_set::DocumentStylesheetSet;
|
use style::stylesheet_set::DocumentStylesheetSet;
|
||||||
use style::stylesheets::{Stylesheet, StylesheetContents, Origin, OriginSet};
|
use style::stylesheets::{Stylesheet, StylesheetContents, Origin, OriginSet};
|
||||||
use task_source::TaskSource;
|
use task_source::TaskSource;
|
||||||
|
@ -3675,7 +3675,7 @@ impl DocumentMethods for Document {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#dom-document-open
|
// https://html.spec.whatwg.org/multipage/#dom-document-open
|
||||||
fn Open(&self, type_: DOMString, replace: DOMString) -> Fallible<DomRoot<Document>> {
|
fn Open(&self, _type: Option<DOMString>, replace: DOMString) -> Fallible<DomRoot<Document>> {
|
||||||
if !self.is_html_document() {
|
if !self.is_html_document() {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
return Err(Error::InvalidState);
|
return Err(Error::InvalidState);
|
||||||
|
@ -3709,9 +3709,7 @@ impl DocumentMethods for Document {
|
||||||
// Step 6.
|
// Step 6.
|
||||||
// TODO: ignore-opens-during-unload counter check.
|
// TODO: ignore-opens-during-unload counter check.
|
||||||
|
|
||||||
// Step 7: first argument already bound to `type_`.
|
// Step 7, 8.
|
||||||
|
|
||||||
// Step 8.
|
|
||||||
// TODO: check session history's state.
|
// TODO: check session history's state.
|
||||||
let replace = replace.eq_ignore_ascii_case("replace");
|
let replace = replace.eq_ignore_ascii_case("replace");
|
||||||
|
|
||||||
|
@ -3740,11 +3738,11 @@ impl DocumentMethods for Document {
|
||||||
// Step 15.
|
// Step 15.
|
||||||
Node::replace_all(None, self.upcast::<Node>());
|
Node::replace_all(None, self.upcast::<Node>());
|
||||||
|
|
||||||
// Steps 16-18.
|
// Steps 16, 17.
|
||||||
// Let's not?
|
// Let's not?
|
||||||
// TODO: https://github.com/whatwg/html/issues/1698
|
// TODO: https://github.com/whatwg/html/issues/1698
|
||||||
|
|
||||||
// Step 19.
|
// Step 18.
|
||||||
self.implementation.set(None);
|
self.implementation.set(None);
|
||||||
self.images.set(None);
|
self.images.set(None);
|
||||||
self.embeds.set(None);
|
self.embeds.set(None);
|
||||||
|
@ -3760,65 +3758,59 @@ impl DocumentMethods for Document {
|
||||||
self.target_element.set(None);
|
self.target_element.set(None);
|
||||||
*self.last_click_info.borrow_mut() = None;
|
*self.last_click_info.borrow_mut() = None;
|
||||||
|
|
||||||
|
// Step 19.
|
||||||
|
// TODO: Set the active document of document's browsing context to document with window.
|
||||||
|
|
||||||
// Step 20.
|
// Step 20.
|
||||||
self.set_encoding(UTF_8);
|
// TODO: Replace document's singleton objects with new instances of those objects, created in window's Realm.
|
||||||
|
|
||||||
// Step 21.
|
// Step 21.
|
||||||
// TODO: reload override buffer.
|
self.set_encoding(UTF_8);
|
||||||
|
|
||||||
// Step 22.
|
// Step 22.
|
||||||
|
// TODO: reload override buffer.
|
||||||
|
|
||||||
|
// Step 23.
|
||||||
// TODO: salvageable flag.
|
// TODO: salvageable flag.
|
||||||
|
|
||||||
let url = entry_responsible_document.url();
|
let url = entry_responsible_document.url();
|
||||||
|
|
||||||
// Step 23.
|
// Step 24.
|
||||||
self.set_url(url.clone());
|
self.set_url(url.clone());
|
||||||
|
|
||||||
// Step 24.
|
// Step 25.
|
||||||
// TODO: mute iframe load.
|
// TODO: mute iframe load.
|
||||||
|
|
||||||
// Step 27.
|
// Step 26.
|
||||||
let type_ = if type_.eq_ignore_ascii_case("replace") {
|
|
||||||
"text/html"
|
|
||||||
} else if let Some(position) = type_.find(';') {
|
|
||||||
&type_[0..position]
|
|
||||||
} else {
|
|
||||||
&*type_
|
|
||||||
};
|
|
||||||
let type_ = type_.trim_matches(HTML_SPACE_CHARACTERS);
|
|
||||||
|
|
||||||
// Step 25.
|
|
||||||
let resource_threads =
|
let resource_threads =
|
||||||
self.window.upcast::<GlobalScope>().resource_threads().clone();
|
self.window.upcast::<GlobalScope>().resource_threads().clone();
|
||||||
*self.loader.borrow_mut() =
|
*self.loader.borrow_mut() =
|
||||||
DocumentLoader::new_with_threads(resource_threads, Some(url.clone()));
|
DocumentLoader::new_with_threads(resource_threads, Some(url.clone()));
|
||||||
ServoParser::parse_html_script_input(self, url, type_);
|
ServoParser::parse_html_script_input(self, url, "text/html");
|
||||||
|
|
||||||
// Step 26.
|
// Step 27.
|
||||||
self.ready_state.set(DocumentReadyState::Interactive);
|
self.ready_state.set(DocumentReadyState::Interactive);
|
||||||
|
|
||||||
// Step 28 is handled when creating the parser in step 25.
|
// Step 28.
|
||||||
|
// TODO: remove history traversal tasks.
|
||||||
|
|
||||||
// Step 29.
|
// Step 29.
|
||||||
// TODO: truncate session history.
|
// TODO: truncate session history.
|
||||||
|
|
||||||
// Step 30.
|
// Step 30.
|
||||||
// TODO: remove history traversal tasks.
|
|
||||||
|
|
||||||
// Step 31.
|
|
||||||
// TODO: remove earlier entries.
|
// TODO: remove earlier entries.
|
||||||
|
|
||||||
if !replace {
|
if !replace {
|
||||||
// Step 32.
|
// Step 31.
|
||||||
// TODO: add history entry.
|
// TODO: add history entry.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 33.
|
// Step 32.
|
||||||
// TODO: clear fired unload flag.
|
// TODO: clear fired unload flag.
|
||||||
|
|
||||||
// Step 34 is handled when creating the parser in step 25.
|
// Step 33 is handled when creating the parser in step 26.
|
||||||
|
|
||||||
// Step 35.
|
// Step 34.
|
||||||
Ok(DomRoot::from_ref(self))
|
Ok(DomRoot::from_ref(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3851,7 +3843,7 @@ impl DocumentMethods for Document {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
// Step 5.
|
// Step 5.
|
||||||
self.Open("text/html".into(), "".into())?;
|
self.Open(None, "".into())?;
|
||||||
self.get_current_parser().unwrap()
|
self.get_current_parser().unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -118,7 +118,7 @@ partial /*sealed*/ interface Document {
|
||||||
|
|
||||||
// dynamic markup insertion
|
// dynamic markup insertion
|
||||||
[CEReactions, Throws]
|
[CEReactions, Throws]
|
||||||
Document open(optional DOMString type = "text/html", optional DOMString replace = "");
|
Document open(optional DOMString type, optional DOMString replace = "");
|
||||||
// WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
|
// WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
|
||||||
[CEReactions, Throws]
|
[CEReactions, Throws]
|
||||||
void close();
|
void close();
|
||||||
|
|
|
@ -98,3 +98,5 @@ jobs:
|
||||||
symbol: I(diff)
|
symbol: I(diff)
|
||||||
periodic-updates:
|
periodic-updates:
|
||||||
symbol: I(file)
|
symbol: I(file)
|
||||||
|
firefox-snap:
|
||||||
|
symbol: I(snap)
|
||||||
|
|
|
@ -31,7 +31,7 @@ job-defaults:
|
||||||
implementation: docker-worker
|
implementation: docker-worker
|
||||||
os: linux
|
os: linux
|
||||||
max-run-time: 7200
|
max-run-time: 7200
|
||||||
docker-image: mozillareleases/firefox-snapcraft@sha256:107cc7a89d45ce6df30f44fe0dfd0b375b3ab443b75e92efc77c4f7bc5da8717
|
docker-image: {in-tree: firefox-snap}
|
||||||
artifacts:
|
artifacts:
|
||||||
- name: public/build
|
- name: public/build
|
||||||
type: directory
|
type: directory
|
||||||
|
@ -40,8 +40,6 @@ job-defaults:
|
||||||
- /bin/bash
|
- /bin/bash
|
||||||
- -cx
|
- -cx
|
||||||
- >
|
- >
|
||||||
apt-get update &&
|
|
||||||
apt-get dist-upgrade -y &&
|
|
||||||
curl -o scripts.tar.bz2 {config_params[head_repository]}/archive/{config_params[head_rev]}.tar.bz2/taskcluster/docker/firefox-snap/ &&
|
curl -o scripts.tar.bz2 {config_params[head_repository]}/archive/{config_params[head_rev]}.tar.bz2/taskcluster/docker/firefox-snap/ &&
|
||||||
mkdir scripts &&
|
mkdir scripts &&
|
||||||
tar xvfj scripts.tar.bz2 -C scripts --strip-components 4 &&
|
tar xvfj scripts.tar.bz2 -C scripts --strip-components 4 &&
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
FROM ubuntu:16.04
|
FROM snapcore/snapcraft:stable
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -qy snapcraft bzip2 curl git && apt-get clean
|
RUN apt-get update && apt-get install -qy python3 bzip2 curl git && apt-get clean
|
||||||
|
|
||||||
|
# Set a default command useful for debugging
|
||||||
|
CMD ["/bin/bash", "--login"]
|
||||||
|
|
|
@ -58,6 +58,9 @@ done
|
||||||
sed -e "s/@VERSION@/${VERSION}/g" -e "s/@BUILD_NUMBER@/${BUILD_NUMBER}/g" snapcraft.yaml.in > "${WORKSPACE}/snapcraft.yaml"
|
sed -e "s/@VERSION@/${VERSION}/g" -e "s/@BUILD_NUMBER@/${BUILD_NUMBER}/g" snapcraft.yaml.in > "${WORKSPACE}/snapcraft.yaml"
|
||||||
cp -v "$SCRIPT_DIRECTORY/mimeapps.list" "$WORKSPACE"
|
cp -v "$SCRIPT_DIRECTORY/mimeapps.list" "$WORKSPACE"
|
||||||
cd "${WORKSPACE}"
|
cd "${WORKSPACE}"
|
||||||
|
|
||||||
|
# Make sure snapcraft knows we're building amd64, even though we may not be on this arch.
|
||||||
|
export SNAP_ARCH='amd64'
|
||||||
snapcraft
|
snapcraft
|
||||||
|
|
||||||
mv -- *.snap "$TARGET_FULL_PATH"
|
mv -- *.snap "$TARGET_FULL_PATH"
|
||||||
|
|
|
@ -34,7 +34,7 @@ class TestWindowMaximize(MarionetteTestCase):
|
||||||
if self.marionette.session_capabilities["platformName"] == "windows_nt":
|
if self.marionette.session_capabilities["platformName"] == "windows_nt":
|
||||||
delta = 16
|
delta = 16
|
||||||
else:
|
else:
|
||||||
delta = 8
|
delta = 22
|
||||||
|
|
||||||
self.assertGreaterEqual(
|
self.assertGreaterEqual(
|
||||||
actual["width"], self.max["width"] - delta,
|
actual["width"], self.max["width"] - delta,
|
||||||
|
|
|
@ -51,13 +51,13 @@ def run_marionette(tests, binary=None, topsrcdir=None, **kwargs):
|
||||||
args = argparse.Namespace(tests=tests)
|
args = argparse.Namespace(tests=tests)
|
||||||
|
|
||||||
args.binary = binary
|
args.binary = binary
|
||||||
|
args.logger = kwargs.pop('log', None)
|
||||||
|
|
||||||
for k, v in kwargs.iteritems():
|
for k, v in kwargs.iteritems():
|
||||||
setattr(args, k, v)
|
setattr(args, k, v)
|
||||||
|
|
||||||
parser.verify_usage(args)
|
parser.verify_usage(args)
|
||||||
|
|
||||||
args.logger = kwargs.get('log')
|
|
||||||
if not args.logger:
|
if not args.logger:
|
||||||
args.logger = commandline.setup_logging("Marionette Unit Tests",
|
args.logger = commandline.setup_logging("Marionette Unit Tests",
|
||||||
args,
|
args,
|
||||||
|
|
|
@ -56,7 +56,7 @@ TEST_SUITES = {
|
||||||
},
|
},
|
||||||
'marionette': {
|
'marionette': {
|
||||||
'aliases': ('mn',),
|
'aliases': ('mn',),
|
||||||
'mach_command': 'marionette',
|
'mach_command': 'marionette-test',
|
||||||
'kwargs': {'tests': None},
|
'kwargs': {'tests': None},
|
||||||
},
|
},
|
||||||
'mochitest-a11y': {
|
'mochitest-a11y': {
|
||||||
|
|
|
@ -44,7 +44,7 @@ module.exports = async function() {
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
let childListMutationsCounter = 0;
|
let childListMutationsCounter = 0;
|
||||||
inspector.on("markupmutation", (evt, mutations) => {
|
inspector.on("markupmutation", mutations => {
|
||||||
let childListMutations = mutations.filter(m => m.type === "childList");
|
let childListMutations = mutations.filter(m => m.type === "childList");
|
||||||
childListMutationsCounter += childListMutations.length;
|
childListMutationsCounter += childListMutations.length;
|
||||||
if (childListMutationsCounter === LIMIT) {
|
if (childListMutationsCounter === LIMIT) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче