Merge mozilla-central to inbound. a=merge CLOSED TREE

--HG--
rename : toolkit/components/extensions/ext-permissions.js => toolkit/components/extensions/parent/ext-permissions.js
This commit is contained in:
Gurzau Raul 2018-03-29 01:00:42 +03:00
Родитель 54769131c0 d117255a14
Коммит 8d268c6ce7
445 изменённых файлов: 10421 добавлений и 52893 удалений

Просмотреть файл

@ -7,9 +7,9 @@
registry = 'https://github.com/rust-lang/crates.io-index'
replace-with = 'vendored-sources'
[source."https://github.com/gankro/serde"]
git = "https://github.com/gankro/serde"
branch = "deserialize_from_enums4"
[source."https://github.com/servo/serde"]
git = "https://github.com/servo/serde"
branch = "deserialize_from_enums5"
replace-with = "vendored-sources"
[source.vendored-sources]

Просмотреть файл

@ -84,7 +84,6 @@ media/libopus/.*
media/libpng/.*
media/libsoundtouch/.*
media/libspeex_resampler/.*
media/libstagefright/.*
media/libtheora/.*
media/libtremor/.*
media/libvorbis/.*
@ -92,11 +91,11 @@ media/libvpx/.*
media/libyuv/.*
media/mtransport/third_party/.*
media/openmax_dl/.*
media/sphinxbase/.*
media/webrtc/signaling/src/sdp/sipcc/.*
media/webrtc/trunk/.*
mfbt/decimal/.*
mfbt/double-conversion/double-conversion/.*
mfbt/lz4.*
mobile/android/geckoview/src/thirdparty/.*
mobile/android/thirdparty/.*
modules/brotli/.*
@ -141,7 +140,6 @@ third_party/python/six/.*
third_party/python/which/.*
third_party/rust/.*
toolkit/components/jsoncpp/.*
toolkit/components/lz4/.*
toolkit/components/protobuf/.*
toolkit/components/url-classifier/chromium/.*
toolkit/components/url-classifier/protobuf/.*

53
Cargo.lock сгенерированный
Просмотреть файл

@ -22,7 +22,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -62,8 +62,8 @@ dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
"tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -121,7 +121,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -508,8 +508,8 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -563,7 +563,7 @@ version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1444,7 +1444,7 @@ name = "ron"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1544,29 +1544,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.27"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
]
[[package]]
name = "serde_derive"
version = "1.0.27"
source = "git+https://github.com/gankro/serde?branch=deserialize_from_enums4#93e24f268ab99c0df10e2183587284e02ca30e9e"
version = "1.0.35"
source = "git+https://github.com/servo/serde?branch=deserialize_from_enums5#de4534b21f263752ed3b641c3c07e012574985bf"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.19.0 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.19.0"
source = "git+https://github.com/gankro/serde?branch=deserialize_from_enums4#93e24f268ab99c0df10e2183587284e02ca30e9e"
version = "0.22.1"
source = "git+https://github.com/servo/serde?branch=deserialize_from_enums5#de4534b21f263752ed3b641c3c07e012574985bf"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1848,7 +1849,7 @@ name = "toml"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -2031,7 +2032,7 @@ dependencies = [
"plane-split 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2050,8 +2051,8 @@ dependencies = [
"core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
"serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2323,9 +2324,9 @@ dependencies = [
"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)" = "<none>"
"checksum serde_derive_internals 0.19.0 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)" = "<none>"
"checksum serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "800fdb0a894572994f3970035a8a5f65d8ec2cd40e6cdf7d8cd9001d7b30648e"
"checksum serde_derive 1.0.35 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
"checksum serde_derive_internals 0.22.1 (git+https://github.com/servo/serde?branch=deserialize_from_enums5)" = "<none>"
"checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"

Просмотреть файл

@ -58,4 +58,4 @@ codegen-units = 1
[patch.crates-io]
libudev-sys = { path = "dom/webauthn/libudev-sys" }
serde_derive = { git = "https://github.com/gankro/serde", branch = "deserialize_from_enums4" }
serde_derive = { git = "https://github.com/servo/serde", branch = "deserialize_from_enums5" }

Просмотреть файл

@ -32,7 +32,7 @@ var StarUI = {
// initially the panel is hidden
// to avoid impacting startup / new window performance
element.hidden = false;
element.addEventListener("keypress", this);
element.addEventListener("keypress", this, {mozSystemGroup: true});
element.addEventListener("mousedown", this);
element.addEventListener("mouseout", this);
element.addEventListener("mousemove", this);

Просмотреть файл

@ -442,6 +442,88 @@ add_task(async function ctrl_d_new_bookmark_mousedown_mouseout_no_autoclose() {
});
});
add_task(async function enter_during_autocomplete_should_prevent_autoclose() {
await test_bookmarks_popup({
isNewBookmark: true,
async popupShowFn(browser) {
EventUtils.synthesizeKey("d", {accelKey: true}, window);
},
async popupEditFn() {
let tagsField = document.getElementById("editBMPanel_tagsField");
tagsField.value = "";
tagsField.focus();
// Register a tag into the DB.
EventUtils.sendString("Abc", window);
tagsField.blur();
// Start autocomplete with the registered tag.
tagsField.value = "";
let popup = document.getElementById("PopupAutoComplete");
let promiseShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
tagsField.focus();
EventUtils.sendString("a", window);
await promiseShown;
ok(promiseShown, "autocomplete shown");
// Select first candidate.
EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
// Type Enter key to choose the item.
EventUtils.synthesizeKey("KEY_Enter", {}, window);
Assert.equal(tagsField.value, "Abc",
"Autocomplete should've inserted the selected item");
},
shouldAutoClose: false,
popupHideFn() {
EventUtils.synthesizeKey("KEY_Escape", {}, window);
},
isBookmarkRemoved: false,
});
});
add_task(async function escape_during_autocomplete_should_prevent_autoclose() {
await test_bookmarks_popup({
isNewBookmark: true,
async popupShowFn(browser) {
EventUtils.synthesizeKey("d", {accelKey: true}, window);
},
async popupEditFn() {
let tagsField = document.getElementById("editBMPanel_tagsField");
tagsField.value = "";
tagsField.focus();
// Register a tag into the DB.
EventUtils.sendString("Abc", window);
tagsField.blur();
// Start autocomplete with the registered tag.
tagsField.value = "";
let popup = document.getElementById("PopupAutoComplete");
let promiseShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
tagsField.focus();
EventUtils.sendString("a", window);
await promiseShown;
ok(promiseShown, "autocomplete shown");
// Select first candidate.
EventUtils.synthesizeKey("KEY_ArrowDown", {}, window);
// Type Enter key to choose the item.
EventUtils.synthesizeKey("KEY_Escape", {}, window);
Assert.equal(tagsField.value, "Abc",
"Autocomplete should've inserted the selected item and shouldn't clear it");
},
shouldAutoClose: false,
popupHideFn() {
EventUtils.synthesizeKey("KEY_Escape", {}, window);
},
isBookmarkRemoved: false,
});
});
registerCleanupFunction(function() {
delete StarUI._closePanelQuickForTesting;
});

Просмотреть файл

@ -2,6 +2,9 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource:///modules/SitePermissions.jsm");
const PREF_PERMISSION_FAKE = "media.navigator.permission.fake";
const PREF_AUDIO_LOOPBACK = "media.audio_loopback_dev";
const PREF_VIDEO_LOOPBACK = "media.video_loopback_dev";
const PREF_FAKE_STREAMS = "media.navigator.streams.fake";
const CONTENT_SCRIPT_HELPER = getRootDirectory(gTestPath) + "get_user_media_content_script.js";
const STATE_CAPTURE_ENABLED = Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED;
@ -563,7 +566,17 @@ async function runTests(tests, options = {}) {
ok(gIdentityHandler._identityPopup.hidden,
"should start the test with the control center hidden");
await SpecialPowers.pushPrefEnv({"set": [[PREF_PERMISSION_FAKE, true]]});
// Set prefs so that permissions prompts are shown and loopback devices
// are not used. To test the chrome we want prompts to be shown, and
// these tests are flakey when using loopback devices (though it would
// be desirable to make them work with loopback in future).
let prefs = [
[PREF_PERMISSION_FAKE, true],
[PREF_AUDIO_LOOPBACK, ""],
[PREF_VIDEO_LOOPBACK, ""],
[PREF_FAKE_STREAMS, true]
];
await SpecialPowers.pushPrefEnv({"set": prefs});
for (let testCase of tests) {
info(testCase.desc);

Просмотреть файл

@ -13,6 +13,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gXulStore",
XPCOMUtils.defineLazyModuleGetters(this, {
BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
AddonManager: "resource://gre/modules/AddonManager.jsm",
});
const PREF_LOGLEVEL = "browser.policies.loglevel";
@ -279,6 +280,63 @@ var Policies = {
}
},
"Extensions": {
onBeforeUIStartup(manager, param) {
if ("Install" in param) {
runOncePerModification("extensionsInstall", JSON.stringify(param.Install), () => {
for (let location of param.Install) {
let url;
if (location.includes("://")) {
// Assume location is an URI
url = location;
} else {
// Assume location is a file path
let xpiFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
try {
xpiFile.initWithPath(location);
} catch (e) {
log.error(`Invalid extension path location - ${location}`);
continue;
}
url = Services.io.newFileURI(xpiFile).spec;
}
AddonManager.getInstallForURL(url, (install) => {
let listener = {
onDownloadFailed: () => {
log.error(`Download failed - ${location}`);
},
onInstallFailed: () => {
log.error(`Installation failed - ${location}`);
},
onInstallEnded: () => {
log.debug(`Installation succeeded - ${location}`);
}
};
install.addListener(listener);
install.install();
}, "application/x-xpinstall");
}
});
}
if ("Uninstall" in param) {
runOncePerModification("extensionsUninstall", JSON.stringify(param.Uninstall), () => {
AddonManager.getAddonsByIDs(param.Uninstall, (addons) => {
for (let addon of addons) {
if (addon) {
addon.uninstall();
}
}
});
});
}
if ("Locked" in param) {
for (let ID of param.Locked) {
manager.disallowFeature(`modify-extension:${ID}`);
}
}
}
},
"FlashPlugin": {
onBeforeUIStartup(manager, param) {
addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
@ -301,7 +359,11 @@ var Policies = {
setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
} else {
setDefaultPref("browser.startup.homepage", homepages);
// The default pref for homepage is actually a complex pref. We need to
// set it in a special way such that it works properly
let homepagePrefVal = "data:text/plain,browser.startup.homepage=" +
homepages;
setDefaultPref("browser.startup.homepage", homepagePrefVal);
setDefaultPref("browser.startup.page", 1);
runOncePerModification("setHomepage", homepages, () => {
Services.prefs.clearUserPref("browser.startup.homepage");

Просмотреть файл

@ -222,6 +222,34 @@
"required": ["Value"]
},
"Extensions": {
"description": "Install, uninstall or lock extensions. The Install option takes URLs or paths as parameters. The Uninstall and Locked options take extension IDs.",
"first_available": "60.0",
"enterprise_only": true,
"type": "object",
"properties": {
"Install" : {
"type": "array",
"items": {
"type": "string"
}
},
"Uninstall" : {
"type": "array",
"items": {
"type": "string"
}
},
"Locked" : {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"FlashPlugin": {
"description": "Allow or deny flash plugin usage.",
"first_available": "60.0",

Просмотреть файл

@ -5,6 +5,7 @@ support-files =
config_broken_json.json
opensearch.html
opensearchEngine.xml
policytest.xpi
[browser_policies_basic_tests.js]
[browser_policies_broken_json.js]
@ -35,6 +36,7 @@ support-files =
[browser_policy_disable_shield.js]
[browser_policy_display_bookmarks.js]
[browser_policy_display_menu.js]
[browser_policy_extensions.js]
[browser_policy_proxy.js]
[browser_policy_search_engine.js]
[browser_policy_set_homepage.js]

Просмотреть файл

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const addonID = "policytest@mozilla.com";
add_task(async function test_addon_install() {
await setupPolicyEngineWithJson({
"policies": {
"Extensions": {
"Install": [
"http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/policytest.xpi"
],
"Locked": [
addonID
]
}
}
});
await wait_for_addon_install();
let addon = await AddonManager.getAddonByID(addonID);
isnot(addon, null, "Addon not installed.");
});
add_task(async function test_addon_locked() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserOpenAddonsMgr("addons://list/extension");
// eslint-disable-next-line no-shadow
await ContentTask.spawn(tab.linkedBrowser, {addonID}, async function({addonID}) {
let list = content.document.getElementById("addon-list");
let flashEntry = list.getElementsByAttribute("value", addonID)[0];
let disableBtn = content.document.getAnonymousElementByAttribute(flashEntry, "anonid", "disable-btn");
let removeBtn = content.document.getAnonymousElementByAttribute(flashEntry, "anonid", "remove-btn");
is(removeBtn.hidden, true, "Remove button should be hidden");
is(disableBtn.hidden, true, "Disable button should be hidden");
});
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_addon_uninstall() {
await setupPolicyEngineWithJson({
"policies": {
"Extensions": {
"Uninstall": [
addonID
]
}
}
});
let addon = await AddonManager.getAddonByID(addonID);
is(addon, null, "Addon should be uninstalled.");
});
function wait_for_addon_install() {
return new Promise((resolve, reject) => {
AddonManager.addInstallListener({
onInstallEnded(install, addon) {
if (addon.id == addonID)
resolve();
},
onDownloadFailed: (install) => {
reject();
},
onInstallFailed: (install) => {
reject();
},
});
});
}

Просмотреть файл

@ -10,6 +10,49 @@ registerCleanupFunction(function restore_pref_values() {
Services.prefs.clearUserPref("browser.startup.page");
});
async function check_homepage({expectedURL, expectedPageVal = 1, locked = false}) {
is(gHomeButton.getHomePage(),
expectedURL, "Homepage URL should match expected");
is(Services.prefs.getIntPref("browser.startup.page", -1), expectedPageVal,
"Pref page value should match expected");
is(Services.prefs.prefIsLocked("browser.startup.homepage"), locked,
"Lock status of browser.startup.homepage should match expected");
is(Services.prefs.prefIsLocked("browser.startup.page"), locked,
"Lock status of browser.startup.page should match expected");
// Test that UI is disabled when the Locked property is enabled
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
await ContentTask.spawn(tab.linkedBrowser, {expectedURL, expectedPageVal, locked},
// eslint-disable-next-line no-shadow
async function({expectedURL, expectedPageVal, locked}) {
let startupPageRadioGroup = content.document.getElementById("browserStartupPage");
is(startupPageRadioGroup.disabled, locked,
"Disabled status of start page radio group should match expected");
is(startupPageRadioGroup.value, expectedPageVal,
"Value of start page radio group should match expected");
content.document.getElementById("category-home").click();
let homepageTextbox = content.document.getElementById("homePageUrl");
// Unfortunately this test does not work because the new UI does not fill
// default values into the URL box at the moment.
// is(homepageTextbox.value, expectedURL,
// "Homepage URL should match expected");
is(homepageTextbox.disabled, locked,
"Homepage URL text box disabled status should match expected");
is(content.document.getElementById("homeMode").disabled, locked,
"Home mode drop down disabled status should match expected");
is(content.document.getElementById("useCurrentBtn").disabled, locked,
"\"Use current page\" button disabled status should match expected");
is(content.document.getElementById("useBookmarkBtn").disabled, locked,
"\"Use bookmark\" button disabled status should match expected");
is(content.document.getElementById("restoreDefaultHomePageBtn").disabled,
locked, "\"Restore defaults\" button disabled status should match expected");
});
await BrowserTestUtils.removeTab(tab);
}
add_task(async function homepage_test_simple() {
await setupPolicyEngineWithJson({
"policies": {
@ -18,10 +61,7 @@ add_task(async function homepage_test_simple() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example1.com/", "Homepage URL should have been set");
is(Services.prefs.getIntPref("browser.startup.page", -1), 1,
"Homepage should be used instead of blank page or previous tabs");
await check_homepage({expectedURL: "http://example1.com/"});
});
add_task(async function homepage_test_repeat_same_policy_value() {
@ -39,11 +79,8 @@ add_task(async function homepage_test_repeat_same_policy_value() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example2.com/",
"Homepage URL should not have been overridden by pre-existing policy value");
is(Services.prefs.getIntPref("browser.startup.page", -1), 3,
"Start page type should not have been overridden by pre-existing policy value");
await check_homepage({expectedURL: "http://example2.com/",
expectedPageVal: 3});
});
add_task(async function homepage_test_different_policy_value() {
@ -56,11 +93,7 @@ add_task(async function homepage_test_different_policy_value() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example3.com/",
"Homepage URL should have been overridden by the policy value");
is(Services.prefs.getIntPref("browser.startup.page", -1), 1,
"Start page type should have been overridden by setting the policy value");
await check_homepage({expectedURL: "http://example3.com/"});
});
add_task(async function homepage_test_empty_additional() {
@ -72,8 +105,7 @@ add_task(async function homepage_test_empty_additional() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example1.com/", "Homepage URL should have been set properly");
await check_homepage({expectedURL: "http://example1.com/"});
});
add_task(async function homepage_test_single_additional() {
@ -85,10 +117,7 @@ add_task(async function homepage_test_single_additional() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example1.com/|http://example2.com/",
"Homepage URL should have been set properly");
await check_homepage({expectedURL: "http://example1.com/|http://example2.com/"});
});
add_task(async function homepage_test_multiple_additional() {
@ -101,10 +130,7 @@ add_task(async function homepage_test_multiple_additional() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example1.com/|http://example2.com/|http://example3.com/",
"Homepage URL should have been set properly");
await check_homepage({expectedURL: "http://example1.com/|http://example2.com/|http://example3.com/"});
});
add_task(async function homepage_test_locked() {
@ -118,34 +144,6 @@ add_task(async function homepage_test_locked() {
}
}
});
is(Services.prefs.getStringPref("browser.startup.homepage", ""),
"http://example4.com/|http://example5.com/|http://example6.com/",
"Homepage URL should have been set properly");
is(Services.prefs.getIntPref("browser.startup.page", -1), 1,
"Homepage should be used instead of blank page or previous tabs");
is(Services.prefs.prefIsLocked("browser.startup.homepage"), true,
"Homepage pref should be locked");
is(Services.prefs.prefIsLocked("browser.startup.page"), true,
"Start page type pref should be locked");
// Test that UI is disabled when the Locked property is enabled
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
is(content.document.getElementById("browserStartupPage").disabled, true,
"When homepage is locked, the startup page choice controls should be locked");
});
await BrowserTestUtils.loadURI(tab.linkedBrowser, "about:preferences#home");
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
is(content.document.getElementById("homeMode").disabled, true,
"Homepage menulist should be disabled");
is(content.document.getElementById("homePageUrl").disabled, true,
"Homepage custom input should be disabled");
is(content.document.getElementById("useCurrentBtn").disabled, true,
"\"Use Current Page\" button should be disabled");
is(content.document.getElementById("useBookmarkBtn").disabled, true,
"\"Use Bookmark...\" button should be disabled");
is(content.document.getElementById("restoreDefaultHomePageBtn").disabled, true,
"\"Restore to Default\" button should be disabled");
});
BrowserTestUtils.removeTab(tab);
await check_homepage({expectedURL: "http://example4.com/|http://example5.com/|http://example6.com/",
locked: true});
});

Двоичные данные
browser/components/enterprisepolicies/tests/browser/policytest.xpi Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1,5 +1,5 @@
This is the PDF.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 2.0.402
Current extension version is: 2.0.447
Taken from upstream commit: 401f3a9d
Taken from upstream commit: c0b22da0

Просмотреть файл

@ -49,6 +49,8 @@ ChromeUtils.defineModuleGetter(this, "PdfjsChromeUtils",
"resource://pdf.js/PdfjsChromeUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PdfjsContentUtils",
"resource://pdf.js/PdfjsContentUtils.jsm");
ChromeUtils.defineModuleGetter(this, "PdfJsDefaultPreferences",
"resource://pdf.js/PdfJsDefaultPreferences.jsm");
function getBoolPref(aPref, aDefaultValue) {
try {
@ -75,35 +77,10 @@ function isDefaultHandler() {
}
function initializeDefaultPreferences() {
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"cursorToolOnLoad": 0,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"textLayerMode": 1,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
}
/* eslint-enable semi */
var defaultBranch = Services.prefs.getDefaultBranch(PREF_PREFIX + ".");
var defaultValue;
for (var key in DEFAULT_PREFERENCES) {
defaultValue = DEFAULT_PREFERENCES[key];
for (var key in PdfJsDefaultPreferences) {
defaultValue = PdfJsDefaultPreferences[key];
switch (typeof defaultValue) {
case "boolean":
defaultBranch.setBoolPref(key, defaultValue);

Просмотреть файл

@ -0,0 +1,41 @@
/* Copyright 2017 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT MANUALLY!
//
"use strict";
var EXPORTED_SYMBOLS = ["PdfJsDefaultPreferences"];
var PdfJsDefaultPreferences = Object.freeze({
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"cursorToolOnLoad": 0,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"textLayerMode": 1,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
});

Просмотреть файл

@ -23,40 +23,18 @@ const PDF_CONTENT_TYPE = "application/pdf";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PdfJsDefaultPreferences",
"resource://pdf.js/PdfJsDefaultPreferences.jsm");
var Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, "mime",
"@mozilla.org/mime;1",
"nsIMIMEService");
/* eslint-disable semi */
var DEFAULT_PREFERENCES =
{
"showPreviousViewOnLoad": true,
"defaultZoomValue": "",
"sidebarViewOnLoad": 0,
"cursorToolOnLoad": 0,
"enableWebGL": false,
"pdfBugEnabled": false,
"disableRange": false,
"disableStream": false,
"disableAutoFetch": false,
"disableFontFace": false,
"textLayerMode": 1,
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"renderer": "canvas",
"renderInteractiveForms": false,
"enablePrintAutoRotate": false,
"disablePageMode": false,
"disablePageLabels": false
}
/* eslint-enable semi */
var PdfjsChromeUtils = {
// For security purposes when running remote, we restrict preferences
// content can access.
_allowedPrefNames: Object.keys(DEFAULT_PREFERENCES),
_allowedPrefNames: Object.keys(PdfJsDefaultPreferences),
_ppmm: null,
_mmg: null,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -28,7 +28,7 @@
else if(typeof exports === 'object')
exports["pdfjs-dist/build/pdf.worker"] = factory();
else
root["pdfjs-dist/build/pdf.worker"] = root.pdfjsDistBuildPdfWorker = factory();
root["pdfjs-dist/build/pdf.worker"] = root.pdfjsWorker = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
@ -105,11 +105,11 @@ return /******/ (function(modules) { // webpackBootstrap
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
exports.unreachable = exports.warn = exports.utf8StringToString = exports.stringToUTF8String = exports.stringToPDFString = exports.stringToBytes = exports.string32 = exports.shadow = exports.setVerbosityLevel = exports.ReadableStream = exports.removeNullCharacters = exports.readUint32 = exports.readUint16 = exports.readInt8 = exports.log2 = exports.isEvalSupported = exports.isLittleEndian = exports.createValidAbsoluteUrl = exports.isSameOrigin = exports.isSpace = exports.isString = exports.isNum = exports.isEmptyObj = exports.isBool = exports.isArrayBuffer = exports.info = exports.getVerbosityLevel = exports.getLookupTableFactory = exports.getInheritableProperty = exports.deprecated = exports.createObjectURL = exports.createPromiseCapability = exports.createBlob = exports.bytesToString = exports.assert = exports.arraysToBytes = exports.arrayByteLength = exports.FormatError = exports.XRefParseException = exports.Util = exports.UnknownErrorException = exports.UnexpectedResponseException = exports.TextRenderingMode = exports.StreamType = exports.PasswordResponses = exports.PasswordException = exports.PageViewport = exports.NotImplementedException = exports.NativeImageDecoding = exports.MissingPDFException = exports.MissingDataException = exports.MessageHandler = exports.InvalidPDFException = exports.AbortException = exports.CMapCompressionType = exports.ImageKind = exports.FontType = exports.AnnotationType = exports.AnnotationFlag = exports.AnnotationFieldFlag = exports.AnnotationBorderStyleType = exports.UNSUPPORTED_FEATURES = exports.VerbosityLevel = exports.OPS = exports.IDENTITY_MATRIX = exports.FONT_IDENTITY_MATRIX = undefined;
__w_pdfjs_require__(21);
var _streams_polyfill = __w_pdfjs_require__(22);
var _streams_polyfill = __w_pdfjs_require__(23);
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
const NativeImageDecoding = {
@ -627,6 +627,29 @@ function isEvalSupported() {
return false;
}
}
function getInheritableProperty({ dict, key, getArray = false, stopWhenFound = true }) {
const LOOP_LIMIT = 100;
let loopCount = 0;
let values;
while (dict) {
const value = getArray ? dict.getArray(key) : dict.get(key);
if (value !== undefined) {
if (stopWhenFound) {
return value;
}
if (!values) {
values = [];
}
values.push(value);
}
if (++loopCount > LOOP_LIMIT) {
warn(`getInheritableProperty: maximum loop count exceeded for "${key}"`);
break;
}
dict = dict.get('Parent');
}
return values;
}
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = function UtilClosure() {
function Util() {}
@ -742,15 +765,6 @@ var Util = function UtilClosure() {
obj1[key] = obj2[key];
}
};
Util.getInheritableProperty = function Util_getInheritableProperty(dict, name, getArray) {
while (dict && !dict.has(name)) {
dict = dict.get('Parent');
}
if (!dict) {
return null;
}
return getArray ? dict.getArray(name) : dict.get(name);
};
Util.inherit = function Util_inherit(sub, base, prototype) {
sub.prototype = Object.create(base.prototype);
sub.prototype.constructor = sub;
@ -1349,6 +1363,7 @@ exports.createBlob = createBlob;
exports.createPromiseCapability = createPromiseCapability;
exports.createObjectURL = createObjectURL;
exports.deprecated = deprecated;
exports.getInheritableProperty = getInheritableProperty;
exports.getLookupTableFactory = getLookupTableFactory;
exports.getVerbosityLevel = getVerbosityLevel;
exports.info = info;
@ -3606,13 +3621,13 @@ var _util = __w_pdfjs_require__(0);
var _primitives = __w_pdfjs_require__(1);
var _ccitt_stream = __w_pdfjs_require__(26);
var _ccitt_stream = __w_pdfjs_require__(27);
var _jbig2_stream = __w_pdfjs_require__(27);
var _jbig2_stream = __w_pdfjs_require__(28);
var _jpeg_stream = __w_pdfjs_require__(6);
var _jpx_stream = __w_pdfjs_require__(30);
var _jpx_stream = __w_pdfjs_require__(31);
const MAX_LENGTH_TO_CACHE = 1000;
const MAX_ADLER32_LENGTH = 5552;
@ -4598,7 +4613,7 @@ var _stream = __w_pdfjs_require__(2);
var _primitives = __w_pdfjs_require__(1);
var _jpg = __w_pdfjs_require__(29);
var _jpg = __w_pdfjs_require__(30);
let JpegStream = function JpegStreamClosure() {
function JpegStream(stream, maybeLength, dict, params) {
@ -10648,16 +10663,26 @@ var Catalog = function CatalogClosure() {
return;
}
count = currentNode.get('Count');
var objId = currentNode.objId;
if (objId && !pageKidsCountCache.has(objId)) {
pageKidsCountCache.put(objId, count);
}
if (currentPageIndex + count <= pageIndex) {
currentPageIndex += count;
continue;
if (Number.isInteger(count) && count >= 0) {
var objId = currentNode.objId;
if (objId && !pageKidsCountCache.has(objId)) {
pageKidsCountCache.put(objId, count);
}
if (currentPageIndex + count <= pageIndex) {
currentPageIndex += count;
continue;
}
}
var kids = currentNode.get('Kids');
if (!Array.isArray(kids)) {
if ((0, _primitives.isName)(currentNode.get('Type'), 'Page') || !currentNode.has('Type') && currentNode.has('Contents')) {
if (currentPageIndex === pageIndex) {
capability.resolve([currentNode, null]);
return;
}
currentPageIndex++;
continue;
}
capability.reject(new _util.FormatError('page dictionary kids object is not an array'));
return;
}
@ -10706,11 +10731,14 @@ var Catalog = function CatalogClosure() {
if (!(0, _primitives.isRef)(kid)) {
throw new _util.FormatError('kid must be a Ref.');
}
if (kid.num === kidRef.num) {
if ((0, _primitives.isRefsEqual)(kid, kidRef)) {
found = true;
break;
}
kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
if (!(0, _primitives.isDict)(kid)) {
throw new _util.FormatError('kid node must be a Dict.');
}
if (kid.has('Count')) {
var count = kid.get('Count');
total += count;
@ -15884,7 +15912,7 @@ exports.CFFCompiler = exports.CFFPrivateDict = exports.CFFTopDict = exports.CFFC
var _util = __w_pdfjs_require__(0);
var _charsets = __w_pdfjs_require__(35);
var _charsets = __w_pdfjs_require__(36);
var _encodings = __w_pdfjs_require__(4);
@ -20026,7 +20054,7 @@ var _util = __w_pdfjs_require__(0);
var _primitives = __w_pdfjs_require__(1);
var _ps_parser = __w_pdfjs_require__(41);
var _ps_parser = __w_pdfjs_require__(42);
let IsEvalSupportedCached = {
get value() {
@ -21073,8 +21101,8 @@ exports.PostScriptCompiler = PostScriptCompiler;
"use strict";
var pdfjsVersion = '2.0.402';
var pdfjsBuild = '401f3a9d';
var pdfjsVersion = '2.0.447';
var pdfjsBuild = 'c0b22da0';
var pdfjsCoreWorker = __w_pdfjs_require__(20);
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
@ -21092,9 +21120,9 @@ exports.WorkerMessageHandler = exports.WorkerTask = undefined;
var _util = __w_pdfjs_require__(0);
var _pdf_manager = __w_pdfjs_require__(24);
var _pdf_manager = __w_pdfjs_require__(25);
var _is_node = __w_pdfjs_require__(44);
var _is_node = __w_pdfjs_require__(45);
var _is_node2 = _interopRequireDefault(_is_node);
@ -21275,7 +21303,7 @@ var WorkerMessageHandler = {
var cancelXHRs = null;
var WorkerTasks = [];
let apiVersion = docParams.apiVersion;
let workerVersion = '2.0.402';
let workerVersion = '2.0.447';
if (apiVersion !== null && apiVersion !== workerVersion) {
throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
}
@ -21462,7 +21490,7 @@ var WorkerMessageHandler = {
ensureNotTerminated();
var evaluatorOptions = {
forceDataSchema: data.disableCreateObjectURL,
maxImageSize: data.maxImageSize === undefined ? -1 : data.maxImageSize,
maxImageSize: data.maxImageSize,
disableFontFace: data.disableFontFace,
nativeImageDecoderSupport: data.nativeImageDecoderSupport,
ignoreErrors: data.ignoreErrors,
@ -21665,6 +21693,7 @@ exports.WorkerMessageHandler = WorkerMessageHandler;
"use strict";
const globalScope = __w_pdfjs_require__(22);
;
/***/ }),
@ -21674,6 +21703,15 @@ exports.WorkerMessageHandler = WorkerMessageHandler;
"use strict";
module.exports = typeof window !== 'undefined' && window.Math === Math ? window : typeof global !== 'undefined' && global.Math === Math ? global : typeof self !== 'undefined' && self.Math === Math ? self : {};
/***/ }),
/* 23 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
let isReadableStreamSupported = false;
if (typeof ReadableStream !== 'undefined') {
try {
@ -21688,11 +21726,11 @@ if (typeof ReadableStream !== 'undefined') {
if (isReadableStreamSupported) {
exports.ReadableStream = ReadableStream;
} else {
exports.ReadableStream = __w_pdfjs_require__(23).ReadableStream;
exports.ReadableStream = __w_pdfjs_require__(24).ReadableStream;
}
/***/ }),
/* 23 */
/* 24 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -24708,7 +24746,7 @@ if (isReadableStreamSupported) {
}]));
/***/ }),
/* 24 */
/* 25 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -24723,7 +24761,7 @@ var _util = __w_pdfjs_require__(0);
var _chunked_stream = __w_pdfjs_require__(9);
var _document = __w_pdfjs_require__(25);
var _document = __w_pdfjs_require__(26);
var _stream = __w_pdfjs_require__(2);
@ -24892,7 +24930,7 @@ exports.LocalPdfManager = LocalPdfManager;
exports.NetworkPdfManager = NetworkPdfManager;
/***/ }),
/* 25 */
/* 26 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -24911,7 +24949,7 @@ var _util = __w_pdfjs_require__(0);
var _stream = __w_pdfjs_require__(2);
var _annotation = __w_pdfjs_require__(31);
var _annotation = __w_pdfjs_require__(32);
var _crypto = __w_pdfjs_require__(14);
@ -24919,7 +24957,7 @@ var _parser = __w_pdfjs_require__(5);
var _operator_list = __w_pdfjs_require__(7);
var _evaluator = __w_pdfjs_require__(32);
var _evaluator = __w_pdfjs_require__(33);
var _function = __w_pdfjs_require__(18);
@ -24949,59 +24987,43 @@ var Page = function PageClosure() {
};
}
Page.prototype = {
getPageProp: function Page_getPageProp(key) {
return this.pageDict.get(key);
},
getInheritedPageProp: function Page_getInheritedPageProp(key, getArray) {
var dict = this.pageDict,
valueArray = null,
loopCount = 0;
var MAX_LOOP_COUNT = 100;
getArray = getArray || false;
while (dict) {
var value = getArray ? dict.getArray(key) : dict.get(key);
if (value !== undefined) {
if (!valueArray) {
valueArray = [];
}
valueArray.push(value);
}
if (++loopCount > MAX_LOOP_COUNT) {
(0, _util.warn)('getInheritedPageProp: maximum loop count exceeded for ' + key);
return valueArray ? valueArray[0] : undefined;
}
dict = dict.get('Parent');
_getInheritableProperty(key, getArray = false) {
let value = (0, _util.getInheritableProperty)({
dict: this.pageDict,
key,
getArray,
stopWhenFound: false
});
if (!Array.isArray(value)) {
return value;
}
if (!valueArray) {
return undefined;
if (value.length === 1 || !(0, _primitives.isDict)(value[0])) {
return value[0];
}
if (valueArray.length === 1 || !(0, _primitives.isDict)(valueArray[0])) {
return valueArray[0];
}
return _primitives.Dict.merge(this.xref, valueArray);
return _primitives.Dict.merge(this.xref, value);
},
get content() {
return this.getPageProp('Contents');
return this.pageDict.get('Contents');
},
get resources() {
return (0, _util.shadow)(this, 'resources', this.getInheritedPageProp('Resources') || _primitives.Dict.empty);
return (0, _util.shadow)(this, 'resources', this._getInheritableProperty('Resources') || _primitives.Dict.empty);
},
get mediaBox() {
var mediaBox = this.getInheritedPageProp('MediaBox', true);
var mediaBox = this._getInheritableProperty('MediaBox', true);
if (!Array.isArray(mediaBox) || mediaBox.length !== 4) {
return (0, _util.shadow)(this, 'mediaBox', LETTER_SIZE_MEDIABOX);
}
return (0, _util.shadow)(this, 'mediaBox', mediaBox);
},
get cropBox() {
var cropBox = this.getInheritedPageProp('CropBox', true);
var cropBox = this._getInheritableProperty('CropBox', true);
if (!Array.isArray(cropBox) || cropBox.length !== 4) {
return (0, _util.shadow)(this, 'cropBox', this.mediaBox);
}
return (0, _util.shadow)(this, 'cropBox', cropBox);
},
get userUnit() {
var obj = this.getPageProp('UserUnit');
var obj = this.pageDict.get('UserUnit');
if (!(0, _util.isNum)(obj) || obj <= 0) {
obj = DEFAULT_USER_UNIT;
}
@ -25017,7 +25039,7 @@ var Page = function PageClosure() {
return (0, _util.shadow)(this, 'view', intersection || mediaBox);
},
get rotate() {
var rotate = this.getInheritedPageProp('Rotate') || 0;
var rotate = this._getInheritableProperty('Rotate') || 0;
if (rotate % 90 !== 0) {
rotate = 0;
} else if (rotate >= 360) {
@ -25149,7 +25171,7 @@ var Page = function PageClosure() {
},
get annotations() {
var annotations = [];
var annotationRefs = this.getInheritedPageProp('Annots') || [];
var annotationRefs = this._getInheritableProperty('Annots') || [];
for (var i = 0, n = annotationRefs.length; i < n; ++i) {
var annotationRef = annotationRefs[i];
var annotation = _annotation.AnnotationFactory.create(this.xref, annotationRef, this.pdfManager, this.idFactory);
@ -25415,7 +25437,7 @@ exports.Page = Page;
exports.PDFDocument = PDFDocument;
/***/ }),
/* 26 */
/* 27 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -25472,7 +25494,7 @@ var CCITTFaxStream = function CCITTFaxStreamClosure() {
exports.CCITTFaxStream = CCITTFaxStream;
/***/ }),
/* 27 */
/* 28 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -25487,7 +25509,7 @@ var _primitives = __w_pdfjs_require__(1);
var _stream = __w_pdfjs_require__(2);
var _jbig = __w_pdfjs_require__(28);
var _jbig = __w_pdfjs_require__(29);
var _util = __w_pdfjs_require__(0);
@ -25543,7 +25565,7 @@ let Jbig2Stream = function Jbig2StreamClosure() {
exports.Jbig2Stream = Jbig2Stream;
/***/ }),
/* 28 */
/* 29 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -27312,7 +27334,7 @@ var Jbig2Image = function Jbig2ImageClosure() {
exports.Jbig2Image = Jbig2Image;
/***/ }),
/* 29 */
/* 30 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -28268,7 +28290,7 @@ var JpegImage = function JpegImageClosure() {
exports.JpegImage = JpegImage;
/***/ }),
/* 30 */
/* 31 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -28343,7 +28365,7 @@ let JpxStream = function JpxStreamClosure() {
exports.JpxStream = JpxStream;
/***/ }),
/* 31 */
/* 32 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -28389,7 +28411,10 @@ class AnnotationFactory {
case 'Text':
return new TextAnnotation(parameters);
case 'Widget':
let fieldType = _util.Util.getInheritableProperty(dict, 'FT');
let fieldType = (0, _util.getInheritableProperty)({
dict,
key: 'FT'
});
fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
switch (fieldType) {
case 'Tx':
@ -28697,13 +28722,29 @@ class WidgetAnnotation extends Annotation {
let data = this.data;
data.annotationType = _util.AnnotationType.WIDGET;
data.fieldName = this._constructFieldName(dict);
data.fieldValue = _util.Util.getInheritableProperty(dict, 'V', true);
data.fieldValue = (0, _util.getInheritableProperty)({
dict,
key: 'V',
getArray: true
});
data.alternativeText = (0, _util.stringToPDFString)(dict.get('TU') || '');
data.defaultAppearance = _util.Util.getInheritableProperty(dict, 'DA') || '';
let fieldType = _util.Util.getInheritableProperty(dict, 'FT');
data.defaultAppearance = (0, _util.getInheritableProperty)({
dict,
key: 'DA'
}) || '';
let fieldType = (0, _util.getInheritableProperty)({
dict,
key: 'FT'
});
data.fieldType = (0, _primitives.isName)(fieldType) ? fieldType.name : null;
this.fieldResources = _util.Util.getInheritableProperty(dict, 'DR') || _primitives.Dict.empty;
data.fieldFlags = _util.Util.getInheritableProperty(dict, 'Ff');
this.fieldResources = (0, _util.getInheritableProperty)({
dict,
key: 'DR'
}) || _primitives.Dict.empty;
data.fieldFlags = (0, _util.getInheritableProperty)({
dict,
key: 'Ff'
});
if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) {
data.fieldFlags = 0;
}
@ -28749,13 +28790,20 @@ class WidgetAnnotation extends Annotation {
class TextWidgetAnnotation extends WidgetAnnotation {
constructor(params) {
super(params);
const dict = params.dict;
this.data.fieldValue = (0, _util.stringToPDFString)(this.data.fieldValue || '');
let alignment = _util.Util.getInheritableProperty(params.dict, 'Q');
let alignment = (0, _util.getInheritableProperty)({
dict,
key: 'Q'
});
if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) {
alignment = null;
}
this.data.textAlignment = alignment;
let maximumLength = _util.Util.getInheritableProperty(params.dict, 'MaxLen');
let maximumLength = (0, _util.getInheritableProperty)({
dict,
key: 'MaxLen'
});
if (!Number.isInteger(maximumLength) || maximumLength < 0) {
maximumLength = null;
}
@ -28845,7 +28893,10 @@ class ChoiceWidgetAnnotation extends WidgetAnnotation {
constructor(params) {
super(params);
this.data.options = [];
let options = _util.Util.getInheritableProperty(params.dict, 'Opt');
let options = (0, _util.getInheritableProperty)({
dict: params.dict,
key: 'Opt'
});
if (Array.isArray(options)) {
let xref = params.xref;
for (let i = 0, ii = options.length; i < ii; i++) {
@ -29013,7 +29064,7 @@ exports.AnnotationBorderStyle = AnnotationBorderStyle;
exports.AnnotationFactory = AnnotationFactory;
/***/ }),
/* 32 */
/* 33 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -29026,13 +29077,13 @@ exports.PartialEvaluator = undefined;
var _util = __w_pdfjs_require__(0);
var _cmap = __w_pdfjs_require__(33);
var _cmap = __w_pdfjs_require__(34);
var _stream = __w_pdfjs_require__(2);
var _primitives = __w_pdfjs_require__(1);
var _fonts = __w_pdfjs_require__(34);
var _fonts = __w_pdfjs_require__(35);
var _encodings = __w_pdfjs_require__(4);
@ -29040,27 +29091,27 @@ var _unicode = __w_pdfjs_require__(17);
var _standard_fonts = __w_pdfjs_require__(16);
var _pattern = __w_pdfjs_require__(38);
var _pattern = __w_pdfjs_require__(39);
var _parser = __w_pdfjs_require__(5);
var _bidi = __w_pdfjs_require__(39);
var _bidi = __w_pdfjs_require__(40);
var _colorspace = __w_pdfjs_require__(3);
var _glyphlist = __w_pdfjs_require__(8);
var _metrics = __w_pdfjs_require__(40);
var _metrics = __w_pdfjs_require__(41);
var _function = __w_pdfjs_require__(18);
var _jpeg_stream = __w_pdfjs_require__(6);
var _murmurhash = __w_pdfjs_require__(42);
var _murmurhash = __w_pdfjs_require__(43);
var _operator_list = __w_pdfjs_require__(7);
var _image = __w_pdfjs_require__(43);
var _image = __w_pdfjs_require__(44);
var PartialEvaluator = function PartialEvaluatorClosure() {
const DefaultPartialEvaluatorOptions = {
@ -31707,7 +31758,7 @@ var EvaluatorPreprocessor = function EvaluatorPreprocessorClosure() {
exports.PartialEvaluator = PartialEvaluator;
/***/ }),
/* 33 */
/* 34 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -32422,7 +32473,7 @@ exports.IdentityCMap = IdentityCMap;
exports.CMapFactory = CMapFactory;
/***/ }),
/* 34 */
/* 35 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -32445,11 +32496,11 @@ var _standard_fonts = __w_pdfjs_require__(16);
var _unicode = __w_pdfjs_require__(17);
var _font_renderer = __w_pdfjs_require__(36);
var _font_renderer = __w_pdfjs_require__(37);
var _stream = __w_pdfjs_require__(2);
var _type1_parser = __w_pdfjs_require__(37);
var _type1_parser = __w_pdfjs_require__(38);
var PRIVATE_USE_OFFSET_START = 0xE000;
var PRIVATE_USE_OFFSET_END = 0xF8FF;
@ -34969,7 +35020,7 @@ exports.ProblematicCharRanges = ProblematicCharRanges;
exports.getFontType = getFontType;
/***/ }),
/* 35 */
/* 36 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -34986,7 +35037,7 @@ exports.ExpertCharset = ExpertCharset;
exports.ExpertSubsetCharset = ExpertSubsetCharset;
/***/ }),
/* 36 */
/* 37 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -35726,7 +35777,7 @@ var FontRendererFactory = function FontRendererFactoryClosure() {
exports.FontRendererFactory = FontRendererFactory;
/***/ }),
/* 37 */
/* 38 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -36289,7 +36340,7 @@ var Type1Parser = function Type1ParserClosure() {
exports.Type1Parser = Type1Parser;
/***/ }),
/* 38 */
/* 39 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -37079,7 +37130,7 @@ exports.Pattern = Pattern;
exports.getTilingPatternIR = getTilingPatternIR;
/***/ }),
/* 39 */
/* 40 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -37324,7 +37375,7 @@ function bidi(str, startLevel, vertical) {
exports.bidi = bidi;
/***/ }),
/* 40 */
/* 41 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -40278,7 +40329,7 @@ var getMetrics = (0, _util.getLookupTableFactory)(function (t) {
exports.getMetrics = getMetrics;
/***/ }),
/* 41 */
/* 42 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -40482,7 +40533,7 @@ exports.PostScriptLexer = PostScriptLexer;
exports.PostScriptParser = PostScriptParser;
/***/ }),
/* 42 */
/* 43 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -40600,7 +40651,7 @@ var MurmurHash3_64 = function MurmurHash3_64Closure(seed) {
exports.MurmurHash3_64 = MurmurHash3_64;
/***/ }),
/* 43 */
/* 44 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";
@ -41124,7 +41175,7 @@ var PDFImage = function PDFImageClosure() {
exports.PDFImage = PDFImage;
/***/ }),
/* 44 */
/* 45 */
/***/ (function(module, exports, __w_pdfjs_require__) {
"use strict";

Просмотреть файл

@ -329,6 +329,13 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="row">
<span data-l10n-id="document_properties_page_count">Page Count:</span> <p id="pageCountField">-</p>
</div>
<div class="row">
<span data-l10n-id="document_properties_page_size">Page Size:</span>
<p>
<span id="pageSizeFieldMM">-</span><br>
<span id="pageSizeFieldInch">-</span>
</p>
</div>
<div class="buttonRow">
<button id="documentPropertiesClose" class="overlayButton"><span data-l10n-id="document_properties_close">Close</span></button>
</div>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -21,7 +21,6 @@ add_task(async function test() {
await ContentTask.spawn(newTabBrowser, null, async function() {
// Overall sanity tests
Assert.ok(content.document.querySelector("div#viewer"), "document content has viewer UI");
Assert.ok("PDFJS" in content.wrappedJSObject, "window content has PDFJS object");
// Sidebar: open
var sidebar = content.document.querySelector("button#sidebarToggle"),

Просмотреть файл

@ -158,7 +158,6 @@ add_task(async function test() {
await ContentTask.spawn(newTabBrowser, null, async function() {
// Check if PDF is opened with internal viewer
Assert.ok(content.document.querySelector("div#viewer"), "document content has viewer UI");
Assert.ok("PDFJS" in content.wrappedJSObject, "window content has PDFJS object");
});
await ContentTask.spawn(newTabBrowser, null, contentSetUp);

Просмотреть файл

@ -21,7 +21,6 @@ add_task(async function test() {
await ContentTask.spawn(browser, null, async function() {
Assert.ok(content.document.querySelector("div#viewer"), "document content has viewer UI");
Assert.ok("PDFJS" in content.wrappedJSObject, "window content has PDFJS object");
// open sidebar
var sidebar = content.document.querySelector("button#sidebarToggle");

Просмотреть файл

@ -91,7 +91,6 @@ add_task(async function test() {
// check that PDF is opened with internal viewer
Assert.ok(content.document.querySelector("div#viewer"), "document content has viewer UI");
Assert.ok("PDFJS" in content.wrappedJSObject, "window content has PDFJS object");
let initialWidth, previousWidth;
initialWidth = previousWidth =

Просмотреть файл

@ -0,0 +1,23 @@
Backport cxx14 default dialect flag from clang 6.0.0 trunk to 5.0.1
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- a/clang/lib/Frontend/CompilerInvocation.cpp (revision 320871)
+++ b/clang/lib/Frontend/CompilerInvocation.cpp (working copy)
@@ -1690,11 +1690,11 @@
break;
case InputKind::CXX:
case InputKind::ObjCXX:
- // The PS4 uses C++11 as the default C++ standard.
- if (T.isPS4())
- LangStd = LangStandard::lang_gnucxx11;
- else
- LangStd = LangStandard::lang_gnucxx98;
+#if defined(CLANG_DEFAULT_STD_CXX)
+ LangStd = CLANG_DEFAULT_STD_CXX;
+#else
+ LangStd = LangStandard::lang_gnucxx14;
+#endif
break;
case InputKind::RenderScript:
LangStd = LangStandard::lang_c99;

Просмотреть файл

@ -15,5 +15,8 @@
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc"
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"patches": [
"clang-tidy-cxx14.patch"
]
}

Просмотреть файл

@ -23,6 +23,7 @@
"patches": [
"llvm-debug-frame-for-5.patch",
"compiler-rt-cross-compile.patch",
"compiler-rt-no-codesign.patch"
"compiler-rt-no-codesign.patch",
"clang-tidy-cxx14.patch"
]
}

Просмотреть файл

@ -12,5 +12,8 @@
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
"python_path": "c:/mozilla-build/python/python.exe",
"cc": "cl.exe",
"cxx": "cl.exe"
"cxx": "cl.exe",
"patches": [
"clang-tidy-cxx14.patch"
]
}

Просмотреть файл

@ -13,5 +13,8 @@
"python_path": "c:/mozilla-build/python/python.exe",
"cc": "cl.exe",
"cxx": "cl.exe",
"ml": "ml64.exe"
"ml": "ml64.exe",
"patches": [
"clang-tidy-cxx14.patch"
]
}

Просмотреть файл

@ -256,6 +256,10 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, c_compiler):
@depends(c_compiler)
@imports('os')
def vc_path(c_compiler):
vc_path_env = os.environ.get('VC_PATH')
if vc_path_env:
return os.path.normpath(vc_path_env)
if c_compiler.type not in ('msvc', 'clang-cl'):
return
@ -283,8 +287,13 @@ def vc_path(c_compiler):
@depends(vc_path, c_compiler)
@checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
@imports('os')
@imports(_from='os.path', _import='isdir')
def dia_sdk_dir(vc_path, c_compiler):
dia_sdk_dir_env = os.environ.get('DIA_SDK_PATH')
if dia_sdk_dir_env:
return os.path.normpath(dia_sdk_dir_env)
if vc_path:
if c_compiler.version < '19.10':
path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')

Просмотреть файл

@ -1213,14 +1213,45 @@ body #output-container {
}
/*
* Make the arrow the same color and approximately the same size of the twisty icon.
* Should be properly fixed in https://bugzilla.mozilla.org/show_bug.cgi?id=1307937.
* Make console.group, exception and XHR message's arrow look the same as the arrow
* used in the ObjectInspector (same background-image, width, transition).
* Properties were copied from devtools/client/shared/components/reps/reps.css.
*/
.webconsole-output-wrapper .object-inspector.tree .tree-node .arrow {
.webconsole-output-wrapper img.collapse-button.arrow {
mask: url("chrome://devtools/skin/images/devtools-components/arrow.svg") no-repeat;
mask-size: 100%;
width: 9px;
height: 9px;
margin-block-start: 5px;
margin-inline-start: 4px;
margin-inline-end: 1px;
transform: rotate(-90deg);
transition: transform 0.125s ease;
}
/*
* We need to override the margin for group arrow in order to keep the alignment
* with the indent border.
*/
.webconsole-output-wrapper .message.startGroup img.collapse-button.arrow,
.webconsole-output-wrapper .message.startGroupCollapsed img.collapse-button.arrow {
margin-inline-start: 2px;
}
html[dir="rtl"] .webconsole-output-wrapper img.collapse-button.arrow:not(.expanded) {
transform: rotate(90deg);
}
.webconsole-output-wrapper img.collapse-button.arrow.expanded {
transform: rotate(0deg);
}
/* Apply the same color to both message arrows and ObjectInspector ones. */
.webconsole-output-wrapper .message img.arrow {
background-color: #AFA8AB;
}
.theme-dark .webconsole-output-wrapper .object-inspector.tree .tree-node .arrow {
.theme-dark .webconsole-output-wrapper .message img.arrow {
background-color: #7F7E81;
}

Просмотреть файл

@ -18,13 +18,13 @@ function CollapseButton(props) {
title = messageToggleDetails,
} = props;
let classes = ["theme-twisty"];
let classes = ["arrow", "collapse-button"];
if (open) {
classes.push("open");
classes.push("expanded");
}
return dom.a({
return dom.img({
className: classes.join(" "),
onClick,
title: title,

Просмотреть файл

@ -295,7 +295,7 @@ describe("ConsoleAPICall component:", () => {
const wrapper = render(ConsoleApiCall({ message, serviceContainer, open: true }));
expect(wrapper.find(".message-body").text()).toBe("bar");
expect(wrapper.find(".theme-twisty.open").length).toBe(1);
expect(wrapper.find(".collapse-button.expanded").length).toBe(1);
});
it("renders group with custom style", () => {
@ -335,7 +335,7 @@ describe("ConsoleAPICall component:", () => {
serviceContainer,
})
));
wrapper.find(".theme-twisty.open").simulate("click");
wrapper.find(".collapse-button.expanded").simulate("click");
let call = store.dispatch.getCall(0);
expect(call.args[0]).toEqual({
id: message.id,
@ -350,7 +350,7 @@ describe("ConsoleAPICall component:", () => {
serviceContainer,
})
));
wrapper.find(".theme-twisty").simulate("click");
wrapper.find(".collapse-button").simulate("click");
call = store.dispatch.getCall(1);
expect(call.args[0]).toEqual({
id: message.id,
@ -428,7 +428,7 @@ describe("ConsoleAPICall component:", () => {
const wrapper = render(ConsoleApiCall({ message, serviceContainer, open: false}));
expect(wrapper.find(".message-body").text()).toBe("foo");
expect(wrapper.find(".theme-twisty:not(.open)").length).toBe(1);
expect(wrapper.find(".collapse-button:not(.expanded)").length).toBe(1);
});
it("renders group with custom style", () => {

Просмотреть файл

@ -114,7 +114,7 @@ describe("PageError component:", () => {
const wrapper = render(PageError({ message, serviceContainer, open: true }));
// There should be a collapse button.
expect(wrapper.find(".theme-twisty.open").length).toBe(1);
expect(wrapper.find(".collapse-button.expanded").length).toBe(1);
// There should be five stacktrace items.
const frameLinks = wrapper.find(`.stack-trace span.frame-link`);
@ -134,7 +134,7 @@ describe("PageError component:", () => {
serviceContainer,
})
));
wrapper.find(".theme-twisty.open").simulate("click");
wrapper.find(".collapse-button.expanded").simulate("click");
let call = store.dispatch.getCall(0);
expect(call.args[0]).toEqual({
id: message.id,
@ -149,7 +149,7 @@ describe("PageError component:", () => {
serviceContainer,
})
));
wrapper.find(".theme-twisty").simulate("click");
wrapper.find(".collapse-button").simulate("click");
call = store.dispatch.getCall(1);
expect(call.args[0]).toEqual({
id: message.id,

Просмотреть файл

@ -286,7 +286,6 @@ skip-if = true # Bug 1404382
[browser_webconsole_ineffective_iframe_sandbox_warning.js]
[browser_webconsole_init.js]
[browser_webconsole_input_field_focus_on_panel_select.js]
skip-if = true # Bug 1405343
[browser_webconsole_input_focus.js]
[browser_webconsole_insecure_passwords_about_blank_web_console_warning.js]
[browser_webconsole_insecure_passwords_web_console_warning.js]

Просмотреть файл

@ -105,7 +105,7 @@ async function testGroupToggle({
visibleMessageIdsAfterExpand,
visibleMessageIdsAfterCollapse
}) {
let toggleArrow = node.querySelector(".theme-twisty");
let toggleArrow = node.querySelector(".collapse-button");
const isOpen = node2 => node2.classList.contains("open");
const assertVisibleMessageIds = (expanded) => {
let visibleMessageIds = store.getState().messages.visibleMessages;

Просмотреть файл

@ -3,35 +3,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// XXX Remove this when the file is migrated to the new frontend.
/* eslint-disable no-undef */
// Test that the JS input field is focused when the user switches back to the
// web console from other tools, see bug 891581.
"use strict";
const TEST_URI = "data:text/html;charset=utf8,<p>hello";
const TEST_URI = "data:text/html;charset=utf8,<p>Test console input focus";
add_task(async function() {
await loadTab(TEST_URI);
let hud = await openConsole();
hud.jsterm.clearOutput();
let hud = await openNewTabAndConsole(TEST_URI);
is(hud.jsterm.inputNode.hasAttribute("focused"), true,
"inputNode should be focused");
let inputNode = hud.jsterm.inputNode;
const filterInput = hud.ui.outputNode.querySelector(".text-filter");
hud.ui.filterBox.focus();
info("Focus after console is opened");
ok(hasFocus(inputNode), "input node is focused after console is opened");
is(hud.ui.filterBox.hasAttribute("focused"), true,
"filterBox should be focused");
filterInput.focus();
ok(hasFocus(filterInput), "filter input should be focused");
is(hud.jsterm.inputNode.hasAttribute("focused"), false,
"inputNode shouldn't be focused");
is(hasFocus(inputNode), false, "input node is not focused anymore");
info("Go to the inspector panel");
await openInspector();
hud = await openConsole();
is(hud.jsterm.inputNode.hasAttribute("focused"), true,
"inputNode should be focused");
info("Go back to the console");
await openConsole();
ok(hasFocus(inputNode), "input node is focused when coming from a different panel");
});

Просмотреть файл

@ -435,6 +435,17 @@ async function openDebugger(options = {}) {
return {target, toolbox, panel};
}
async function openInspector(options = {}) {
if (!options.tab) {
options.tab = gBrowser.selectedTab;
}
const target = TargetFactory.forTab(options.tab);
const toolbox = await gDevTools.showToolbox(target, "inspector");
return toolbox.getCurrentPanel();
}
/**
* Open the Web Console for the given tab, or the current one if none given.
*

Просмотреть файл

@ -49,6 +49,7 @@ function NewWebConsoleFrame(webConsoleOwner) {
this.window = this.owner.iframeWindow;
this._onToolboxPrefChanged = this._onToolboxPrefChanged.bind(this);
this._onPanelSelected = this._onPanelSelected.bind(this);
EventEmitter.decorate(this);
}
@ -228,6 +229,10 @@ NewWebConsoleFrame.prototype = {
this._onToolboxPrefChanged();
this._initShortcuts();
if (toolbox) {
toolbox.on("webconsole-selected", this._onPanelSelected);
}
},
_initShortcuts: function() {
@ -309,6 +314,15 @@ NewWebConsoleFrame.prototype = {
this.newConsoleOutput.dispatchTimestampsToggle(newValue);
},
/**
* Sets the focus to JavaScript input field when the web console tab is
* selected or when there is a split console present.
* @private
*/
_onPanelSelected: function() {
this.jsterm.focus();
},
/**
* Handler for the tabNavigated notification.
*

Просмотреть файл

@ -15,6 +15,7 @@
* [Code reviews](./contributing/code-reviews.md)
* [Filing good bugs](./contributing/filing-good-bugs.md)
* [Investigating performance issues](./contributing/performance.md)
* [Writing efficient React code](./contributing/react-performance-tips.md)
* [Automated tests](tests/README.md)
* Running tests
* [`xpcshell`](tests/xpcshell.md)

Просмотреть файл

@ -0,0 +1,527 @@
# Writing efficient React code
In this article we'll discuss about the various component types we can use, as
well as discuss some tips to make your React application faster.
## TL;DR tips
* Prefer props and state immutability and use `PureComponent` components as a default
* As a convention, the object reference should change **if and only if** the inner data
changes.
* Be careful to never use new instance of functions as props to a Component (it's fine to use
them as props to a DOM element).
* Be careful to not update a reference if the inner data doesn't change.
* [Always measure before optimizing](./performance.md) to have a real impact on
performance. And always measure _after_ optimizing too, to prove your change
had a real impact.
## How React renders normal components
### What's a normal component?
As a start let's discuss about how React renders normal plain components, that
don't use `shouldComponentUpdate`. What we call plain components here are either:
* classes that extend [`Component`](https://reactjs.org/docs/react-component.html)
```jsx
class Application extends React.Component {
render() {
return <div>{this.props.content}</div>;
}
}
```
* normal functions that take some `props` as parameter and return some JSX. We
call these functions either Stateless Components or Functional Components.
This is important to understand that these Stateless Components are _not_
especially optimized in React.
```jsx
function Application(props) {
return <div>{props.content}</div>;
}
```
These functions are equivalent to classes extending `Component`. In
the rest of the article we'll especially focus on the latter. Unless otherwise
stated everything about classes extending `Component` is also true for
Stateless/Functional Components.
#### Notes on the use of JSX
Because we don't use a build step in mozilla-central yet, some of our
tools don't use JSX and use [factories](https://reactjs.org/docs/react-api.html#createfactory)
instead:
```javascript
class Application extends React.Component {
render() {
return dom.div(null, this.props.content);
}
}
```
We'll use JSX in this documentation for more clarity but this is strictly
equivalent. You can read more on [React documentation](https://reactjs.org/docs/react-without-jsx.html).
### The first render
There's only one way to start a React application and trigger a first render:
calling `ReactDOM.render`:
```jsx
ReactDOM.render(
<Application content='Hello World!'/>,
document.getElementById('root')
);
```
React will call that component's `render` method, and then recursively call
every child's `render` method, generating a rendering tree and then a virtual
DOM tree. It will then render actual DOM elements to the specified container.
### Subsequent rerenders
There are several ways to trigger a rerender:
1. We call `ReactDOM.render` again with the same component.
```jsx
ReactDOM.render(
<Application content='Good Bye, Cruel World!'/>,
document.getElementById('root')
);
```
2. One component's state changes, through the use of [`setState`](https://reactjs.org/docs/react-component.html#setstate).
If the application is using Redux, this is how Redux-connected components
trigger updates too.
3. One component's props change. But note that this can't happen by itself, this
is always a consequence of the case 1 or 2 in one of its parents. So we'll
ignore this case for this chapter.
When one of these happens, just like the initial render, React will call that
component's `render` method, and then recursively call every child's `render`
method, but this time possibly with changed props compared to the previous render.
These recursive calls produce a new rendering tree. That's where React uses an
algorithm called _virtual diffing_ or
[_reconciliation_](https://reactjs.org/docs/reconciliation.html) to find the
minimal set of updates to apply to the DOM. This is good because the less
updates to the DOM the less work the browser has to do to reflow and repaint the
application.
### Main sources of performance issues
From this explanation we can gather that the main performance issues can
come from:
1. triggering the render process **too frequently**,
2. **expensive** render methods,
3. the reconciliation algorithm itself. The algorithm is O(n) according to React
authors, which means the processing duration increases linearly with **the number
of elements in the tree** we compare. So a larger tree means a longer time to
process.
Let's dive more into each one of these issues.
#### Do not render too often
A rerender will happen after calling `setState` to change the
local state.
Everything that's in the state should be used in `render`.
Anything in the state that's not used in `render` shouldn't be in the state, but
rather in an instance variable. This way you won't trigger an update if you
change some internal state that you don't want to reflect in the UI.
If you call `setState` from an event handler you may call it too often.
This is usually not a problem because React is smart enough to merge close
setState calls and trigger a rerender only once per frame. Yet if your `render`
is expensive (see below as well) this could lead to problems and you may want to
use `setTimeout` or other similar techniques to throttle the renders.
#### Keep `render` methods as lean as possible
When rendering a list, it's very common that we'll map this list to a list of
components. This can be costly and we might want to cut this list in several
chunks of items or to
[virtualize this list](https://reactjs.org/docs/optimizing-performance.html#virtualize-long-lists).
Although this is not always possible or easy.
Do not do heavy computations in your `render` methods. Rather do them before
setting the state, and set the state to the result of these computations.
Ideally `render` should be a direct mirror of the component's props and state.
Note that this rule also applies to the other methods called as part of the
rendering process: `componentWillUpdate` and `componentDidUpdate`. In
`componentDidUpdate` especially avoid synchronous reflows by getting DOM
measurements, and do not call `setState` as this would trigger yet another
update.
#### Help the reconciliation algorithm be efficient
The smaller the tree is, the faster the algorithm is. So it's
useful to limit the changes to a subtree of the full tree. Note that the use of
`shouldComponentUpdate` or `PureComponent` alleviates this issue by cutting off
entire branches from the rendering tree, [we discuss this in more details
below](shouldcomponentupdate-and-purecomponent-avoiding-renders-altogether).
Try to change the state as close as possible to where your UI
should change (close in the components tree).
Do not forget to [set `key` attributes when rendering a list of
things](https://reactjs.org/docs/lists-and-keys.html), which shouldn't be the
array's indices but something that identifies the item in a predictable, unique
and stable way. This helps the algorithm
a lot by skipping parts that likely haven't changed.
### More documentation
The React documentation has [a very well documented page](https://reactjs.org/docs/implementation-notes.html#mounting-as-a-recursive-process)
explaining the whole render and rerender process.
## `shouldComponentUpdate` and `PureComponent`: avoiding renders altogether
React has an optimized algorithm to apply changes. But the fastest algorithm is
an algorithm that isn't executed at all.
[React's own documentation about performance](https://reactjs.org/docs/optimizing-performance.html#shouldcomponentupdate-in-action)
is quite complete on this subject.
### Avoiding rerenders with `shouldComponentUpdate`
As the first step of a rerender process, React calls your component's
[`shouldComponentUpdate`](https://reactjs.org/docs/react-component.html#shouldcomponentupdate)
method with 2 parameters: the new props, and the new
state. If this method returns false, then React will skip the render process for this
component, **and its whole subtree**.
```jsx
class ComplexPanel extends React.Component {
// Note: this syntax, new but supported by Babel, automatically binds the
// method with the object instance.
onClick = () => {
this.setState({ detailsOpen: true });
}
// Return false to avoid a render
shouldComponentUpdate(nextProps, nextState) {
// Note: this works only if `summary` and `content` are primitive data
// (eg: string, number) or immutable data
// (keep reading to know more about this)
return nextProps.summary !== this.props.summary
|| nextProps.content !== this.props.content
|| nextState.detailsOpen !== this.state.detailsOpen;
}
render() {
return (
<div>
<ComplexSummary summary={this.props.summary} onClick={this.onClick}/>
{this.state.detailsOpen
? <ComplexContent content={this.props.content} />
: null}
</div>
);
}
}
```
__This is a very efficient way to improve your application speed__, because this
avoids everything: both calling render methods for this component _and_ the
whole subtree, and the reconciliation phase for this subtree.
Note that just like the `render` method, `shouldComponentUpdate` is called once
per render cycle, so it needs to be very lean and return as fast as possible. So
it should execute some cheap comparisons only.
### `PureComponent` and immutability
A very common implementation of `shouldComponentUpdate` is provided by React's
[`PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent):
it will shallowly check the new props and states for reference equality.
```jsx
class ComplexPanel extends React.PureComponent {
// Note: this syntax, new but supported by Babel, automatically binds the
// method with the object instance.
onClick = () => {
// Running this repeatidly won't render more than once.
this.setState({ detailsOpen: true });
}
render() {
return (
<div>
<ComplexSummary summary={this.props.summary} onClick={this.onClick}/>
{this.state.detailsOpen
? <ComplexContent content={this.props.content} />
: null}
</div>
);
}
}
```
This has a very important consequence: for non-primitive props and states, that is
objects and arrays that can be mutated without changing the reference itself,
PureComponent's inherited `shouldComponentUpdate` will yield wrong results and will
skip renders where it shouldn't.
So you're left with one of these two options:
* either implement your own `shouldComponentUpdate` in a `Component`
* or (__preferred__) decide to make all your data structure immutable.
The latter is recommended because:
* It's much simpler to think about.
* It's much faster to check for equality in `shouldComponentUpdate` and in other
places (like Redux' selectors).
Note you could technically implement your own `shouldComponentUpdate` in a
`PureComponent` but this is quite useless because `PureComponent` is nothing
more than `Component` with a default implementation for `shouldComponentUpdate`.
### About immutability
#### What it doesn't mean
It doesn't mean you need to enforce the immutability using a library like
[Immutable](https://github.com/facebook/immutable-js).
#### What it means
It means that once a structure exists, you don't mutate it.
**Everytime some data changes, the object reference must change as well**. This
means a new object or a new array needs to be created. This gives the nice
reverse guarantee: if the object reference has changed, the data has changed.
It's good to go one step further to get a **strict equivalence**: if the data
doesn't change, the object reference mustn't change. This isn't necessary for
your app to work, but this is a lot better for performance as this avoids
spurious rerenders.
Keep reading to learn how to proceed.
#### Keep your state objects simple
Updating your immutable state objects can be difficult if the objects used are
complex. That's why it's a good idea to keep the objects simple, especially keep
them not nested, so that you don't need to use a library like
[immutability-helper](https://github.com/kolodny/immutability-helper),
[updeep](https://github.com/substantial/updeep), or even
[Immutable](https://github.com/facebook/immutable-js). Be especially careful
with Immutable as it's easy to create performance problems by misusing
its API.
If you're using Redux ([see below as well](#a-few-words-about-redux)) this
advice applies to your individual reducers as well, even if Redux tools make
it easy to have a nested/combined state.
#### How to update an object
Updating an object is quite easy.
You must not change/add/delete inner properties directly:
```javascript
// Note that in the following examples we use the callback version
// of `setState` everywhere, because we build the new state from
// the current state.
// Please don't do this as this will likely induce bugs.
this.setState(state => {
state.stateObject.details = details;
return state;
});
// This is wrong too: `stateObject` is still mutated.
this.setState(({ stateObject }) => {
stateObject.details = details;
return { stateObject };
});
```
Instead **you must create a new object** for this property. In this example
we'll use the object spread operator, already implemented in Firefox, Chrome and Babel.
However here we take care to return the same object if it doesn't need an update. The
comparison happens inside the callback because it depends on the state as
well. This is a good thing to do so that the shallow equality check doesn't
return false if nothing changes.
```javascript
// Updating one property in the state
this.setState(({ stateObject }) => ({
stateObject: stateObject.content === newContent
? stateObject
: { ...stateObject, content: newContent },
});
// This is very similar if 2 properties need an update:
this.setState(({ stateObject1, stateObject2 }) => ({
stateObject1: stateObject1.content === newContent
? stateObject1
: { ...stateObject1, content: newContent },
stateObject2: stateObject2.details === newDetails
? stateObject2
: { ...stateObject2, details: newDetails },
});
// Or if one of the properties needs to update 2 of it's own properties:
this.setState(({ stateObject }) => ({
stateObject: stateObject.content === newContent && stateObject.details === newDetails
? stateObject
: { ...stateObject, content: newContent, details: newDetails },
});
```
Note that this isn't about the returned `state` object, but its properties.
The returned object is always merged into the current state, and React creates
a new component's state object at each update cycle.
#### How to update an array
Updating an array is easy too.
You must avoid methods that mutate the array like push/splice/pop/shift and you
must not change directly an item.
```javascript
// Please don't do this as this will likely induce bugs.
this.setState(({ stateArray }) => {
stateArray.push(newItem); // This is wrong
stateArray[1] = newItem; // This is wrong too
return { stateArray };
});
```
Instead here again you need to **create a new array instance**.
```javascript
// Adding an element is easy.
this.setState(({ stateArray }) => ({
stateArray: [...stateArray, newElement],
}));
this.setState(({ stateArray }) => {
// Removing an element is more involved.
const newArray = stateArray.filter(element => element !== removeElement);
// or
const newArray = [...stateArray.slice(0, index), ...stateArray.slice(index + 1)];
// or do what you want on a new clone:
const newArray = stateArray.slice();
return {
// Because we want to keep the old array if removeElement isn't in the
// filtered array, we compare the lengths.
// We still start a render phase because we call `setState`, but thanks to
// PureComponent's shouldComponentUpdate implementation we won't actually render.
stateArray: newArray.length === stateArray.length ? stateArray : newArray,
};
// You can also return a falsy value to avoid the render cycle at all:
return newArray.length === stateArray.length
? null
: { stateArray: newArray };
});
```
#### How to update Maps and Sets
The process is very similar for Maps and Sets. Here is a quick example:
```javascript
// For a Set
this.setState(({ stateSet }) => {
if (!stateSet.has(value)) {
stateSet = new Set(stateSet);
stateSet.add(value);
}
return { stateSet };
});
// For a Map
this.setState(({ stateMap }) => {
if (stateMap.get(key) !== value) {
stateMap = new Map(stateMap);
stateMap.set(key, value);
}
return { stateMap };
}));
```
#### How to update primitive values
Obviously, with primitive types like boolean, number or string, that are
comparable with the operator `===`, it's much easier:
```javascript
this.setState({
stateString: "new string",
stateNumber: 42,
stateBool: false,
});
```
Note that we don't use the callback version of `setState` here. That's because
for primitive values we don't need to use the previous state to generate a new
state.
#### A few words about Redux
When working with Redux, the rules stay the same, except all of this
happens in your reducers instead of in your components. With Redux comes the
function [`combineReducers`](https://redux.js.org/docs/api/combineReducers.html)
that obeys all the rules we outlined before while making it possible to have a
nested state.
### `shouldComponentUpdate` or `PureComponent`?
It is highly recommended to go the full **PureComponent + immutability** route,
instead of writing custom `shouldComponentUpdate` implementations for
components. This is more generic, more maintainable, less error-prone, faster.
Of course all rules have exceptions and you're free to implement a
`shouldComponentUpdate` method if you have specific cases to take care of.
### Some gotchas with `PureComponent`
Because `PureComponent` shallowly checks props and state, you need to take care
to not create a new reference for something that's otherwise identical. Some
common cases are:
* Using a new instance for a prop at each render cycle. Especially, do not use
a bound function or an anonymous function (both classic functions or
arrow functions) as a prop:
```jsx
render() {
return <MyComponent onUpdate={() => this.update()} />;
}
```
Each time the `render` method runs, a new function will be created, and in
`MyComponent`'s `shouldComponentUpdate` the shallow check will always fail
defeating its purpose.
* Using another reference for the same data. One very common example is the empty
array: if you use a new `[]` for each render, you won't skip render. A solution
is to reuse a common instance. Be careful as this can very well be hidden
within some complicated Redux reducers.
* A similar issue can arise if you use sets or maps. If you add an element in a
`Set` that's already in there, you don't need to return a new `Set` as it will be
identical.
* Be careful with array's methods, especially `map` or `filter`, as they always
return a new array. So even with the same inputs (same input array, same
function), you'll get a new output, even if it contains the same data. If
you're using Redux, [reselect](https://github.com/reactjs/reselect) is
recommended.
[memoize-immutable](https://github.com/memoize-immutable/memoize-immutable)
can be useful in some cases too.
## Diagnosing performance issues with some tooling
[You can read about it in the dedicated
page](./performance.md#diagnosing-performance-issues-in-react-based-applications).
## Breaking the rules: always measure first
You should generally follow these rules because they bring a consistent
performance in most cases.
However you may have specific cases that will need that you break the rules. In
that case the first thing to do is to **measure** using a profiler so that you
know where your problem are.
Then and only then you can decide to break the rules by using some mutable state
and/or custom `shouldComponentUpdate` implementation.
And remember to measure again after you did your changes, to check and prove
that your changes actually made an impact. Ideally you should always give links
to profiles when requesting a review for a performance patch.

Просмотреть файл

@ -1,59 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* The eventLoopLag actor emits "event-loop-lag" events when the event
* loop gets unresponsive. The event comes with a "time" property (the
* duration of the lag in milliseconds).
*/
const {Ci} = require("chrome");
const Services = require("Services");
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
const {Actor, ActorClassWithSpec} = require("devtools/shared/protocol");
const {eventLoopLagSpec} = require("devtools/shared/specs/eventlooplag");
exports.EventLoopLagActor = ActorClassWithSpec(eventLoopLagSpec, {
_observerAdded: false,
/**
* Start tracking the event loop lags.
*/
start: function() {
if (!this._observerAdded) {
Services.obs.addObserver(this, "event-loop-lag");
this._observerAdded = true;
}
return Services.appShell.startEventLoopLagTracking();
},
/**
* Stop tracking the event loop lags.
*/
stop: function() {
if (this._observerAdded) {
Services.obs.removeObserver(this, "event-loop-lag");
this._observerAdded = false;
}
Services.appShell.stopEventLoopLagTracking();
},
destroy: function() {
this.stop();
Actor.prototype.destroy.call(this);
},
// nsIObserver
observe: function(subject, topic, data) {
if (topic == "event-loop-lag") {
// Forward event loop lag event
this.emit("event-loop-lag", data);
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
});

Просмотреть файл

@ -34,7 +34,6 @@ DevToolsModules(
'emulation.js',
'environment.js',
'errordocs.js',
'eventlooplag.js',
'frame.js',
'framerate.js',
'gcli.js',

Просмотреть файл

@ -495,11 +495,6 @@ var DebuggerServer = {
constructor: "FramerateActor",
type: { tab: true }
});
this.registerModule("devtools/server/actors/eventlooplag", {
prefix: "eventLoopLag",
constructor: "EventLoopLagActor",
type: { tab: true }
});
this.registerModule("devtools/server/actors/reflow", {
prefix: "reflow",
constructor: "ReflowActor",

Просмотреть файл

@ -1,57 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test the eventLoopLag actor.
*/
"use strict";
function run_test() {
let {EventLoopLagFront} = require("devtools/shared/fronts/eventlooplag");
DebuggerServer.init();
DebuggerServer.registerAllActors();
// As seen in EventTracer.cpp
let threshold = 20;
let interval = 10;
let front;
let client = new DebuggerClient(DebuggerServer.connectPipe());
// Start tracking event loop lags.
client.connect().then(function() {
client.listTabs().then(function(resp) {
front = new EventLoopLagFront(client, resp);
front.start().then(success => {
Assert.ok(success);
front.once("event-loop-lag", gotLagEvent);
executeSoon(lag);
});
});
});
// Force a lag
function lag() {
let start = new Date();
let duration = threshold + interval + 1;
while (true) {
if (((new Date()) - start) > duration) {
break;
}
}
}
// Got a lag event. The test will time out if the actor
// fails to detect the lag.
function gotLagEvent(time) {
info("lag: " + time);
Assert.ok(time >= threshold);
front.stop().then(() => {
finishClient(client);
});
}
do_test_pending();
}

Просмотреть файл

@ -132,9 +132,6 @@ reason = bug 1104838
[test_conditional_breakpoint-01.js]
[test_conditional_breakpoint-02.js]
[test_conditional_breakpoint-03.js]
[test_eventlooplag_actor.js]
skip-if = true
reason = only ran on B2G
[test_listsources-01.js]
[test_listsources-02.js]
[test_listsources-03.js]

Просмотреть файл

@ -263,7 +263,7 @@ const isEventHandler = (listener) =>
const Services = require("Services");
const { describeNthCaller } = require("devtools/shared/platform/stack");
let loggingEnabled = true;
let loggingEnabled = false;
if (!isWorker) {
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");

Просмотреть файл

@ -1,15 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { eventLoopLagSpec } = require("devtools/shared/specs/eventlooplag");
exports.EventLoopLagFront = FrontClassWithSpec(eventLoopLagSpec, {
initialize: function(client, form) {
Front.prototype.initialize.call(this, client);
this.actorID = form.eventLoopLagActor;
this.manage(this);
},
});

Просмотреть файл

@ -15,7 +15,6 @@ DevToolsModules(
'csscoverage.js',
'device.js',
'emulation.js',
'eventlooplag.js',
'framerate.js',
'gcli.js',
'highlighters.js',

Просмотреть файл

@ -7,7 +7,7 @@
const Services = require("Services");
const defer = require("devtools/shared/defer");
const { describeNthCaller } = require("devtools/shared/platform/stack");
let loggingEnabled = true;
let loggingEnabled = false;
if (!isWorker) {
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");

Просмотреть файл

@ -1,31 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Arg, RetVal, generateActorSpec } = require("devtools/shared/protocol");
const eventLoopLagSpec = generateActorSpec({
typeName: "eventLoopLag",
events: {
"event-loop-lag": {
type: "event-loop-lag",
// duration of the lag in milliseconds.
time: Arg(0, "number")
}
},
methods: {
start: {
request: {},
response: {success: RetVal("number")}
},
stop: {
request: {},
response: {}
}
}
});
exports.eventLoopLagSpec = eventLoopLagSpec;

Просмотреть файл

@ -74,11 +74,6 @@ const Types = exports.__TypesForTests = [
spec: "devtools/shared/specs/environment",
front: null,
},
{
types: ["eventLoopLag"],
spec: "devtools/shared/specs/eventlooplag",
front: "devtools/shared/fronts/eventlooplag",
},
/* frame has old fashion client and no front */
{
types: ["frame"],

Просмотреть файл

@ -17,7 +17,6 @@ DevToolsModules(
'device.js',
'emulation.js',
'environment.js',
'eventlooplag.js',
'frame.js',
'framerate.js',
'gcli.js',

Просмотреть файл

@ -86,7 +86,6 @@ UNIFIED_SOURCES += [
'nsDocShellEditorData.cpp',
'nsDocShellEnumerator.cpp',
'nsDocShellLoadInfo.cpp',
'nsDocShellTransferableHooks.cpp',
'nsDocShellTreeOwner.cpp',
'nsDSURIContentListener.cpp',
'nsPingListener.cpp',

Просмотреть файл

@ -176,7 +176,6 @@
#include "nsDocShellEnumerator.h"
#include "nsDocShellLoadInfo.h"
#include "nsDocShellLoadTypes.h"
#include "nsDocShellTransferableHooks.h"
#include "nsDOMCID.h"
#include "nsDOMNavigationTiming.h"
#include "nsDSURIContentListener.h"
@ -629,11 +628,6 @@ nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
GetEditingSession(getter_AddRefs(es));
es.forget(aSink);
return *aSink ? NS_OK : NS_NOINTERFACE;
} else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) &&
NS_SUCCEEDED(EnsureTransferableHookData())) {
*aSink = mTransferableHookData;
NS_ADDREF((nsISupports*)*aSink);
return NS_OK;
} else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
nsIPresShell* shell = GetPresShell();
if (shell) {
@ -5510,8 +5504,6 @@ nsDocShell::Destroy()
mEditorData = nullptr;
mTransferableHookData = nullptr;
// Save the state of the current document, before destroying the window.
// This is needed to capture the state of a frameset when the new document
// causes the frameset to be destroyed...
@ -12999,18 +12991,6 @@ nsDocShell::EnsureEditorData()
return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
nsresult
nsDocShell::EnsureTransferableHookData()
{
MOZ_ASSERT(!mIsBeingDestroyed);
if (!mTransferableHookData) {
mTransferableHookData = new nsTransferableHookData();
}
return NS_OK;
}
nsresult
nsDocShell::EnsureFind()
{

Просмотреть файл

@ -74,7 +74,6 @@ typedef uint32_t ScreenOrientationInternal;
} // namespace dom
} // namespace mozilla
class nsIClipboardDragDropHookList;
class nsICommandManager;
class nsIContentViewer;
class nsIController;
@ -964,9 +963,6 @@ private: // data members
// Editor data, if this document is designMode or contentEditable.
nsAutoPtr<nsDocShellEditorData> mEditorData;
// Transferable hooks/callbacks
nsCOMPtr<nsIClipboardDragDropHookList> mTransferableHookData;
// Secure browser UI object
nsCOMPtr<nsISecureBrowserUI> mSecurityUI;

Просмотреть файл

@ -1,54 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDocShellTransferableHooks.h"
#include "nsIClipboardDragDropHooks.h"
#include "nsIClipboardDragDropHookList.h"
#include "nsArrayEnumerator.h"
nsTransferableHookData::nsTransferableHookData()
{
}
nsTransferableHookData::~nsTransferableHookData()
{
}
NS_IMPL_ISUPPORTS(nsTransferableHookData, nsIClipboardDragDropHookList)
NS_IMETHODIMP
nsTransferableHookData::AddClipboardDragDropHooks(
nsIClipboardDragDropHooks* aOverrides)
{
NS_ENSURE_ARG(aOverrides);
// don't let a hook be added more than once
if (mHookList.IndexOfObject(aOverrides) == -1) {
if (!mHookList.AppendObject(aOverrides)) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsTransferableHookData::RemoveClipboardDragDropHooks(
nsIClipboardDragDropHooks* aOverrides)
{
NS_ENSURE_ARG(aOverrides);
if (!mHookList.RemoveObject(aOverrides)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
nsTransferableHookData::GetHookEnumerator(nsISimpleEnumerator** aResult)
{
return NS_NewArrayEnumerator(aResult, mHookList);
}

Просмотреть файл

@ -1,28 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsDocShellTransferableHooks_h__
#define nsDocShellTransferableHooks_h__
#include "nsIClipboardDragDropHookList.h"
#include "nsCOMArray.h"
class nsIClipboardDragDropHooks;
class nsTransferableHookData : public nsIClipboardDragDropHookList
{
public:
nsTransferableHookData();
NS_DECL_ISUPPORTS
NS_DECL_NSICLIPBOARDDRAGDROPHOOKLIST
protected:
virtual ~nsTransferableHookData();
nsCOMArray<nsIClipboardDragDropHooks> mHookList;
};
#endif // nsDocShellTransferableHooks_h__

Просмотреть файл

@ -167,11 +167,8 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
Maybe<NonOwningAnimationTarget> pseudoElement =
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
if (pseudoElement) {
StyleBackendType backend = StyleBackendType::Servo;
EffectCompositor::MaybeUpdateCascadeResults(backend,
pseudoElement->mElement,
pseudoElement->mPseudoType,
aFrame->Style());
EffectCompositor::MaybeUpdateCascadeResults(pseudoElement->mElement,
pseudoElement->mPseudoType);
}
if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
@ -311,27 +308,26 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
eRestyle_CSSTransitions :
eRestyle_CSSAnimations;
if (mPresContext->StyleSet()->IsServo()) {
MOZ_ASSERT(NS_IsMainThread(),
"Restyle request during restyling should be requested only on "
"the main-thread. e.g. after the parallel traversal");
if (ServoStyleSet::IsInServoTraversal() || mIsInPreTraverse) {
MOZ_ASSERT(hint == eRestyle_CSSAnimations ||
hint == eRestyle_CSSTransitions);
MOZ_ASSERT(NS_IsMainThread(),
"Restyle request during restyling should be requested only on "
"the main-thread. e.g. after the parallel traversal");
if (ServoStyleSet::IsInServoTraversal() || mIsInPreTraverse) {
MOZ_ASSERT(hint == eRestyle_CSSAnimations ||
hint == eRestyle_CSSTransitions);
// We can't call Servo_NoteExplicitHints here since AtomicRefCell does not
// allow us mutate ElementData of the |aElement| in SequentialTask.
// Instead we call Servo_NoteExplicitHints for the element in PreTraverse()
// which will be called right before the second traversal that we do for
// updating CSS animations.
// In that case PreTraverse() will return true so that we know to do the
// second traversal so we don't need to post any restyle requests to the
// PresShell.
return;
} else {
MOZ_ASSERT(!mPresContext->RestyleManager()->IsInStyleRefresh());
}
// We can't call Servo_NoteExplicitHints here since AtomicRefCell does not
// allow us mutate ElementData of the |aElement| in SequentialTask.
// Instead we call Servo_NoteExplicitHints for the element in PreTraverse()
// which will be called right before the second traversal that we do for
// updating CSS animations.
// In that case PreTraverse() will return true so that we know to do the
// second traversal so we don't need to post any restyle requests to the
// PresShell.
return;
}
MOZ_ASSERT(!mPresContext->RestyleManager()->IsInStyleRefresh());
mPresContext->PresShell()->RestyleForAnimation(element, hint);
}
@ -544,18 +540,15 @@ EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame,
}
/* static */ void
EffectCompositor::MaybeUpdateCascadeResults(StyleBackendType aBackendType,
Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle)
EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
CSSPseudoElementType aPseudoType)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects || !effects->CascadeNeedsUpdate()) {
return;
}
UpdateCascadeResults(aBackendType, *effects, aElement, aPseudoType,
aComputedStyle);
UpdateCascadeResults(*effects, aElement, aPseudoType);
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
}
@ -599,22 +592,16 @@ EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
/* static */ nsCSSPropertyIDSet
EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType,
EffectSet& aEffectSet,
EffectCompositor::GetOverriddenProperties(EffectSet& aEffectSet,
Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle)
CSSPseudoElementType aPseudoType)
{
MOZ_ASSERT(aBackendType != StyleBackendType::Servo || aElement,
"Should have an element to get style data from if we are using"
" the Servo backend");
MOZ_ASSERT(aElement, "Should have an element to get style data from");
nsCSSPropertyIDSet result;
Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
if (aBackendType == StyleBackendType::Gecko && !aComputedStyle) {
MOZ_CRASH("old style system disabled");
} else if (aBackendType == StyleBackendType::Servo && !elementToRestyle) {
if (!elementToRestyle) {
return result;
}
@ -642,29 +629,16 @@ EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType,
return result;
}
switch (aBackendType) {
case StyleBackendType::Servo:
Servo_GetProperties_Overriding_Animation(elementToRestyle,
&propertiesToTrack,
&result);
break;
case StyleBackendType::Gecko:
MOZ_CRASH("old style system disabled");
break;
default:
MOZ_ASSERT_UNREACHABLE("Unsupported style backend");
}
Servo_GetProperties_Overriding_Animation(elementToRestyle,
&propertiesToTrack,
&result);
return result;
}
/* static */ void
EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType,
EffectSet& aEffectSet,
EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle)
CSSPseudoElementType aPseudoType)
{
MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
"Effect set should correspond to the specified (pseudo-)element");
@ -686,10 +660,7 @@ EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType,
// since we will apply other properties on the main thread where the usual
// cascade applies.
nsCSSPropertyIDSet overriddenProperties =
GetOverriddenProperties(aBackendType,
aEffectSet,
aElement, aPseudoType,
aComputedStyle);
GetOverriddenProperties(aEffectSet, aElement, aPseudoType);
// Returns a bitset the represents which properties from
// LayerAnimationInfo::sRecords are present in |aPropertySet|.
@ -812,7 +783,6 @@ EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
Element* aRoot)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
MOZ_ASSERT(!aRoot || nsContentUtils::GetPresShellForContent(aRoot),
"Traversal root, if provided, should be bound to a display "
"document");
@ -898,10 +868,7 @@ EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
}
for (const NonOwningAnimationTarget& target: elementsWithCascadeUpdates) {
MaybeUpdateCascadeResults(StyleBackendType::Servo,
target.mElement,
target.mPseudoType,
nullptr);
MaybeUpdateCascadeResults(target.mElement, target.mPseudoType);
}
elementsWithCascadeUpdates.Clear();
@ -961,7 +928,6 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
CSSPseudoElementType aPseudoType)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
// If |aElement|'s document does not have a pres shell, e.g. it is document
// without a browsing context such as we might get from an XMLHttpRequest, we
@ -1010,9 +976,7 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (effects) {
MaybeUpdateCascadeResults(StyleBackendType::Servo,
aElement, aPseudoType,
nullptr);
MaybeUpdateCascadeResults(aElement, aPseudoType);
for (KeyframeEffectReadOnly* effect : *effects) {
effect->GetAnimation()->WillComposeStyle();

Просмотреть файл

@ -153,20 +153,11 @@ public:
// the change in the set of effects or a change in one of the effects'
// "in effect" state.
//
// When |aBackendType| is StyleBackendType::Gecko, |aComputedStyle| is used to
// find overridden properties. If it is nullptr, the ComputedStyle of the
// primary frame of the specified (pseudo-)element, if available, is used.
//
// When |aBackendType| is StyleBackendType::Servo, we fetch the rule node
// from the |aElement| (i.e. |aComputedStyle| is ignored).
//
// This method does NOT detect if other styles that apply above the
// animation level of the cascade have changed.
static void
MaybeUpdateCascadeResults(StyleBackendType aBackendType,
dom::Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle);
MaybeUpdateCascadeResults(dom::Element* aElement,
CSSPseudoElementType aPseudoType);
// Update the mPropertiesWithImportantRules and
// mPropertiesForAnimationsLevel members of the given EffectSet, and also
@ -180,16 +171,10 @@ public:
// when we detect changes to the cascade on the Servo side we can't call
// MarkCascadeNeedsUpdate during the traversal so instead we call this as part
// of a follow-up sequential task.
//
// As with MaybeUpdateCascadeResults, |aComputedStyle| is only used
// when |aBackendType| is StyleBackendType::Gecko. When |aBackendType| is
// StyleBackendType::Servo, it is ignored.
static void
UpdateCascadeResults(StyleBackendType aBackendType,
EffectSet& aEffectSet,
UpdateCascadeResults(EffectSet& aEffectSet,
dom::Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle);
CSSPseudoElementType aPseudoType);
// Helper to fetch the corresponding element and pseudo-type from a frame.
//
@ -240,21 +225,10 @@ private:
// Get the properties in |aEffectSet| that we are able to animate on the
// compositor but which are also specified at a higher level in the cascade
// than the animations level.
//
// When |aBackendType| is StyleBackendType::Gecko, we determine which
// properties are specified using the provided |aComputedStyle| and
// |aElement| and |aPseudoType| are ignored. If |aComputedStyle| is nullptr,
// we automatically look up the ComputedStyle of primary frame of the
// (pseudo-)element.
//
// When |aBackendType| is StyleBackendType::Servo, we use the |StrongRuleNode|
// stored on the (pseudo-)element indicated by |aElement| and |aPseudoType|.
static nsCSSPropertyIDSet
GetOverriddenProperties(StyleBackendType aBackendType,
EffectSet& aEffectSet,
GetOverriddenProperties(EffectSet& aEffectSet,
dom::Element* aElement,
CSSPseudoElementType aPseudoType,
ComputedStyle* aComputedStyle);
CSSPseudoElementType aPseudoType);
static nsPresContext* GetPresContext(dom::Element* aElement);

Просмотреть файл

@ -339,7 +339,6 @@ static bool
GetPropertyValuesPairs(JSContext* aCx,
JS::Handle<JSObject*> aObject,
ListAllowance aAllowLists,
StyleBackendType aBackend,
nsTArray<PropertyValuesPair>& aResult);
static bool
@ -523,36 +522,15 @@ KeyframeUtils::GetAnimationPropertiesFromKeyframes(
}
/* static */ bool
KeyframeUtils::IsAnimatableProperty(nsCSSPropertyID aProperty,
StyleBackendType aBackend)
KeyframeUtils::IsAnimatableProperty(nsCSSPropertyID aProperty)
{
// Regardless of the backend type, treat the 'display' property as not
// animatable. (The Servo backend will report it as being animatable, since
// it is in fact animatable by SMIL.)
// animatable. (Servo will report it as being animatable, since it is
// in fact animatable by SMIL.)
if (aProperty == eCSSProperty_display) {
return false;
}
if (aBackend == StyleBackendType::Servo) {
return Servo_Property_IsAnimatable(aProperty);
}
if (aProperty == eCSSProperty_UNKNOWN) {
return false;
}
if (!nsCSSProps::IsShorthand(aProperty)) {
return nsCSSProps::kAnimTypeTable[aProperty] != eStyleAnimType_None;
}
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, aProperty,
CSSEnabledState::eForAllContent) {
if (nsCSSProps::kAnimTypeTable[*subprop] != eStyleAnimType_None) {
return true;
}
}
return false;
return Servo_Property_IsAnimatable(aProperty);
}
// ------------------------------------------------------------------
@ -662,7 +640,6 @@ ConvertKeyframeSequence(JSContext* aCx,
JS::Rooted<JSObject*> object(aCx, &value.toObject());
if (!GetPropertyValuesPairs(aCx, object,
ListAllowance::eDisallow,
aDocument->GetStyleBackendType(),
propertyValuePairs)) {
return false;
}
@ -721,8 +698,6 @@ ConvertKeyframeSequence(JSContext* aCx,
* @param aAllowLists If eAllow, values will be converted to
* (DOMString or sequence<DOMString); if eDisallow, values
* will be converted to DOMString.
* @param aBackend The style backend in use. Used to determine which properties
* are animatable since only animatable properties are read.
* @param aResult The array into which the enumerated property-values
* pairs will be stored.
* @return false on failure or JS exception thrown while interacting
@ -732,7 +707,6 @@ static bool
GetPropertyValuesPairs(JSContext* aCx,
JS::Handle<JSObject*> aObject,
ListAllowance aAllowLists,
StyleBackendType aBackend,
nsTArray<PropertyValuesPair>& aResult)
{
nsTArray<AdditionalProperty> properties;
@ -755,7 +729,7 @@ GetPropertyValuesPairs(JSContext* aCx,
nsCSSPropertyID property =
nsCSSProps::LookupPropertyByIDLName(propName,
CSSEnabledState::eForAllContent);
if (KeyframeUtils::IsAnimatableProperty(property, aBackend)) {
if (KeyframeUtils::IsAnimatableProperty(property)) {
AdditionalProperty* p = properties.AppendElement();
p->mProperty = property;
p->mJsidIndex = i;
@ -1247,7 +1221,6 @@ GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
JS::Rooted<JSObject*> object(aCx, &aValue.toObject());
nsTArray<PropertyValuesPair> propertyValuesPairs;
if (!GetPropertyValuesPairs(aCx, object, ListAllowance::eAllow,
aDocument->GetStyleBackendType(),
propertyValuesPairs)) {
aRv.Throw(NS_ERROR_FAILURE);
return;

Просмотреть файл

@ -105,8 +105,7 @@ public:
* if the property is animatable or not.
* @return true if |aProperty| is animatable.
*/
static bool IsAnimatableProperty(nsCSSPropertyID aProperty,
StyleBackendType aBackend);
static bool IsAnimatableProperty(nsCSSPropertyID aProperty);
};
} // namespace mozilla

Просмотреть файл

@ -1739,16 +1739,12 @@ nsAttrValue::ParseStyleAttribute(const nsAString& aString,
}
}
RefPtr<DeclarationBlock> decl;
if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
RefPtr<URLExtraData> data = new URLExtraData(baseURI, docURI,
principal);
decl = ServoDeclarationBlock::FromCssText(aString, data,
ownerDoc->GetCompatibilityMode(),
ownerDoc->CSSLoader());
} else {
MOZ_CRASH("old style system disabled");
}
RefPtr<URLExtraData> data = new URLExtraData(baseURI, docURI,
principal);
RefPtr<DeclarationBlock> decl = ServoDeclarationBlock::
FromCssText(aString, data,
ownerDoc->GetCompatibilityMode(),
ownerDoc->CSSLoader());
if (!decl) {
return false;
}

Просмотреть файл

@ -26,8 +26,6 @@
#include "nsIDocShell.h"
#include "nsIContentViewerEdit.h"
#include "nsIClipboardDragDropHooks.h"
#include "nsIClipboardDragDropHookList.h"
#include "nsIClipboardHelper.h"
#include "nsISelectionController.h"
@ -279,12 +277,8 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
}
if (doPutOnClipboard && clipboard) {
bool actuallyPutOnClipboard = true;
nsCopySupport::DoHooks(aDoc, trans, &actuallyPutOnClipboard);
// put the transferable on the clipboard
if (actuallyPutOnClipboard)
clipboard->SetData(trans, nullptr, aClipboardID);
clipboard->SetData(trans, nullptr, aClipboardID);
}
// Return the transferable to the caller if requested.
@ -351,49 +345,6 @@ nsCopySupport::GetTransferableForNode(nsINode* aNode,
aTransferable);
}
nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
bool *aDoPutOnClipboard)
{
NS_ENSURE_ARG(aDoc);
*aDoPutOnClipboard = true;
nsCOMPtr<nsISupports> container = aDoc->GetContainer();
nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(container);
if (!hookObj) return NS_ERROR_FAILURE;
nsCOMPtr<nsISimpleEnumerator> enumerator;
hookObj->GetHookEnumerator(getter_AddRefs(enumerator));
if (!enumerator) return NS_ERROR_FAILURE;
// the logic here should follow the behavior specified in
// nsIClipboardDragDropHooks.h
nsCOMPtr<nsIClipboardDragDropHooks> override;
nsCOMPtr<nsISupports> isupp;
bool hasMoreHooks = false;
nsresult rv = NS_OK;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks))
&& hasMoreHooks)
{
rv = enumerator->GetNext(getter_AddRefs(isupp));
if (NS_FAILED(rv)) break;
override = do_QueryInterface(isupp);
if (override)
{
#ifdef DEBUG
nsresult hookResult =
#endif
override->OnCopyOrDrag(nullptr, aTrans, aDoPutOnClipboard);
NS_ASSERTION(NS_SUCCEEDED(hookResult), "OnCopyOrDrag hook failed");
if (!*aDoPutOnClipboard)
break;
}
}
return rv;
}
nsresult
nsCopySupport::GetContents(const nsACString& aMimeType, uint32_t aFlags, nsISelection *aSel, nsIDocument *aDoc, nsAString& outdata)
{

Просмотреть файл

@ -33,8 +33,6 @@ class nsCopySupport
static nsresult ClearSelectionCache();
static nsresult HTMLCopy(nsISelection *aSel, nsIDocument *aDoc,
int16_t aClipboardID, bool aWithRubyAnnotation);
static nsresult DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,
bool *aDoPutOnClipboard);
// Get the selection, or entire document, in the format specified by the mime type
// (text/html or text/plain). If aSel is non-null, use it, otherwise get the entire

Просмотреть файл

@ -3541,7 +3541,7 @@ nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet, uint32_t aSheetType)
StyleSheet* sheet = nullptr;
auto preloadedSheet = static_cast<PreloadedStyleSheet*>(aSheet);
nsresult rv = preloadedSheet->GetSheet(doc->GetStyleBackendType(), &sheet);
nsresult rv = preloadedSheet->GetSheet(&sheet);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);

Просмотреть файл

@ -1314,15 +1314,9 @@ nsIDocument::SelectorCache::~SelectorCache()
void
nsIDocument::SelectorCache::SelectorList::Reset()
{
if (mIsServo) {
if (mServo) {
Servo_SelectorList_Drop(mServo);
mServo = nullptr;
}
} else {
if (mGecko) {
MOZ_CRASH("old style system disabled");
}
if (mServo) {
Servo_SelectorList_Drop(mServo);
mServo = nullptr;
}
}
@ -2507,7 +2501,7 @@ nsIDocument::ResetStylesheetsToURI(nsIURI* aURI)
if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
RemoveStyleSheetsFromStyleSets(
*sheetService->AuthorStyleSheets(GetStyleBackendType()), SheetType::Doc);
*sheetService->AuthorStyleSheets(), SheetType::Doc);
}
mStyleSetFilled = false;
@ -2571,7 +2565,7 @@ nsIDocument::FillStyleSet(StyleSetHandle aStyleSet)
if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
nsTArray<RefPtr<StyleSheet>>& sheets =
*sheetService->AuthorStyleSheets(aStyleSet->BackendType());
*sheetService->AuthorStyleSheets();
for (StyleSheet* sheet : sheets) {
aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
@ -4572,8 +4566,7 @@ nsIDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
return NS_ERROR_INVALID_ARG;
// Loading the sheet sync.
RefPtr<css::Loader> loader =
new css::Loader(GetStyleBackendType(), GetDocGroup());
RefPtr<css::Loader> loader = new css::Loader(GetDocGroup());
css::SheetParsingMode parsingMode;
switch (aType) {
@ -5903,7 +5896,7 @@ nsIDocument::ResolveScheduledSVGPresAttrs()
{
for (auto iter = mLazySVGPresElements.Iter(); !iter.Done(); iter.Next()) {
nsSVGElement* svg = iter.Get()->GetKey();
svg->UpdateContentDeclarationBlock(StyleBackendType::Servo);
svg->UpdateContentDeclarationBlock();
}
mLazySVGPresElements.Clear();
}
@ -9571,7 +9564,6 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
clonedDoc->mOriginalDocument->mStaticCloneCount++;
MOZ_ASSERT(GetStyleBackendType() == clonedDoc->GetStyleBackendType());
size_t sheetsCount = SheetCount();
for (size_t i = 0; i < sheetsCount; ++i) {
RefPtr<StyleSheet> sheet = SheetAt(i);

Просмотреть файл

@ -906,13 +906,9 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
// There's a cached property declaration block
// that needs to be updated
if (nsIDocument* doc = mDocShell->GetDocument()) {
// We don't need to do anything for Gecko here because
// we plan to RebuildAllStyleData anyway.
if (doc->GetStyleBackendType() == StyleBackendType::Servo) {
for (nsINode* cur = doc; cur; cur = cur->GetNextNode()) {
if (cur->IsHTMLElement(nsGkAtoms::body)) {
static_cast<HTMLBodyElement*>(cur)->ClearMappedServoStyle();
}
for (nsINode* cur = doc; cur; cur = cur->GetNextNode()) {
if (cur->IsHTMLElement(nsGkAtoms::body)) {
static_cast<HTMLBodyElement*>(cur)->ClearMappedServoStyle();
}
}
}

Просмотреть файл

@ -37,9 +37,6 @@
#include "mozilla/dom/Selection.h"
#include "mozilla/layers/KeyboardMap.h"
#include "nsIClipboardDragDropHooks.h"
#include "nsIClipboardDragDropHookList.h"
using namespace mozilla;
using namespace mozilla::layers;
@ -918,101 +915,6 @@ nsGoBackCommand::DoWebNavCommand(const char *aCommandName, nsIWebNavigation* aWe
}
#endif
/*---------------------------------------------------------------------------
nsClipboardDragDropHookCommand
params value type possible values
"addhook" isupports nsIClipboardDragDropHooks as nsISupports
"removehook" isupports nsIClipboardDragDropHooks as nsISupports
----------------------------------------------------------------------------*/
class nsClipboardDragDropHookCommand final : public nsIControllerCommand
{
~nsClipboardDragDropHookCommand() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTROLLERCOMMAND
protected:
// no member variables, please, we're stateless!
};
NS_IMPL_ISUPPORTS(nsClipboardDragDropHookCommand, nsIControllerCommand)
NS_IMETHODIMP
nsClipboardDragDropHookCommand::IsCommandEnabled(const char * aCommandName,
nsISupports *aCommandContext,
bool *outCmdEnabled)
{
*outCmdEnabled = true;
return NS_OK;
}
NS_IMETHODIMP
nsClipboardDragDropHookCommand::DoCommand(const char *aCommandName,
nsISupports *aCommandContext)
{
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsClipboardDragDropHookCommand::DoCommandParams(const char *aCommandName,
nsICommandParams *aParams,
nsISupports *aCommandContext)
{
NS_ENSURE_ARG(aParams);
nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aCommandContext);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsIDocShell *docShell = window->GetDocShell();
nsCOMPtr<nsIClipboardDragDropHookList> obj = do_GetInterface(docShell);
if (!obj) return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsISupports> isuppHook;
nsresult returnValue = NS_OK;
nsresult rv = aParams->GetISupportsValue("addhook", getter_AddRefs(isuppHook));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIClipboardDragDropHooks> hook = do_QueryInterface(isuppHook);
if (hook)
returnValue = obj->AddClipboardDragDropHooks(hook);
else
returnValue = NS_ERROR_INVALID_ARG;
}
rv = aParams->GetISupportsValue("removehook", getter_AddRefs(isuppHook));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIClipboardDragDropHooks> hook = do_QueryInterface(isuppHook);
if (hook)
{
rv = obj->RemoveClipboardDragDropHooks(hook);
if (NS_FAILED(rv) && NS_SUCCEEDED(returnValue))
returnValue = rv;
}
else
returnValue = NS_ERROR_INVALID_ARG;
}
return returnValue;
}
NS_IMETHODIMP
nsClipboardDragDropHookCommand::GetCommandStateParams(const char *aCommandName,
nsICommandParams *aParams,
nsISupports *aCommandContext)
{
NS_ENSURE_ARG_POINTER(aParams);
return aParams->SetBooleanValue("state_enabled", true);
}
class nsLookUpDictionaryCommand final : public nsIControllerCommand
{
public:
@ -1279,8 +1181,6 @@ nsWindowCommandRegistration::RegisterWindowCommands(
NS_REGISTER_ONE_COMMAND(nsGoForwardCommand, "cmd_browserForward");
#endif
NS_REGISTER_ONE_COMMAND(nsClipboardDragDropHookCommand, "cmd_clipboardDragDropHook");
NS_REGISTER_ONE_COMMAND(nsLookUpDictionaryCommand, "cmd_lookUpDictionary");
return rv;

Просмотреть файл

@ -50,7 +50,6 @@
#include "mozilla/NotNull.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -1505,8 +1504,7 @@ public:
{
public:
SelectorList()
: mIsServo(false)
, mGecko(nullptr)
: mGecko(nullptr)
{}
SelectorList(SelectorList&& aOther)
@ -1517,21 +1515,15 @@ public:
SelectorList& operator=(SelectorList&& aOther)
{
Reset();
mIsServo = aOther.mIsServo;
if (mIsServo) {
mServo = aOther.mServo;
aOther.mServo = nullptr;
} else {
MOZ_CRASH("old style system disabled");
}
mServo = aOther.mServo;
aOther.mServo = nullptr;
return *this;
}
SelectorList(const SelectorList& aOther) = delete;
explicit SelectorList(mozilla::UniquePtr<RawServoSelectorList>&& aList)
: mIsServo(true)
, mServo(aList.release())
: mServo(aList.release())
{}
@ -1539,31 +1531,24 @@ public:
Reset();
}
bool IsServo() const { return mIsServo; }
bool IsGecko() const { return !IsServo(); }
explicit operator bool() const
{
return IsServo() ? !!AsServo() : !!AsGecko();
return !!AsServo();
}
nsCSSSelectorList* AsGecko() const
{
MOZ_ASSERT(IsGecko());
return mGecko;
}
RawServoSelectorList* AsServo() const
{
MOZ_ASSERT(IsServo());
return mServo;
}
private:
void Reset();
bool mIsServo;
union {
nsCSSSelectorList* mGecko;
RawServoSelectorList* mServo;
@ -1598,14 +1583,12 @@ public:
nsDataHashtable<nsStringHashKey, SelectorList> mTable;
};
SelectorCache& GetSelectorCache(mozilla::StyleBackendType aBackendType) {
mozilla::UniquePtr<SelectorCache>& cache =
aBackendType == mozilla::StyleBackendType::Servo
? mServoSelectorCache : mGeckoSelectorCache;
if (!cache) {
cache.reset(new SelectorCache(EventTargetFor(mozilla::TaskCategory::Other)));
SelectorCache& GetSelectorCache() {
if (!mSelectorCache) {
mSelectorCache.reset(new SelectorCache(
EventTargetFor(mozilla::TaskCategory::Other)));
}
return *cache;
return *mSelectorCache;
}
// Get the root <html> element, or return null if there isn't one (e.g.
// if the root isn't <html>)
@ -1737,11 +1720,6 @@ public:
return mCSSLoader;
}
mozilla::StyleBackendType GetStyleBackendType() const
{
return mozilla::StyleBackendType::Servo;
}
/**
* Get this document's StyleImageLoader. This is guaranteed to not return null.
*/
@ -3755,10 +3733,7 @@ private:
// Lazy-initialization to have mDocGroup initialized in prior to the
// SelectorCaches.
// FIXME(emilio): We can use a single cache when all CSSOM methods are
// implemented for the Servo backend.
mozilla::UniquePtr<SelectorCache> mServoSelectorCache;
mozilla::UniquePtr<SelectorCache> mGeckoSelectorCache;
mozilla::UniquePtr<SelectorCache> mSelectorCache;
protected:
friend class nsDocumentOnStack;

Просмотреть файл

@ -43,8 +43,7 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
// doc sheet should end up before it.
if (sheetDocIndex < 0) {
if (sheetService) {
auto& authorSheets =
*sheetService->AuthorStyleSheets(GetStyleBackendType());
auto& authorSheets = *sheetService->AuthorStyleSheets();
if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
break;
}

Просмотреть файл

@ -2492,8 +2492,7 @@ nsINode::ParseServoSelectorList(
{
nsIDocument* doc = OwnerDoc();
nsIDocument::SelectorCache& cache =
doc->GetSelectorCache(mozilla::StyleBackendType::Servo);
nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
nsIDocument::SelectorCache::SelectorList* list =
cache.GetList(aSelectorString);
if (list) {

Просмотреть файл

@ -224,8 +224,7 @@ nsStyleLinkElement::CheckPreloadAttrs(const nsAttrValue& aAs,
// Check if media attribute is valid.
if (!aMedia.IsEmpty()) {
RefPtr<MediaList> mediaList = MediaList::Create(aDocument->GetStyleBackendType(),
aMedia);
RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
nsPresContext* presContext = aDocument->GetPresContext();
if (!presContext) {
return false;

Просмотреть файл

@ -162,9 +162,6 @@ void
nsStyledElement::NodeInfoChanged(nsIDocument* aOldDoc)
{
nsStyledElementBase::NodeInfoChanged(aOldDoc);
if (OwnerDoc()->GetStyleBackendType() != aOldDoc->GetStyleBackendType()) {
ReparseStyleAttribute(false, /* aForceIfAlreadyParsed */ true);
}
}
nsICSSDeclaration*

Просмотреть файл

@ -1118,20 +1118,20 @@ nsTreeSanitizer::SanitizeStyleSheet(const nsAString& aOriginal,
mozilla::css::Rule* rule = rules->Item(i);
if (!rule)
continue;
switch (rule->GetType()) {
switch (rule->Type()) {
default:
didSanitize = true;
// Ignore these rule types.
break;
case mozilla::css::Rule::NAMESPACE_RULE:
case mozilla::css::Rule::FONT_FACE_RULE: {
case CSSRuleBinding::NAMESPACE_RULE:
case CSSRuleBinding::FONT_FACE_RULE: {
// Append @namespace and @font-face rules verbatim.
nsAutoString cssText;
rule->GetCssText(cssText);
aSanitized.Append(cssText);
break;
}
case mozilla::css::Rule::STYLE_RULE: {
case CSSRuleBinding::STYLE_RULE: {
// For style rules, we will just look for and remove the
// -moz-binding properties.
auto styleRule = static_cast<BindingStyleRule*>(rule);

Просмотреть файл

@ -2689,8 +2689,6 @@ GetFontStyleForServo(Element* aElement, const nsAString& aFont,
nsAString& aOutUsedFont,
ErrorResult& aError)
{
MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
RefPtr<RawServoDeclarationBlock> declarations =
CreateFontDeclarationForServo(aFont, aPresShell->GetDocument());
if (!declarations) {
@ -2760,8 +2758,6 @@ ResolveFilterStyleForServo(const nsAString& aFilterString,
nsIPresShell* aPresShell,
ErrorResult& aError)
{
MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
RefPtr<RawServoDeclarationBlock> declarations =
CreateFilterDeclarationForServo(aFilterString, aPresShell->GetDocument());
if (!declarations) {
@ -2800,14 +2796,7 @@ CanvasRenderingContext2D::ParseFilter(const nsAString& aString,
return false;
}
nsString usedFont;
if (presShell->StyleSet()->IsGecko()) {
MOZ_CRASH("old style system disabled");
return false;
}
// For stylo
MOZ_ASSERT(presShell->StyleSet()->IsServo());
nsString usedFont; // unused
RefPtr<ComputedStyle> parentStyle =
GetFontStyleForServo(mCanvasElement,
@ -3735,14 +3724,9 @@ CanvasRenderingContext2D::SetFontInternal(const nsAString& aFont,
return false;
}
RefPtr<ComputedStyle> sc;
nsString usedFont;
if (presShell->StyleSet()->IsServo()) {
sc =
GetFontStyleForServo(mCanvasElement, aFont, presShell, usedFont, aError);
} else {
MOZ_CRASH("old style system disabled");
}
RefPtr<ComputedStyle> sc =
GetFontStyleForServo(mCanvasElement, aFont, presShell, usedFont, aError);
if (!sc) {
return false;
}
@ -3755,8 +3739,8 @@ CanvasRenderingContext2D::SetFontInternal(const nsAString& aFont,
// size (fontStyle->mSize). See
// https://bugzilla.mozilla.org/show_bug.cgi?id=698652.
// FIXME: Nobody initializes mAllowZoom for servo?
MOZ_ASSERT(presShell->StyleSet()->IsServo() || !fontStyle->mAllowZoom,
"expected text zoom to be disabled on this nsStyleFont");
//MOZ_ASSERT(!fontStyle->mAllowZoom,
// "expected text zoom to be disabled on this nsStyleFont");
nsFont resizedFont(fontStyle->mFont);
// Create a font group working in units of CSS pixels instead of the usual
// device pixels, to avoid being affected by page zoom. nsFontMetrics will

Просмотреть файл

@ -216,8 +216,7 @@ HTMLBodyElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
}
if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
if (!aData->PropertyIsSet(eCSSProperty_color) &&
!aData->ShouldIgnoreColors()) {
if (!aData->PropertyIsSet(eCSSProperty_color)) {
// color: color
nscolor color;
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::text);

Просмотреть файл

@ -75,8 +75,7 @@ HTMLFontElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
}
}
if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
if (!aData->PropertyIsSet(eCSSProperty_color) &&
!aData->ShouldIgnoreColors()) {
if (!aData->PropertyIsSet(eCSSProperty_color)) {
// color: color
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::color);
nscolor color;

Просмотреть файл

@ -167,7 +167,7 @@ HTMLHRElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
if (aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Color))) {
// color: a color
// (we got the color attribute earlier)
if (colorIsSet && !aData->ShouldIgnoreColors()) {
if (colorIsSet) {
aData->SetColorValueIfUnset(eCSSProperty_color, color);
}
}

Просмотреть файл

@ -61,8 +61,7 @@ HTMLSourceElement::WouldMatchMediaForDocument(const nsAString& aMedia,
nsPresContext* pctx = aDocument->GetPresContext();
RefPtr<MediaList> mediaList =
MediaList::Create(aDocument->GetStyleBackendType(), aMedia);
RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
return pctx && mediaList->Matches(pctx);
}
@ -75,7 +74,7 @@ HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue)
return;
}
mMediaList = MediaList::Create(OwnerDoc()->GetStyleBackendType(), mediaStr);
mMediaList = MediaList::Create(mediaStr);
}
nsresult

Просмотреть файл

@ -990,7 +990,7 @@ HTMLTableElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
// bordercolor
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bordercolor);
nscolor color;
if (value && !aData->ShouldIgnoreColors() && value->GetColorValue(color)) {
if (value && value->GetColorValue(color)) {
aData->SetColorValueIfUnset(eCSSProperty_border_top_color, color);
aData->SetColorValueIfUnset(eCSSProperty_border_left_color, color);
aData->SetColorValueIfUnset(eCSSProperty_border_bottom_color, color);

Просмотреть файл

@ -1475,8 +1475,7 @@ nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
return;
if (!aData->PropertyIsSet(eCSSProperty_background_image) &&
!aData->ShouldIgnoreColors()) {
if (!aData->PropertyIsSet(eCSSProperty_background_image)) {
// background
nsAttrValue* value =
const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
@ -1493,8 +1492,7 @@ nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
if (!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))
return;
if (!aData->PropertyIsSet(eCSSProperty_background_color) &&
!aData->ShouldIgnoreColors()) {
if (!aData->PropertyIsSet(eCSSProperty_background_color)) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
nscolor color;
if (value && value->GetColorValue(color)) {
@ -2959,13 +2957,7 @@ nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
static bool
IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
{
if (aPresShell->StyleSet()->IsServo()) {
return !aElement->HasServoData() || Servo_Element_IsDisplayNone(aElement);
}
MOZ_CRASH("Old style system disabled");
return false;
return !aElement->HasServoData() || Servo_Element_IsDisplayNone(aElement);
}
void

Просмотреть файл

@ -2268,7 +2268,7 @@ nsHTMLDocument::TearingDownEditor()
nsTArray<RefPtr<StyleSheet>> agentSheets;
presShell->GetAgentStyleSheets(agentSheets);
auto cache = nsLayoutStylesheetCache::For(GetStyleBackendType());
auto cache = nsLayoutStylesheetCache::Singleton();
agentSheets.RemoveElement(cache->ContentEditableSheet());
if (oldState == eDesignMode)
@ -2414,7 +2414,7 @@ nsHTMLDocument::EditingStateChanged()
rv = presShell->GetAgentStyleSheets(agentSheets);
NS_ENSURE_SUCCESS(rv, rv);
auto cache = nsLayoutStylesheetCache::For(GetStyleBackendType());
auto cache = nsLayoutStylesheetCache::Singleton();
StyleSheet* contentEditableSheet = cache->ContentEditableSheet();

Просмотреть файл

@ -2297,9 +2297,7 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority)
// Content processes have no permission to access profile directory, so we
// send the file URL instead.
StyleBackendType backendType =
StyleBackendType::Servo;
StyleSheet* ucs = nsLayoutStylesheetCache::For(backendType)->UserContentSheet();
StyleSheet* ucs = nsLayoutStylesheetCache::Singleton()->UserContentSheet();
if (ucs) {
SerializeURI(ucs->GetSheetURI(), xpcomInit.userContentSheetURL());
} else {
@ -2415,19 +2413,19 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority)
// The URIs of the Gecko and Servo sheets should be the same, so it
// shouldn't matter which we look at.
for (StyleSheet* sheet : *sheetService->AgentStyleSheets(backendType)) {
for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
URIParams uri;
SerializeURI(sheet->GetSheetURI(), uri);
Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AGENT_SHEET);
}
for (StyleSheet* sheet : *sheetService->UserStyleSheets(backendType)) {
for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
URIParams uri;
SerializeURI(sheet->GetSheetURI(), uri);
Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::USER_SHEET);
}
for (StyleSheet* sheet : *sheetService->AuthorStyleSheets(backendType)) {
for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
URIParams uri;
SerializeURI(sheet->GetSheetURI(), uri);
Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);

Просмотреть файл

@ -112,7 +112,7 @@ nsMathMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// Enable MathML and setup the style sheet during binding, not element
// construction, because we could move a MathML element from the document
// that created it to another document.
auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType());
auto cache = nsLayoutStylesheetCache::Singleton();
doc->SetMathMLEnabled();
doc->EnsureOnDemandBuiltInUASheet(cache->MathMLSheet());

Просмотреть файл

@ -29,6 +29,9 @@
#include "GeneratedJNIWrappers.h"
#endif
#define AUDIOIPC_POOL_SIZE_DEFAULT 1
#define AUDIOIPC_STACK_SIZE_DEFAULT (64*1024)
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_BACKEND "media.cubeb.backend"
#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
@ -38,18 +41,27 @@
#define PREF_CUBEB_FORCE_SAMPLE_RATE "media.cubeb.force_sample_rate"
#define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
#define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
#define PREF_AUDIOIPC_POOL_SIZE "media.audioipc.pool_size"
#define PREF_AUDIOIPC_STACK_SIZE "media.audioipc.stack_size"
#if (defined(XP_LINUX) && !defined(MOZ_WIDGET_ANDROID)) || defined(XP_MACOSX)
#define MOZ_CUBEB_REMOTING
#endif
extern "C" {
struct AudioIpcInitParams {
int mServerConnection;
size_t mPoolSize;
size_t mStackSize;
};
// These functions are provided by audioipc-server crate
extern void* audioipc_server_start();
extern mozilla::ipc::FileDescriptor::PlatformHandleType audioipc_server_new_client(void*);
extern void audioipc_server_stop(void*);
// These functions are provided by audioipc-client crate
extern int audioipc_client_init(cubeb**, const char*, int);
extern int audioipc_client_init(cubeb**, const char*, const AudioIpcInitParams*);
}
namespace mozilla {
@ -116,7 +128,9 @@ bool sCubebPlaybackLatencyPrefSet = false;
bool sCubebMSGLatencyPrefSet = false;
bool sAudioStreamInitEverSucceeded = false;
#ifdef MOZ_CUBEB_REMOTING
bool sCubebSandbox;
bool sCubebSandbox = false;
size_t sAudioIPCPoolSize;
size_t sAudioIPCStackSize;
#endif
StaticAutoPtr<char> sBrandName;
StaticAutoPtr<char> sCubebBackendName;
@ -233,6 +247,16 @@ void PrefChanged(const char* aPref, void* aClosure)
StartSoundServer();
}
}
else if (strcmp(aPref, PREF_AUDIOIPC_POOL_SIZE) == 0) {
StaticMutexAutoLock lock(sMutex);
sAudioIPCPoolSize = Preferences::GetUint(PREF_AUDIOIPC_POOL_SIZE,
AUDIOIPC_POOL_SIZE_DEFAULT);
}
else if (strcmp(aPref, PREF_AUDIOIPC_STACK_SIZE) == 0) {
StaticMutexAutoLock lock(sMutex);
sAudioIPCStackSize = Preferences::GetUint(PREF_AUDIOIPC_STACK_SIZE,
AUDIOIPC_STACK_SIZE_DEFAULT);
}
#endif
}
@ -367,6 +391,9 @@ cubeb* GetCubebContextUnlocked()
}
#ifdef MOZ_CUBEB_REMOTING
MOZ_LOG(gCubebLog, LogLevel::Info, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
int rv = CUBEB_OK;
if (sCubebSandbox) {
if (XRE_IsParentProcess()) {
// TODO: Don't use audio IPC when within the same process.
@ -375,14 +402,19 @@ cubeb* GetCubebContextUnlocked()
} else {
MOZ_DIAGNOSTIC_ASSERT(sIPCConnection);
}
AudioIpcInitParams initParams;
initParams.mPoolSize = sAudioIPCPoolSize;
initParams.mStackSize = sAudioIPCStackSize;
initParams.mServerConnection = sIPCConnection->ClonePlatformHandle().release();
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_POOL_SIZE, (int) initParams.mPoolSize));
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_STACK_SIZE, (int) initParams.mStackSize));
rv = audioipc_client_init(&sCubebContext, sBrandName, &initParams);
} else {
rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
}
MOZ_LOG(gCubebLog, LogLevel::Info, ("%s: %s", PREF_CUBEB_SANDBOX, sCubebSandbox ? "true" : "false"));
int rv = sCubebSandbox
? audioipc_client_init(&sCubebContext, sBrandName,
sIPCConnection->ClonePlatformHandle().release())
: cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
sIPCConnection = nullptr;
#else // !MOZ_CUBEB_REMOTING
int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
@ -476,6 +508,8 @@ void InitLibrary()
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_FORCE_SAMPLE_RATE);
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_POOL_SIZE);
Preferences::RegisterCallbackAndCall(PrefChanged, PREF_AUDIOIPC_STACK_SIZE);
if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
} else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
@ -500,6 +534,8 @@ void InitLibrary()
void ShutdownLibrary()
{
Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
Preferences::UnregisterCallback(PrefChanged, PREF_AUDIOIPC_STACK_SIZE);
Preferences::UnregisterCallback(PrefChanged, PREF_AUDIOIPC_POOL_SIZE);
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_SANDBOX);
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_BACKEND);
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);

Просмотреть файл

@ -1858,43 +1858,67 @@ already_AddRefed<MediaManager::PledgeSourceSet>
MediaManager::EnumerateRawDevices(uint64_t aWindowId,
MediaSourceEnum aVideoType,
MediaSourceEnum aAudioType,
bool aFake)
DeviceEnumerationType aVideoEnumType /* = DeviceEnumerationType::Normal */,
DeviceEnumerationType aAudioEnumType /* = DeviceEnumerationType::Normal */)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aVideoType != MediaSourceEnum::Other ||
aAudioType != MediaSourceEnum::Other);
// Since the enums can take one of several values, the following asserts rely
// on short circuting behavior. E.g. aVideoEnumType != Fake will be true if
// the requested device is not fake and thus the assert will pass. However,
// if the device is fake, aVideoType == MediaSourceEnum::Camera will be
// checked as well, ensuring that fake devices are of the camera type.
MOZ_ASSERT(aVideoEnumType != DeviceEnumerationType::Fake ||
aVideoType == MediaSourceEnum::Camera,
"If fake cams are requested video type should be camera!");
MOZ_ASSERT(aVideoEnumType != DeviceEnumerationType::Loopback ||
aVideoType == MediaSourceEnum::Camera,
"If loopback video is requested video type should be camera!");
MOZ_ASSERT(aAudioEnumType != DeviceEnumerationType::Fake ||
aAudioType == MediaSourceEnum::Microphone,
"If fake mics are requested audio type should be microphone!");
MOZ_ASSERT(aAudioEnumType != DeviceEnumerationType::Loopback ||
aAudioType == MediaSourceEnum::Microphone,
"If loopback audio is requested audio type should be microphone!");
LOG(("%s: aWindowId=%" PRIu64 ", aVideoType=%" PRIu8 ", aAudioType=%" PRIu8
", aVideoEnumType=%" PRIu8 ", aAudioEnumType=%" PRIu8,
__func__, aWindowId,
static_cast<uint8_t>(aVideoType), static_cast<uint8_t>(aAudioType),
static_cast<uint8_t>(aVideoEnumType), static_cast<uint8_t>(aAudioEnumType)));
RefPtr<PledgeSourceSet> p = new PledgeSourceSet();
uint32_t id = mOutstandingPledges.Append(*p);
nsAutoCString audioLoopDev, videoLoopDev;
if (!aFake) {
// Fake stream not requested. The entire device stack is available.
// Loop in loopback devices if they are set, and their respective type is
// requested. This is currently used for automated media tests only.
if (aVideoType == MediaSourceEnum::Camera) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
}
if (aAudioType == MediaSourceEnum::Microphone) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
}
}
bool hasVideo = aVideoType != MediaSourceEnum::Other;
bool hasAudio = aAudioType != MediaSourceEnum::Other;
bool fakeCams = aFake && aVideoType == MediaSourceEnum::Camera;
bool fakeMics = aFake && aAudioType == MediaSourceEnum::Microphone;
bool realDevicesRequested = (!fakeCams && hasVideo) || (!fakeMics && hasAudio);
RefPtr<Runnable> task = NewTaskFrom([id, aWindowId, audioLoopDev,
videoLoopDev, aVideoType,
aAudioType, hasVideo, hasAudio,
fakeCams, fakeMics, realDevicesRequested]() {
// True of at least one of video or audio is a fake device
bool fakeDeviceRequested = (aVideoEnumType == DeviceEnumerationType::Fake && hasVideo) ||
(aAudioEnumType == DeviceEnumerationType::Fake && hasAudio);
// True if at least one of video or audio is a real device
bool realDeviceRequested = (aVideoEnumType != DeviceEnumerationType::Fake && hasVideo) ||
(aAudioEnumType != DeviceEnumerationType::Fake && hasAudio);
nsAutoCString videoLoopDev, audioLoopDev;
if (hasVideo && aVideoEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
}
if (hasAudio && aAudioEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
}
RefPtr<Runnable> task = NewTaskFrom([id, aWindowId, aVideoType, aAudioType,
aVideoEnumType, aAudioEnumType,
videoLoopDev, audioLoopDev,
hasVideo, hasAudio, fakeDeviceRequested,
realDeviceRequested]() {
// Only enumerate what's asked for, and only fake cams and mics.
RefPtr<MediaEngine> fakeBackend, realBackend;
if (fakeCams || fakeMics) {
if (fakeDeviceRequested) {
fakeBackend = new MediaEngineDefault();
}
if (realDevicesRequested) {
if (realDeviceRequested) {
MediaManager* manager = MediaManager::GetIfExists();
MOZ_RELEASE_ASSERT(manager); // Must exist while media thread is alive
realBackend = manager->GetBackend(aWindowId);
@ -1903,17 +1927,21 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
auto result = MakeUnique<SourceSet>();
if (hasVideo) {
nsTArray<RefPtr<MediaDevice>> videos;
GetSources(fakeCams? fakeBackend : realBackend, aWindowId, aVideoType,
videos, videoLoopDev.get());
SourceSet videos;
LOG(("EnumerateRawDevices Task: Getting video sources with %s backend",
aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
GetSources(aVideoEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
aWindowId, aVideoType, videos, videoLoopDev.get());
for (auto& source : videos) {
result->AppendElement(source);
}
}
if (hasAudio) {
nsTArray<RefPtr<MediaDevice>> audios;
GetSources(fakeMics? fakeBackend : realBackend, aWindowId, aAudioType,
audios, audioLoopDev.get());
SourceSet audios;
LOG(("EnumerateRawDevices Task: Getting audio sources with %s backend",
aVideoEnumType == DeviceEnumerationType::Fake ? "fake" : "real"));
GetSources(aAudioEnumType == DeviceEnumerationType::Fake ? fakeBackend : realBackend,
aWindowId, aAudioType, audios, audioLoopDev.get());
for (auto& source : audios) {
result->AppendElement(source);
}
@ -1931,7 +1959,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId,
}));
});
if (realDevicesRequested &&
if (realDeviceRequested &&
Preferences::GetBool("media.navigator.permission.device", false)) {
// Need to ask permission to retrieve list of all devices;
// notify frontend observer and wait for callback notification to post task.
@ -2260,7 +2288,9 @@ void MediaManager::OnDeviceChange() {
// On some Windows machine, if we call EnumertaeRawDevices immediately after receiving
// devicechange event, sometimes we would get outdated devices list.
PR_Sleep(PR_MillisecondsToInterval(100));
RefPtr<PledgeSourceSet> p = self->EnumerateRawDevices(0, MediaSourceEnum::Camera, MediaSourceEnum::Microphone, false);
RefPtr<PledgeSourceSet> p = self->EnumerateRawDevices(0,
MediaSourceEnum::Camera,
MediaSourceEnum::Microphone);
p->Then([self](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices);
nsTArray<nsString> deviceIDs;
@ -2722,21 +2752,56 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
rv = GenerateUUID(callID);
NS_ENSURE_SUCCESS(rv, rv);
bool fake = c.mFake.WasPassed()? c.mFake.Value() :
Preferences::GetBool("media.navigator.streams.fake");
bool hasVideo = videoType != MediaSourceEnum::Other;
bool hasAudio = audioType != MediaSourceEnum::Other;
bool fakeCams = fake && videoType == MediaSourceEnum::Camera;
bool fakeMics = fake && audioType == MediaSourceEnum::Microphone;
bool realDevicesRequested = (!fakeCams && hasVideo) || (!fakeMics && hasAudio);
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
// Handle loopback and fake requests. For gUM we don't consider resist
// fingerprinting as users should be prompted anyway.
bool wantFakes = c.mFake.WasPassed() ? c.mFake.Value() :
Preferences::GetBool("media.navigator.streams.fake");
nsAutoCString videoLoopDev, audioLoopDev;
// Video
if (videoType == MediaSourceEnum::Camera) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
// Loopback prefs take precedence over fake prefs
if (!videoLoopDev.IsEmpty()) {
videoEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
videoEnumerationType = DeviceEnumerationType::Fake;
}
}
// Audio
if (audioType == MediaSourceEnum::Microphone) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
// Loopback prefs take precedence over fake prefs
if (!audioLoopDev.IsEmpty()) {
audioEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
audioEnumerationType = DeviceEnumerationType::Fake;
}
}
bool realDevicesRequested = (videoEnumerationType != DeviceEnumerationType::Fake && hasVideo) ||
(audioEnumerationType != DeviceEnumerationType::Fake && hasAudio);
bool askPermission =
(!privileged || Preferences::GetBool("media.navigator.permission.force")) &&
(realDevicesRequested || Preferences::GetBool("media.navigator.permission.fake"));
(!privileged || Preferences::GetBool("media.navigator.permission.force")) &&
(realDevicesRequested || Preferences::GetBool("media.navigator.permission.fake"));
LOG(("%s: Preparing to enumerate devices. windowId=%" PRIu64
", videoType=%" PRIu8 ", audioType=%" PRIu8
", videoEnumerationType=%" PRIu8 ", audioEnumerationType=%" PRIu8
", askPermission=%s",
__func__, windowID,
static_cast<uint8_t>(videoType), static_cast<uint8_t>(audioType),
static_cast<uint8_t>(videoEnumerationType), static_cast<uint8_t>(audioEnumerationType),
askPermission ? "true" : "false"));
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowID, videoType,
audioType, fake);
audioType,
videoEnumerationType,
audioEnumerationType);
RefPtr<MediaManager> self = this;
p->Then([self, onSuccess, onFailure, windowID, c, windowListener,
sourceListener, askPermission, prefs, isHTTPS, isHandlingUserInput,
@ -2953,9 +3018,16 @@ already_AddRefed<MediaManager::PledgeSourceSet>
MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
MediaSourceEnum aVideoType,
MediaSourceEnum aAudioType,
bool aFake)
DeviceEnumerationType aVideoEnumType /* = DeviceEnumerationType::Normal */,
DeviceEnumerationType aAudioEnumType /* = DeviceEnumerationType::Normal */)
{
MOZ_ASSERT(NS_IsMainThread());
LOG(("%s: aWindowId=%" PRIu64 ", aVideoType=%" PRIu8 ", aAudioType=%" PRIu8
", aVideoEnumType=%" PRIu8 ", aAudioEnumType=%" PRIu8,
__func__, aWindowId,
static_cast<uint8_t>(aVideoType), static_cast<uint8_t>(aAudioType),
static_cast<uint8_t>(aVideoEnumType), static_cast<uint8_t>(aAudioEnumType)));
nsPIDOMWindowInner* window =
nsGlobalWindowInner::GetInnerWindowWithId(aWindowId)->AsInner();
@ -2991,19 +3063,23 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
RefPtr<Pledge<nsCString>> p = media::GetPrincipalKey(principalInfo, persist);
p->Then([id, aWindowId, aVideoType, aAudioType,
aFake](const nsCString& aOriginKey) mutable {
aVideoEnumType, aAudioEnumType](const nsCString& aOriginKey) mutable {
MOZ_ASSERT(NS_IsMainThread());
MediaManager* mgr = MediaManager::GetIfExists();
if (!mgr) {
return;
}
RefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId, aVideoType,
aAudioType, aFake);
RefPtr<PledgeSourceSet> p = mgr->EnumerateRawDevices(aWindowId,
aVideoType,
aAudioType,
aVideoEnumType,
aAudioEnumType);
p->Then([id,
aWindowId,
aOriginKey,
aFake,
aVideoEnumType,
aAudioEnumType,
aVideoType,
aAudioType](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices); // secondary result
@ -3014,9 +3090,12 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
return NS_OK;
}
// If we fetched any real cameras or mics, remove the "default" part of
// their IDs.
if (aVideoType == MediaSourceEnum::Camera &&
aAudioType == MediaSourceEnum::Microphone &&
!aFake) {
(aVideoEnumType != DeviceEnumerationType::Fake ||
aAudioEnumType != DeviceEnumerationType::Fake)) {
mgr->mDeviceIDs.Clear();
for (auto& device : *devices) {
nsString id;
@ -3071,13 +3150,41 @@ MediaManager::EnumerateDevices(nsPIDOMWindowInner* aWindow,
RefPtr<SourceListener> sourceListener = new SourceListener();
windowListener->Register(sourceListener);
bool fake = Preferences::GetBool("media.navigator.streams.fake") ||
nsContentUtils::ResistFingerprinting(aCallerType);
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
// In order of precedence: resist fingerprinting > loopback > fake pref
if (resistFingerprinting) {
videoEnumerationType = DeviceEnumerationType::Fake;
audioEnumerationType = DeviceEnumerationType::Fake;
} else {
// Handle loopback and fake requests
nsAutoCString videoLoopDev, audioLoopDev;
bool wantFakes = Preferences::GetBool("media.navigator.streams.fake");
// Video
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
// Loopback prefs take precedence over fake prefs
if (!videoLoopDev.IsEmpty()) {
videoEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
videoEnumerationType = DeviceEnumerationType::Fake;
}
// Audio
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
// Loopback prefs take precedence over fake prefs
if (!audioLoopDev.IsEmpty()) {
audioEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
audioEnumerationType = DeviceEnumerationType::Fake;
}
}
RefPtr<PledgeSourceSet> p = EnumerateDevicesImpl(windowId,
MediaSourceEnum::Camera,
MediaSourceEnum::Microphone,
fake);
videoEnumerationType,
audioEnumerationType);
p->Then([onSuccess, windowListener, sourceListener](SourceSet*& aDevices) mutable {
UniquePtr<SourceSet> devices(aDevices); // grab result
DebugOnly<bool> rv = windowListener->Remove(sourceListener);

Просмотреть файл

@ -231,16 +231,24 @@ public: // TODO: make private once we upgrade to GCC 4.8+ on linux.
static void AnonymizeDevices(SourceSet& aDevices, const nsACString& aOriginKey);
static already_AddRefed<nsIWritableVariant> ToJSArray(SourceSet& aDevices);
private:
enum class DeviceEnumerationType :uint8_t {
Normal, // Enumeration should not return loopback or fake devices
Fake, // Enumeration should return fake device(s)
Loopback /* Enumeration should return loopback device(s) (possibly in
addition to normal devices) */
};
already_AddRefed<PledgeSourceSet>
EnumerateRawDevices(uint64_t aWindowId,
dom::MediaSourceEnum aVideoType,
dom::MediaSourceEnum aAudioType,
bool aFake);
DeviceEnumerationType aVideoEnumType = DeviceEnumerationType::Normal,
DeviceEnumerationType aAudioEnumType = DeviceEnumerationType::Normal);
already_AddRefed<PledgeSourceSet>
EnumerateDevicesImpl(uint64_t aWindowId,
dom::MediaSourceEnum aVideoSrcType,
dom::MediaSourceEnum aAudioSrcType,
bool aFake = false);
dom::MediaSourceEnum aVideoType,
dom::MediaSourceEnum aAudioType,
DeviceEnumerationType aVideoEnumType = DeviceEnumerationType::Normal,
DeviceEnumerationType aAudioEnumType = DeviceEnumerationType::Normal);
already_AddRefed<PledgeChar>
SelectSettings(
dom::MediaStreamConstraints& aConstraints,

Просмотреть файл

@ -2047,9 +2047,13 @@ MediaStream::RemoveAllListenersImpl()
}
mTrackListeners.Clear();
if (SourceMediaStream* source = AsSourceStream()) {
source->RemoveAllDirectListeners();
RemoveAllDirectListenersImpl();
auto videoOutputs(mVideoOutputs);
for (auto& l : videoOutputs) {
l.mListener->NotifyRemoved();
}
mVideoOutputs.Clear();
}
void
@ -3266,7 +3270,7 @@ SourceMediaStream::EndAllTrackAndFinish()
}
void
SourceMediaStream::RemoveAllDirectListeners()
SourceMediaStream::RemoveAllDirectListenersImpl()
{
GraphImpl()->AssertOnGraphThreadOrNotRunning();

Просмотреть файл

@ -428,6 +428,12 @@ public:
void RemoveVideoOutputImpl(MediaStreamVideoSink* aSink, TrackID aID);
void AddListenerImpl(already_AddRefed<MediaStreamListener> aListener);
void RemoveListenerImpl(MediaStreamListener* aListener);
/**
* Removes all direct listeners and signals to them that they have been
* uninstalled.
*/
virtual void RemoveAllDirectListenersImpl() {}
void RemoveAllListenersImpl();
virtual void AddTrackListenerImpl(already_AddRefed<MediaStreamTrackListener> aListener,
TrackID aTrackID);
@ -801,18 +807,14 @@ public:
MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment);
}
void RemoveAllDirectListenersImpl() override;
/**
* End all tracks and Finish() this stream. Used to voluntarily revoke access
* to a LocalMediaStream.
*/
void EndAllTrackAndFinish();
/**
* Removes all direct listeners and signals to them that they have been
* uninstalled.
*/
void RemoveAllDirectListeners();
void RegisterForAudioMixing();
/**

Просмотреть файл

@ -481,4 +481,24 @@ TrackUnionStream::RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener*
}
}
}
void TrackUnionStream::RemoveAllDirectListenersImpl()
{
for (TrackMapEntry& entry : mTrackMap) {
nsTArray<RefPtr<DirectMediaStreamTrackListener>>
listeners(entry.mOwnedDirectListeners);
for (const auto& listener : listeners) {
RemoveDirectTrackListenerImpl(listener, entry.mOutputTrackID);
}
MOZ_DIAGNOSTIC_ASSERT(entry.mOwnedDirectListeners.IsEmpty());
}
nsTArray<TrackBound<DirectMediaStreamTrackListener>>
boundListeners(mPendingDirectTrackListeners);
for (const auto& binding : boundListeners) {
RemoveDirectTrackListenerImpl(binding.mListener, binding.mTrackID);
}
MOZ_DIAGNOSTIC_ASSERT(mPendingDirectTrackListeners.IsEmpty());
}
} // namespace mozilla

Просмотреть файл

@ -74,6 +74,7 @@ protected:
TrackID aTrackID) override;
void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID) override;
void RemoveAllDirectListenersImpl() override;
nsTArray<TrackMapEntry> mTrackMap;

Просмотреть файл

@ -167,6 +167,19 @@ void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer,
}
}
uint32_t DecideAudioPlaybackChannels(const AudioInfo& info)
{
if (MediaPrefs::MonoAudio()) {
return 1;
}
if (MediaPrefs::AudioSinkForceStereo()) {
return 2;
}
return info.mChannels;
}
bool
IsVideoContentType(const nsCString& aContentType)
{

Просмотреть файл

@ -158,6 +158,10 @@ ScaleDisplayByAspectRatio(gfx::IntSize& aDisplay, float aAspectRatio);
void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer,
uint32_t aFrames);
// Decide the number of playback channels according to the
// given AudioInfo and the prefs that are being set.
uint32_t DecideAudioPlaybackChannels(const AudioInfo& info);
bool IsVideoContentType(const nsCString& aContentType);
// Returns true if it's safe to use aPicture as the picture to be

Просмотреть файл

@ -64,12 +64,7 @@ AudioSink::AudioSink(AbstractThread* aThread,
}
MOZ_DIAGNOSTIC_ASSERT(mOutputRate, "output rate can't be 0.");
bool monoAudioEnabled = MediaPrefs::MonoAudio();
mOutputChannels =
monoAudioEnabled
? 1
: (MediaPrefs::AudioSinkForceStereo() ? 2 : mInfo.mChannels);
mOutputChannels = DecideAudioPlaybackChannels(mInfo);
}
AudioSink::~AudioSink()

Просмотреть файл

@ -95,6 +95,17 @@ OpusDataDecoder::Init()
mOpusParser->mCoupledStreams,
mMappingTable.Elements(),
&r);
// Opus has a special feature for stereo coding where it represent wide
// stereo channels by 180-degree out of phase. This improves quality, but
// needs to be disabled when the output is downmixed to mono. Playback number
// of channels are set in AudioSink, using the same method
// `DecideAudioPlaybackChannels()`, and triggers downmix if needed.
if (mOpusDecoder && mOpusParser->mChannels == 2 &&
DecideAudioPlaybackChannels(mInfo) == 1) {
opus_multistream_decoder_ctl(mOpusDecoder, OPUS_SET_PHASE_INVERSION_DISABLED(1));
}
mSkip = mOpusParser->mPreSkip;
mPaddingDiscarded = false;

Просмотреть файл

@ -0,0 +1,87 @@
// Support script for test that use getUserMedia. This allows explicit
// configuration of prefs which affect gUM. See also
// `testing/mochitest/runtests.py` for how the harness configures values.
// Setup preconditions for tests using getUserMedia. This functions helps
// manage different prefs that affect gUM calls in tests and makes explicit
// the expected state before test runs.
async function pushGetUserMediaTestPrefs({
fakeAudio = false,
fakeVideo = false,
loopbackAudio = false,
loopbackVideo = false}) {
// Make sure we have sensical arguments
if (!fakeAudio && !loopbackAudio) {
throw new Error("pushGetUserMediaTestPrefs: Should have fake or loopback audio!");
} else if (fakeAudio && loopbackAudio) {
throw new Error("pushGetUserMediaTestPrefs: Should not have both fake and loopback audio!");
}
if (!fakeVideo && !loopbackVideo) {
throw new Error("pushGetUserMediaTestPrefs: Should have fake or loopback video!");
} else if (fakeVideo && loopbackVideo) {
throw new Error("pushGetUserMediaTestPrefs: Should not have both fake and loopback video!");
}
let testPrefs = [];
if (fakeAudio) {
// Unset the loopback device so it doesn't take precedence
testPrefs.push(["media.audio_loopback_dev", ""]);
// Setup fake streams pref
testPrefs.push(["media.navigator.streams.fake", true]);
}
if (loopbackAudio) {
// If audio loopback is requested we expect the test harness to have set
// the loopback device pref, make sure it's set
let audioLoopDev = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
if (!audioLoopDev) {
throw new Error("pushGetUserMediaTestPrefs: Loopback audio requested but " +
"media.audio_loopback_dev does not appear to be set!");
}
}
if (fakeVideo) {
// Unset the loopback device so it doesn't take precedence
testPrefs.push(["media.video_loopback_dev", ""]);
// Setup fake streams pref
testPrefs.push(["media.navigator.streams.fake", true]);
}
if (loopbackVideo) {
// If video loopback is requested we expect the test harness to have set
// the loopback device pref, make sure it's set
let videoLoopDev = SpecialPowers.getCharPref("media.video_loopback_dev", "");
if (!videoLoopDev) {
throw new Error("pushGetUserMediaTestPrefs: Loopback video requested but " +
"media.video_loopback_dev does not appear to be set!");
}
}
if (loopbackAudio || loopbackVideo) {
// Prevent gUM permission prompt. Since loopback devices are considered
// real devices we need to set prefs so the gUM prompt isn't presented.
testPrefs.push(['media.navigator.permission.disabled', true]);
}
return SpecialPowers.pushPrefEnv({set: testPrefs});
}
// Setup preconditions for tests using getUserMedia. This function will
// configure prefs to select loopback device(s) if it can find loopback device
// names already set in the prefs. If no loopback device name can be found then
// prefs are setup such that a fake device is used.
async function setupGetUserMediaTestPrefs() {
prefRequests = {};
let audioLoopDev = SpecialPowers.getCharPref("media.audio_loopback_dev", "");
if (audioLoopDev) {
prefRequests.fakeAudio = false;
prefRequests.loopbackAudio = true;
} else {
prefRequests.fakeAudio = true;
prefRequests.loopbackAudio = false;
}
let videoLoopDev = SpecialPowers.getCharPref("media.video_loopback_dev", "");
if (videoLoopDev) {
prefRequests.fakeVideo = false;
prefRequests.loopbackVideo = true;
} else {
prefRequests.fakeVideo = true;
prefRequests.loopbackVideo = false;
}
return pushGetUserMediaTestPrefs(prefRequests);
}

Просмотреть файл

@ -457,6 +457,7 @@ support-files =
gizmo.webm^headers^
gizmo-noaudio.webm
gizmo-noaudio.webm^headers^
gUM_support.js
gzipped_mp4.sjs
huge-id3.mp3
huge-id3.mp3^headers^
@ -607,6 +608,8 @@ support-files =
test-7-6.1.opus^headers^
test-8-7.1.opus
test-8-7.1.opus^headers^
test-stereo-phase-inversion-180.opus
test-stereo-phase-inversion-180.opus^headers^
variable-channel.ogg
variable-channel.ogg^headers^
variable-channel.opus
@ -1273,3 +1276,5 @@ tags = hls
# We could skip the test in that case as we cannot play 2 video at a time.
skip-if = toolkit != 'android' || android_version < '18'
tags = hls
[test_bug1431810_opus_downmix_to_mono.html]

Двоичные данные
dom/media/test/test-stereo-phase-inversion-180.opus Normal file

Двоичный файл не отображается.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше