зеркало из https://github.com/mozilla/gecko-dev.git
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:
Коммит
8d268c6ce7
|
@ -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/.*
|
||||
|
|
|
@ -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});
|
||||
});
|
||||
|
|
Двоичный файл не отображается.
|
@ -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]
|
||||
|
|
Двоичный файл не отображается.
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче