зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
786d0c66bc
|
@ -385,7 +385,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dogear 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dogear 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"moz_task 0.1.0",
|
"moz_task 0.1.0",
|
||||||
|
@ -956,7 +956,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dogear"
|
name = "dogear"
|
||||||
version = "0.3.1"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3947,7 +3947,7 @@ dependencies = [
|
||||||
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
|
"checksum devd-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d009f166c0d9e9f9909dc751630b3a6411ab7f85a153d32d01deb364ffe52a7"
|
||||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||||
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
|
"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a"
|
||||||
"checksum dogear 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "251a15c9a597d70eb53cbb0c5473d8d8c6241aef615c092030ebab27fb5b26ef"
|
"checksum dogear 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57cd6ee785daa898686f3e2fb4a2b1ce490fcd6d69665c857d16fb61b48f4aae"
|
||||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||||
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
|
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
|
||||||
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"
|
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"
|
||||||
|
|
|
@ -112,6 +112,7 @@ support-files =
|
||||||
test_no_mcb_on_http_site_font2.html
|
test_no_mcb_on_http_site_font2.html
|
||||||
test_no_mcb_on_http_site_font2.css
|
test_no_mcb_on_http_site_font2.css
|
||||||
[browser_no_mcb_for_loopback.js]
|
[browser_no_mcb_for_loopback.js]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
tags = mcb
|
tags = mcb
|
||||||
support-files =
|
support-files =
|
||||||
../general/moz.png
|
../general/moz.png
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
--sidebar-width: 320px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 320px 1fr;
|
grid-template-columns: var(--sidebar-width) 1fr;
|
||||||
grid-template-rows: 75px 1fr;
|
grid-template-rows: 75px 1fr;
|
||||||
grid-template-areas: "header header"
|
grid-template-areas: "header header"
|
||||||
"logins login";
|
"logins login";
|
||||||
|
@ -17,12 +18,13 @@ header {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: var(--in-content-box-background);
|
background-color: var(--in-content-box-background);
|
||||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||||
padding-inline: 60px 23px;
|
padding-inline-end: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
login-filter {
|
login-filter {
|
||||||
max-width: 30%;
|
min-width: 320px;
|
||||||
margin: auto;
|
max-width: 400px;
|
||||||
|
margin-inline: 40px auto;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
@ -52,8 +54,9 @@ login-item {
|
||||||
}
|
}
|
||||||
|
|
||||||
#branding-logo {
|
#branding-logo {
|
||||||
|
flex-basis: var(--sidebar-width);
|
||||||
|
flex-shrink: 0;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin-inline-end: 18px;
|
|
||||||
-moz-context-properties: fill;
|
-moz-context-properties: fill;
|
||||||
fill: #20123a;
|
fill: #20123a;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
.fxaccounts-avatar-button {
|
.fxaccounts-avatar-button {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fxaccount-email {
|
.fxaccount-email {
|
||||||
|
|
|
@ -978,6 +978,12 @@ var Policies = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
OfferToSaveLoginsDefault: {
|
||||||
|
onBeforeUIStartup(manager, param) {
|
||||||
|
setDefaultPref("signon.rememberSignons", param);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
OverrideFirstRunPage: {
|
OverrideFirstRunPage: {
|
||||||
onProfileAfterChange(manager, param) {
|
onProfileAfterChange(manager, param) {
|
||||||
let url = param ? param.href : "";
|
let url = param ? param.href : "";
|
||||||
|
|
|
@ -497,6 +497,10 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"OfferToSaveLoginsDefault": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
|
||||||
"OverrideFirstRunPage": {
|
"OverrideFirstRunPage": {
|
||||||
"type": "URLorEmpty"
|
"type": "URLorEmpty"
|
||||||
},
|
},
|
||||||
|
|
|
@ -456,6 +456,16 @@ const POLICIES_TESTS = [
|
||||||
"browser.newtabpage.activity-stream.feeds.section.topstories": false,
|
"browser.newtabpage.activity-stream.feeds.section.topstories": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// POLICY: OfferToSaveLoginsDefault
|
||||||
|
{
|
||||||
|
policies: {
|
||||||
|
OfferToSaveLoginsDefault: false,
|
||||||
|
},
|
||||||
|
unlockedPrefs: {
|
||||||
|
"signon.rememberSignons": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
add_task(async function test_policy_simple_prefs() {
|
add_task(async function test_policy_simple_prefs() {
|
||||||
|
|
|
@ -205,7 +205,9 @@ class TabsUpdateFilterEventManager extends EventManager {
|
||||||
let register = (fire, filterProps) => {
|
let register = (fire, filterProps) => {
|
||||||
let filter = { ...filterProps };
|
let filter = { ...filterProps };
|
||||||
if (filter.urls) {
|
if (filter.urls) {
|
||||||
filter.urls = new MatchPatternSet(filter.urls);
|
filter.urls = new MatchPatternSet(filter.urls, {
|
||||||
|
restrictSchemes: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
let needsModified = true;
|
let needsModified = true;
|
||||||
if (filter.properties) {
|
if (filter.properties) {
|
||||||
|
@ -944,7 +946,9 @@ this.tabs = class extends ExtensionAPI {
|
||||||
queryInfo = Object.assign({}, queryInfo);
|
queryInfo = Object.assign({}, queryInfo);
|
||||||
|
|
||||||
if (queryInfo.url !== null) {
|
if (queryInfo.url !== null) {
|
||||||
queryInfo.url = new MatchPatternSet([].concat(queryInfo.url));
|
queryInfo.url = new MatchPatternSet([].concat(queryInfo.url), {
|
||||||
|
restrictSchemes: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (queryInfo.title !== null) {
|
if (queryInfo.title !== null) {
|
||||||
queryInfo.title = new MatchGlob(queryInfo.title);
|
queryInfo.title = new MatchGlob(queryInfo.title);
|
||||||
|
|
|
@ -164,6 +164,7 @@ skip-if = (verify && debug && (os == 'mac'))
|
||||||
[browser_ext_pageAction_simple.js]
|
[browser_ext_pageAction_simple.js]
|
||||||
[browser_ext_pageAction_telemetry.js]
|
[browser_ext_pageAction_telemetry.js]
|
||||||
[browser_ext_pageAction_title.js]
|
[browser_ext_pageAction_title.js]
|
||||||
|
skip-if = fission # Timeouts Bug 1574926
|
||||||
[browser_ext_popup_api_injection.js]
|
[browser_ext_popup_api_injection.js]
|
||||||
[browser_ext_popup_background.js]
|
[browser_ext_popup_background.js]
|
||||||
[browser_ext_popup_corners.js]
|
[browser_ext_popup_corners.js]
|
||||||
|
|
|
@ -21,56 +21,38 @@ add_task(async function() {
|
||||||
permissions: ["tabs"],
|
permissions: ["tabs"],
|
||||||
},
|
},
|
||||||
|
|
||||||
background: function() {
|
async background() {
|
||||||
browser.tabs.query(
|
let tabs = await browser.tabs.query({ lastFocusedWindow: true });
|
||||||
{
|
browser.test.assertEq(tabs.length, 3, "should have three tabs");
|
||||||
lastFocusedWindow: true,
|
|
||||||
},
|
|
||||||
function(tabs) {
|
|
||||||
browser.test.assertEq(tabs.length, 3, "should have three tabs");
|
|
||||||
|
|
||||||
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
|
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
|
||||||
|
|
||||||
browser.test.assertEq(tabs[0].url, "about:blank", "first tab blank");
|
browser.test.assertEq(tabs[0].url, "about:blank", "first tab blank");
|
||||||
tabs.shift();
|
tabs.shift();
|
||||||
|
|
||||||
browser.test.assertTrue(tabs[0].active, "tab 0 active");
|
browser.test.assertTrue(tabs[0].active, "tab 0 active");
|
||||||
browser.test.assertFalse(tabs[1].active, "tab 1 inactive");
|
browser.test.assertFalse(tabs[1].active, "tab 1 inactive");
|
||||||
|
|
||||||
browser.test.assertFalse(tabs[0].pinned, "tab 0 unpinned");
|
browser.test.assertFalse(tabs[0].pinned, "tab 0 unpinned");
|
||||||
browser.test.assertFalse(tabs[1].pinned, "tab 1 unpinned");
|
browser.test.assertFalse(tabs[1].pinned, "tab 1 unpinned");
|
||||||
|
|
||||||
browser.test.assertEq(
|
browser.test.assertEq(tabs[0].url, "about:robots", "tab 0 url correct");
|
||||||
tabs[0].url,
|
browser.test.assertEq(tabs[1].url, "about:config", "tab 1 url correct");
|
||||||
"about:robots",
|
|
||||||
"tab 0 url correct"
|
|
||||||
);
|
|
||||||
browser.test.assertEq(
|
|
||||||
tabs[1].url,
|
|
||||||
"about:config",
|
|
||||||
"tab 1 url correct"
|
|
||||||
);
|
|
||||||
|
|
||||||
browser.test.assertEq(
|
browser.test.assertEq(tabs[0].status, "complete", "tab 0 status correct");
|
||||||
tabs[0].status,
|
browser.test.assertEq(tabs[1].status, "complete", "tab 1 status correct");
|
||||||
"complete",
|
|
||||||
"tab 0 status correct"
|
|
||||||
);
|
|
||||||
browser.test.assertEq(
|
|
||||||
tabs[1].status,
|
|
||||||
"complete",
|
|
||||||
"tab 1 status correct"
|
|
||||||
);
|
|
||||||
|
|
||||||
browser.test.assertEq(
|
browser.test.assertEq(
|
||||||
tabs[0].title,
|
tabs[0].title,
|
||||||
"Gort! Klaatu barada nikto!",
|
"Gort! Klaatu barada nikto!",
|
||||||
"tab 0 title correct"
|
"tab 0 title correct"
|
||||||
);
|
|
||||||
|
|
||||||
browser.test.notifyPass("tabs.query");
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
tabs = await browser.tabs.query({ url: "about:blank" });
|
||||||
|
browser.test.assertEq(tabs.length, 1, "about:blank query finds one tab");
|
||||||
|
browser.test.assertEq(tabs[0].url, "about:blank", "with the correct url");
|
||||||
|
|
||||||
|
browser.test.notifyPass("tabs.query");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ support-files =
|
||||||
[browser_block_mozAddonManager.js]
|
[browser_block_mozAddonManager.js]
|
||||||
[browser_dynamical_window_rounding.js]
|
[browser_dynamical_window_rounding.js]
|
||||||
[browser_navigator.js]
|
[browser_navigator.js]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
[browser_netInfo.js]
|
[browser_netInfo.js]
|
||||||
[browser_performanceAPI.js]
|
[browser_performanceAPI.js]
|
||||||
[browser_roundedWindow_dialogWindow.js]
|
[browser_roundedWindow_dialogWindow.js]
|
||||||
|
|
|
@ -72,6 +72,7 @@ support-files =
|
||||||
skip-if = (os == 'mac' && os_version == '10.14') # bug 1554807
|
skip-if = (os == 'mac' && os_version == '10.14') # bug 1554807
|
||||||
[browser_locationBarExternalLoad.js]
|
[browser_locationBarExternalLoad.js]
|
||||||
[browser_moz_action_link.js]
|
[browser_moz_action_link.js]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
[browser_new_tab_urlbar_reset.js]
|
[browser_new_tab_urlbar_reset.js]
|
||||||
[browser_openViewOnFocus.js]
|
[browser_openViewOnFocus.js]
|
||||||
[browser_pasteAndGo.js]
|
[browser_pasteAndGo.js]
|
||||||
|
|
|
@ -41,7 +41,6 @@ ac_add_options --disable-jemalloc
|
||||||
ac_add_options --enable-proxy-bypass-protection
|
ac_add_options --enable-proxy-bypass-protection
|
||||||
|
|
||||||
# These aren't supported on mingw at this time
|
# These aren't supported on mingw at this time
|
||||||
ac_add_options --disable-maintenance-service
|
|
||||||
ac_add_options --disable-webrtc # Bug 1393901
|
ac_add_options --disable-webrtc # Bug 1393901
|
||||||
ac_add_options --disable-geckodriver # Bug 1489320
|
ac_add_options --disable-geckodriver # Bug 1489320
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ ac_add_options --disable-jemalloc
|
||||||
ac_add_options --enable-proxy-bypass-protection
|
ac_add_options --enable-proxy-bypass-protection
|
||||||
|
|
||||||
# These aren't supported on mingw at this time
|
# These aren't supported on mingw at this time
|
||||||
ac_add_options --disable-maintenance-service
|
|
||||||
ac_add_options --disable-webrtc # Bug 1393901
|
ac_add_options --disable-webrtc # Bug 1393901
|
||||||
ac_add_options --disable-geckodriver # Bug 1489320
|
ac_add_options --disable-geckodriver # Bug 1489320
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,8 @@ policy-NoDefaultBookmarks = Disable creation of the default bookmarks bundled wi
|
||||||
|
|
||||||
policy-OfferToSaveLogins = Enforce the setting to allow { -brand-short-name } to offer to remember saved logins and passwords. Both true and false values are accepted.
|
policy-OfferToSaveLogins = Enforce the setting to allow { -brand-short-name } to offer to remember saved logins and passwords. Both true and false values are accepted.
|
||||||
|
|
||||||
|
policy-OfferToSaveLoginsDefault = Set the default value for allowing { -brand-short-name } to offer to remember saved logins and passwords. Both true and false values are accepted.
|
||||||
|
|
||||||
policy-OverrideFirstRunPage = Override the first run page. Set this policy to blank if you want to disable the first run page.
|
policy-OverrideFirstRunPage = Override the first run page. Set this policy to blank if you want to disable the first run page.
|
||||||
|
|
||||||
policy-OverridePostUpdatePage = Override the post-update “What’s New” page. Set this policy to blank if you want to disable the post-update page.
|
policy-OverridePostUpdatePage = Override the post-update “What’s New” page. Set this policy to blank if you want to disable the post-update page.
|
||||||
|
|
|
@ -274,10 +274,6 @@
|
||||||
|
|
||||||
%include ../shared/identity-block/identity-block.inc.css
|
%include ../shared/identity-block/identity-block.inc.css
|
||||||
|
|
||||||
#wrapper-urlbar-container[place="palette"] {
|
|
||||||
max-width: 20em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pageAction-urlbar-shareURL,
|
#pageAction-urlbar-shareURL,
|
||||||
#pageAction-panel-shareURL {
|
#pageAction-panel-shareURL {
|
||||||
list-style-image: url("chrome://browser/skin/share.svg");
|
list-style-image: url("chrome://browser/skin/share.svg");
|
||||||
|
|
|
@ -1699,14 +1699,13 @@ toolbarpaletteitem[place="menu-panel"] > .subviewbutton-nav::after {
|
||||||
border-bottom: 1px solid var(--panel-separator-color);
|
border-bottom: 1px solid var(--panel-separator-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 auto;
|
flex: 1 auto;
|
||||||
height: 40px; /* fixed item height to prevent flex sizing; height + 2*4px padding */
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-header > label {
|
.panel-header > label {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin: 0;
|
margin: 4px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -574,10 +574,6 @@ menuitem.bookmark-item {
|
||||||
%include ../shared/autocomplete.inc.css
|
%include ../shared/autocomplete.inc.css
|
||||||
%include ../shared/urlbar-autocomplete.inc.css
|
%include ../shared/urlbar-autocomplete.inc.css
|
||||||
|
|
||||||
.urlbarView {
|
|
||||||
font-size: 1.15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#PopupAutoComplete > richlistbox > richlistitem[originaltype~="datalist-first"] {
|
#PopupAutoComplete > richlistbox > richlistitem[originaltype~="datalist-first"] {
|
||||||
border-top: 1px solid ThreeDShadow;
|
border-top: 1px solid ThreeDShadow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ Important Concepts
|
||||||
sparse
|
sparse
|
||||||
Support for projects building with GN <gn>
|
Support for projects building with GN <gn>
|
||||||
telemetry
|
telemetry
|
||||||
|
sccache-dist
|
||||||
test_certificates
|
test_certificates
|
||||||
|
|
||||||
integrated development environment (IDE)
|
integrated development environment (IDE)
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
.. _sccache_dist:
|
||||||
|
|
||||||
|
==================================
|
||||||
|
Distributed sccache (sccache-dist)
|
||||||
|
==================================
|
||||||
|
|
||||||
|
`sccache <https://github.com/mozilla/sccache>`_ is a ccache-like tool written in
|
||||||
|
rust.
|
||||||
|
|
||||||
|
Distributed sccache (also referred to as sccache-dist) is being rolled out to
|
||||||
|
Mozilla offices as a replacement for icecc. The steps for setting up your
|
||||||
|
machine as an sccache-dist server as well as distributing your build to servers
|
||||||
|
in your office are detailed below.
|
||||||
|
|
||||||
|
In addition to improved security properties, distributed sccache offers
|
||||||
|
distribution and caching of rust compilation, so it should be an improvement
|
||||||
|
above and beyond what we see with icecc. Build servers run on linux and
|
||||||
|
distributing builds is currently supported from macOS and linux machines.
|
||||||
|
Distribution from Windows is supported in principle but hasn't seen sufficient
|
||||||
|
testing.
|
||||||
|
|
||||||
|
Steps for distributing a build as an sccache-dist client
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
Start by following the instructions at https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#configure-a-client
|
||||||
|
to configure your sccache distributed client. Ignore the note about custom
|
||||||
|
toolchains if you're distributing compilation from linux.
|
||||||
|
sccache 0.2.10 or above is recommended, and the auth section of your config
|
||||||
|
must read::
|
||||||
|
|
||||||
|
[dist.auth]
|
||||||
|
type = "mozilla"
|
||||||
|
|
||||||
|
* The scheduler url to use is: ``https://sccache1.corpdmz.<OFFICE>.mozilla.com``,
|
||||||
|
where <OFFICE> is, for instance, sfo1. A complete list of office short names
|
||||||
|
to be used can be found `here <https://docs.google.com/spreadsheets/d/1alscUTcfFyu3L0vs_S_cGi9JxF4uPrfsmwJko9annWE/edit#gid=0>`_
|
||||||
|
|
||||||
|
* If you're compiling from a macOS client, there are a handful of additional
|
||||||
|
considerations detailed here:
|
||||||
|
https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#considerations-when-distributing-from-macos.
|
||||||
|
In particular, custom toolchains will need to be specified.
|
||||||
|
Run ``./mach bootstrap`` to download prebuilt toolchains and place them in
|
||||||
|
``~/.mozbuild/clang-dist-toolchain.tar.xz`` and
|
||||||
|
``~/.mozbuild/rustc-dist-toolchain.tar.xz``.
|
||||||
|
|
||||||
|
* Add the following to your mozconfig::
|
||||||
|
|
||||||
|
ac_add_options CCACHE=/path/to/sccache
|
||||||
|
|
||||||
|
* When attempting to get your client running, the output of ``sccache -s`` should
|
||||||
|
be consulted to confirm compilations are being distributed. To receive helpful
|
||||||
|
logging from the local daemon in case they aren't, run
|
||||||
|
``SCCACHE_NO_DAEMON=1 RUST_LOG=sccache=trace path/to/sccache --start-server``
|
||||||
|
in a terminal window separate from your build prior to building.
|
||||||
|
|
||||||
|
* Run ``./mach build -j<value>`` with an appropriately large ``<value>``.
|
||||||
|
``sccache --dist-status`` should provide the number of cores available to you
|
||||||
|
(or a message if you're not connected). In the future this will be integrated
|
||||||
|
with the build system to automatically select an appropriate value.
|
||||||
|
|
||||||
|
This should be enough to distribute your build and replace your use of icecc.
|
||||||
|
Bear in mind there may be a few speedbumps, and please ensure your version of
|
||||||
|
sccache is current before investigating further. Please see the common questions
|
||||||
|
section below and ask for help if anything is preventing you from using it over
|
||||||
|
email (dev-builds), on slack in #sccache, or in #build on irc.
|
||||||
|
|
||||||
|
Steps for setting up a server
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Build servers must run linux and use bubblewrap 3.0+ for sandboxing of compile
|
||||||
|
processes. This requires a kernel 4.6 or greater, so Ubuntu 18+, RHEL 8, or
|
||||||
|
similar.
|
||||||
|
|
||||||
|
* Acquire a recent build of sccache. ``./mach bootstrap`` or
|
||||||
|
``./mach artifact toolchain --from-build linux64-sccache`` will provide this.
|
||||||
|
``cargo install`` may also be used, but ensure the version for the ``sccache``
|
||||||
|
and ``sccache-dist`` binaries you end up using is 0.2.10 or above.
|
||||||
|
Alternatively, the source is available at https://github.com/mozilla/sccache
|
||||||
|
and should be built with the ``dist-server`` feature selected if building from
|
||||||
|
there.
|
||||||
|
|
||||||
|
* Collect the IP of your builder and request assignment of a static IP in a bug
|
||||||
|
filed in
|
||||||
|
`NetOps :: Other <https://bugzilla.mozilla.org/enter_bug.cgi?product=Infrastructure%20%26%20Operations&component=NetOps%3A%20Office%20Other>`_
|
||||||
|
cc sccache-admins@mozilla.com on this bug.
|
||||||
|
|
||||||
|
* File a bug in
|
||||||
|
`Infrastructure :: Other <https://bugzilla.mozilla.org/enter_bug.cgi?product=Infrastructure+%26+Operations&component=Infrastructure%3A+Other>`_
|
||||||
|
asking for an sccache builder auth token to be generated for your builder.
|
||||||
|
The bug should include your name, office, where in the office the builder is
|
||||||
|
located (desk, closet, etc - so IT can physically find it if needed), the IP
|
||||||
|
address, and a secure method to reach you (gpg, keybase.io, etc). An auth
|
||||||
|
token will be generated and delivered to you.
|
||||||
|
|
||||||
|
* The instructions at https://github.com/mozilla/sccache/blob/master/docs/DistributedQuickstart.md#configure-a-build-server
|
||||||
|
should contain everything else required to configure and run the server.
|
||||||
|
|
||||||
|
|
||||||
|
Common questions/considerations
|
||||||
|
===============================
|
||||||
|
|
||||||
|
* My build is still slow: scache-dist can only do so much with parts of the
|
||||||
|
build that aren't able to be parallelized. To start debugging a slow build,
|
||||||
|
ensure the "Successful distributed compilations" line in the output of
|
||||||
|
``sccache -s`` dominates other counts. For a full build, at least a 2-3x
|
||||||
|
improvement should be observed.
|
||||||
|
|
||||||
|
* My build output is incomprehensible due to a flood of warnings: clang will
|
||||||
|
treat some warnings differently when its fed preprocessed code in a separate
|
||||||
|
invocation (preprocessing occurs locally with sccache-dist). See the
|
||||||
|
following note about disabling problematic warnings:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Using_Icecream#I_get_build_failures_due_to_-Werror_when_building_remotely_but_not_when_building_locally
|
||||||
|
|
||||||
|
* My build fails with a message about incompatible versions of rustc between
|
||||||
|
dependent crates: if you're using a custom toolchain check that the version
|
||||||
|
of rustc in your ``rustc-dist-toolchain.tar.xz`` is the same as the version
|
||||||
|
you're running locally.
|
|
@ -26,7 +26,7 @@ export { breakOnNext } from "./breakOnNext";
|
||||||
export { mapFrames } from "./mapFrames";
|
export { mapFrames } from "./mapFrames";
|
||||||
export { pauseOnExceptions } from "./pauseOnExceptions";
|
export { pauseOnExceptions } from "./pauseOnExceptions";
|
||||||
export { selectFrame } from "./selectFrame";
|
export { selectFrame } from "./selectFrame";
|
||||||
export { toggleSkipPausing } from "./skipPausing";
|
export { toggleSkipPausing, setSkipPausing } from "./skipPausing";
|
||||||
export { toggleMapScopes } from "./mapScopes";
|
export { toggleMapScopes } from "./mapScopes";
|
||||||
export { setExpandedScope } from "./expandScopes";
|
export { setExpandedScope } from "./expandScopes";
|
||||||
export { generateInlinePreview } from "./inlinePreview";
|
export { generateInlinePreview } from "./inlinePreview";
|
||||||
|
|
|
@ -18,3 +18,19 @@ export function toggleSkipPausing() {
|
||||||
dispatch({ type: "TOGGLE_SKIP_PAUSING", skipPausing });
|
dispatch({ type: "TOGGLE_SKIP_PAUSING", skipPausing });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @memberof actions/pause
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export function setSkipPausing(skipPausing: boolean) {
|
||||||
|
return async ({ dispatch, client, getState, sourceMaps }: ThunkArgs) => {
|
||||||
|
const currentlySkipping = getSkipPausing(getState());
|
||||||
|
if (currentlySkipping === skipPausing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.setSkipPausing(skipPausing);
|
||||||
|
dispatch({ type: "TOGGLE_SKIP_PAUSING", skipPausing });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@ jest.mock("../../utils/prefs", () => ({
|
||||||
pendingBreakpoints: {},
|
pendingBreakpoints: {},
|
||||||
},
|
},
|
||||||
clear: jest.fn(),
|
clear: jest.fn(),
|
||||||
|
features: {
|
||||||
|
inlinePreview: true,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -30,6 +30,10 @@ export type UIAction =
|
||||||
+type: "TOGGLE_FRAMEWORK_GROUPING",
|
+type: "TOGGLE_FRAMEWORK_GROUPING",
|
||||||
+value: boolean,
|
+value: boolean,
|
||||||
|}
|
|}
|
||||||
|
| {|
|
||||||
|
+type: "TOGGLE_INLINE_PREVIEW",
|
||||||
|
+value: boolean,
|
||||||
|
|}
|
||||||
| {|
|
| {|
|
||||||
+type: "SHOW_SOURCE",
|
+type: "SHOW_SOURCE",
|
||||||
+source: Source,
|
+source: Source,
|
||||||
|
|
|
@ -77,6 +77,15 @@ export function toggleFrameworkGrouping(toggleValue: boolean) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toggleInlinePreview(toggleValue: boolean) {
|
||||||
|
return ({ dispatch, getState }: ThunkArgs) => {
|
||||||
|
dispatch({
|
||||||
|
type: "TOGGLE_INLINE_PREVIEW",
|
||||||
|
value: toggleValue,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function showSource(cx: Context, sourceId: string) {
|
export function showSource(cx: Context, sourceId: string) {
|
||||||
return ({ dispatch, getState }: ThunkArgs) => {
|
return ({ dispatch, getState }: ThunkArgs) => {
|
||||||
const source = getSource(getState(), sourceId);
|
const source = getSource(getState(), sourceId);
|
||||||
|
|
|
@ -54,6 +54,7 @@ class InlinePreviews extends Component<Props> {
|
||||||
return (
|
return (
|
||||||
<InlinePreviewRow
|
<InlinePreviewRow
|
||||||
editor={editor}
|
editor={editor}
|
||||||
|
key={line}
|
||||||
line={lineNum}
|
line={lineNum}
|
||||||
previews={previews[line]}
|
previews={previews[line]}
|
||||||
numColumnBreakpoints={numColumnBreakpoints}
|
numColumnBreakpoints={numColumnBreakpoints}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import {
|
||||||
getCurrentThread,
|
getCurrentThread,
|
||||||
getThreadContext,
|
getThreadContext,
|
||||||
getSkipPausing,
|
getSkipPausing,
|
||||||
|
getInlinePreview,
|
||||||
} from "../../selectors";
|
} from "../../selectors";
|
||||||
|
|
||||||
// Redux actions
|
// Redux actions
|
||||||
|
@ -103,6 +104,7 @@ export type Props = {
|
||||||
symbols: SymbolDeclarations,
|
symbols: SymbolDeclarations,
|
||||||
isPaused: boolean,
|
isPaused: boolean,
|
||||||
skipPausing: boolean,
|
skipPausing: boolean,
|
||||||
|
inlinePreviewEnabled: boolean,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
openConditionalPanel: typeof actions.openConditionalPanel,
|
openConditionalPanel: typeof actions.openConditionalPanel,
|
||||||
|
@ -584,6 +586,7 @@ class Editor extends PureComponent<Props, State> {
|
||||||
selectedSource,
|
selectedSource,
|
||||||
conditionalPanelLocation,
|
conditionalPanelLocation,
|
||||||
isPaused,
|
isPaused,
|
||||||
|
inlinePreviewEnabled,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { editor, contextMenu } = this.state;
|
const { editor, contextMenu } = this.state;
|
||||||
|
|
||||||
|
@ -611,7 +614,7 @@ class Editor extends PureComponent<Props, State> {
|
||||||
{features.columnBreakpoints ? (
|
{features.columnBreakpoints ? (
|
||||||
<ColumnBreakpoints editor={editor} />
|
<ColumnBreakpoints editor={editor} />
|
||||||
) : null}
|
) : null}
|
||||||
{isPaused && features.inlinePreview ? (
|
{isPaused && inlinePreviewEnabled ? (
|
||||||
<InlinePreviews editor={editor} selectedSource={selectedSource} />
|
<InlinePreviews editor={editor} selectedSource={selectedSource} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -665,6 +668,7 @@ const mapStateToProps = state => {
|
||||||
symbols: getSymbols(state, selectedSource),
|
symbols: getSymbols(state, selectedSource),
|
||||||
isPaused: getIsPaused(state, getCurrentThread(state)),
|
isPaused: getIsPaused(state, getCurrentThread(state)),
|
||||||
skipPausing: getSkipPausing(state),
|
skipPausing: getSkipPausing(state),
|
||||||
|
inlinePreviewEnabled: getInlinePreview(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from "../../../utils/source";
|
} from "../../../utils/source";
|
||||||
|
|
||||||
import { downloadFile } from "../../../utils/utils";
|
import { downloadFile } from "../../../utils/utils";
|
||||||
|
import { features } from "../../../utils/prefs";
|
||||||
|
|
||||||
import { isFulfilled } from "../../../utils/async-value";
|
import { isFulfilled } from "../../../utils/async-value";
|
||||||
import actions from "../../../actions";
|
import actions from "../../../actions";
|
||||||
|
@ -159,6 +160,14 @@ const downloadFileItem = (
|
||||||
click: () => downloadFile(selectedContent, getFilename(selectedSource)),
|
click: () => downloadFile(selectedContent, getFilename(selectedSource)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const inlinePreviewItem = (editorActions: EditorItemActions) => ({
|
||||||
|
id: "node-menu-inline-preview",
|
||||||
|
label: features.inlinePreview
|
||||||
|
? L10N.getStr("inlinePreview.disable.label")
|
||||||
|
: L10N.getStr("inlinePreview.enable.label"),
|
||||||
|
click: () => editorActions.toggleInlinePreview(!features.inlinePreview),
|
||||||
|
});
|
||||||
|
|
||||||
export function editorMenuItems({
|
export function editorMenuItems({
|
||||||
cx,
|
cx,
|
||||||
editorActions,
|
editorActions,
|
||||||
|
@ -218,6 +227,8 @@ export function editorMenuItems({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items.push({ type: "separator" }, inlinePreviewItem(editorActions));
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,6 +240,7 @@ export type EditorItemActions = {
|
||||||
jumpToMappedLocation: typeof actions.jumpToMappedLocation,
|
jumpToMappedLocation: typeof actions.jumpToMappedLocation,
|
||||||
showSource: typeof actions.showSource,
|
showSource: typeof actions.showSource,
|
||||||
toggleBlackBox: typeof actions.toggleBlackBox,
|
toggleBlackBox: typeof actions.toggleBlackBox,
|
||||||
|
toggleInlinePreview: typeof actions.toggleInlinePreview,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function editorItemActions(dispatch: Function) {
|
export function editorItemActions(dispatch: Function) {
|
||||||
|
@ -241,6 +253,7 @@ export function editorItemActions(dispatch: Function) {
|
||||||
jumpToMappedLocation: actions.jumpToMappedLocation,
|
jumpToMappedLocation: actions.jumpToMappedLocation,
|
||||||
showSource: actions.showSource,
|
showSource: actions.showSource,
|
||||||
toggleBlackBox: actions.toggleBlackBox,
|
toggleBlackBox: actions.toggleBlackBox,
|
||||||
|
toggleInlinePreview: actions.toggleInlinePreview,
|
||||||
},
|
},
|
||||||
dispatch
|
dispatch
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Props = {
|
||||||
unHighlightDomElement: typeof actions.unHighlightDomElement,
|
unHighlightDomElement: typeof actions.unHighlightDomElement,
|
||||||
deleteBreakpoint: typeof deleteDOMMutationBreakpoint,
|
deleteBreakpoint: typeof deleteDOMMutationBreakpoint,
|
||||||
toggleBreakpoint: typeof toggleDOMMutationBreakpointState,
|
toggleBreakpoint: typeof toggleDOMMutationBreakpointState,
|
||||||
|
setSkipPausing: typeof actions.setSkipPausing,
|
||||||
};
|
};
|
||||||
|
|
||||||
const localizationTerms = {
|
const localizationTerms = {
|
||||||
|
@ -40,12 +41,22 @@ const localizationTerms = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class DOMMutationBreakpointsContents extends Component<Props> {
|
class DOMMutationBreakpointsContents extends Component<Props> {
|
||||||
|
handleBreakpoint(breakpointId, shouldEnable) {
|
||||||
|
const { toggleBreakpoint, setSkipPausing } = this.props;
|
||||||
|
|
||||||
|
// The user has enabled a mutation breakpoint so we should no
|
||||||
|
// longer skip pausing
|
||||||
|
if (shouldEnable) {
|
||||||
|
setSkipPausing(false);
|
||||||
|
}
|
||||||
|
toggleBreakpoint(breakpointId, shouldEnable);
|
||||||
|
}
|
||||||
|
|
||||||
renderItem(breakpoint: DOMMutationBreakpoint) {
|
renderItem(breakpoint: DOMMutationBreakpoint) {
|
||||||
const {
|
const {
|
||||||
openElementInInspector,
|
openElementInInspector,
|
||||||
highlightDomElement,
|
highlightDomElement,
|
||||||
unHighlightDomElement,
|
unHighlightDomElement,
|
||||||
toggleBreakpoint,
|
|
||||||
deleteBreakpoint,
|
deleteBreakpoint,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { enabled, id: breakpointId, nodeFront, mutationType } = breakpoint;
|
const { enabled, id: breakpointId, nodeFront, mutationType } = breakpoint;
|
||||||
|
@ -55,7 +66,7 @@ class DOMMutationBreakpointsContents extends Component<Props> {
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={enabled}
|
checked={enabled}
|
||||||
onChange={() => toggleBreakpoint(breakpointId, !enabled)}
|
onChange={() => this.handleBreakpoint(breakpointId, !enabled)}
|
||||||
/>
|
/>
|
||||||
<div className="dom-mutation-info">
|
<div className="dom-mutation-info">
|
||||||
<div className="dom-mutation-label">
|
<div className="dom-mutation-label">
|
||||||
|
@ -123,6 +134,7 @@ class DomMutationBreakpoints extends Component<Props> {
|
||||||
openElementInInspector={this.props.openElementInInspector}
|
openElementInInspector={this.props.openElementInInspector}
|
||||||
highlightDomElement={this.props.highlightDomElement}
|
highlightDomElement={this.props.highlightDomElement}
|
||||||
unHighlightDomElement={this.props.unHighlightDomElement}
|
unHighlightDomElement={this.props.unHighlightDomElement}
|
||||||
|
setSkipPausing={this.props.setSkipPausing}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -136,5 +148,6 @@ export default connect(
|
||||||
openElementInInspector: actions.openElementInInspectorCommand,
|
openElementInInspector: actions.openElementInInspectorCommand,
|
||||||
highlightDomElement: actions.highlightDomElement,
|
highlightDomElement: actions.highlightDomElement,
|
||||||
unHighlightDomElement: actions.unHighlightDomElement,
|
unHighlightDomElement: actions.unHighlightDomElement,
|
||||||
|
setSkipPausing: actions.setSkipPausing,
|
||||||
}
|
}
|
||||||
)(DomMutationBreakpoints);
|
)(DomMutationBreakpoints);
|
||||||
|
|
|
@ -343,6 +343,20 @@ function update(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable skipPausing if a breakpoint is enabled or added
|
||||||
|
case "SET_BREAKPOINT": {
|
||||||
|
return action.breakpoint.disabled
|
||||||
|
? state
|
||||||
|
: { ...state, skipPausing: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
case "UPDATE_EVENT_LISTENERS":
|
||||||
|
case "REMOVE_BREAKPOINT":
|
||||||
|
case "SET_XHR_BREAKPOINT":
|
||||||
|
case "ENABLE_XHR_BREAKPOINT": {
|
||||||
|
return { ...state, skipPausing: false };
|
||||||
|
}
|
||||||
|
|
||||||
case "TOGGLE_SKIP_PAUSING": {
|
case "TOGGLE_SKIP_PAUSING": {
|
||||||
const { skipPausing } = action;
|
const { skipPausing } = action;
|
||||||
prefs.skipPausing = skipPausing;
|
prefs.skipPausing = skipPausing;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* @module reducers/ui
|
* @module reducers/ui
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { prefs } from "../utils/prefs";
|
import { prefs, features } from "../utils/prefs";
|
||||||
|
|
||||||
import type { Source, Range, SourceLocation } from "../types";
|
import type { Source, Range, SourceLocation } from "../types";
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ export type UIState = {
|
||||||
},
|
},
|
||||||
conditionalPanelLocation: null | SourceLocation,
|
conditionalPanelLocation: null | SourceLocation,
|
||||||
isLogPoint: boolean,
|
isLogPoint: boolean,
|
||||||
|
inlinePreviewEnabled: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createUIState = (): UIState => ({
|
export const createUIState = (): UIState => ({
|
||||||
|
@ -51,6 +52,7 @@ export const createUIState = (): UIState => ({
|
||||||
isLogPoint: false,
|
isLogPoint: false,
|
||||||
orientation: "horizontal",
|
orientation: "horizontal",
|
||||||
viewport: null,
|
viewport: null,
|
||||||
|
inlinePreviewEnabled: features.inlinePreview,
|
||||||
});
|
});
|
||||||
|
|
||||||
function update(state: UIState = createUIState(), action: Action): UIState {
|
function update(state: UIState = createUIState(), action: Action): UIState {
|
||||||
|
@ -64,6 +66,11 @@ function update(state: UIState = createUIState(), action: Action): UIState {
|
||||||
return { ...state, frameworkGroupingOn: action.value };
|
return { ...state, frameworkGroupingOn: action.value };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "TOGGLE_INLINE_PREVIEW": {
|
||||||
|
features.inlinePreview = action.value;
|
||||||
|
return { ...state, inlinePreviewEnabled: action.value };
|
||||||
|
}
|
||||||
|
|
||||||
case "SET_ORIENTATION": {
|
case "SET_ORIENTATION": {
|
||||||
return { ...state, orientation: action.orientation };
|
return { ...state, orientation: action.orientation };
|
||||||
}
|
}
|
||||||
|
@ -185,4 +192,8 @@ export function getViewport(state: OuterState) {
|
||||||
return state.ui.viewport;
|
return state.ui.viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getInlinePreview(state: OuterState) {
|
||||||
|
return state.ui.inlinePreviewEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
export default update;
|
export default update;
|
||||||
|
|
|
@ -7,6 +7,19 @@ function skipPausing(dbg) {
|
||||||
return waitForState(dbg, state => dbg.selectors.getSkipPausing());
|
return waitForState(dbg, state => dbg.selectors.getSkipPausing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleBreakpoint(dbg, index) {
|
||||||
|
const breakpoints = findAllElements(dbg, "breakpointItems");
|
||||||
|
const bp = breakpoints[index];
|
||||||
|
const input = bp.querySelector("input");
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disableBreakpoint(dbg, index) {
|
||||||
|
const disabled = waitForDispatch(dbg, "SET_BREAKPOINT");
|
||||||
|
toggleBreakpoint(dbg, index);
|
||||||
|
await disabled;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tests toggling the skip pausing button and
|
* Tests toggling the skip pausing button and
|
||||||
* invoking functions without pausing.
|
* invoking functions without pausing.
|
||||||
|
@ -25,4 +38,14 @@ add_task(async function() {
|
||||||
await reload(dbg, "simple3");
|
await reload(dbg, "simple3");
|
||||||
res = await invokeInTab("simple");
|
res = await invokeInTab("simple");
|
||||||
is(res, 3, "simple() successfully completed");
|
is(res, 3, "simple() successfully completed");
|
||||||
|
|
||||||
|
info("Adding a breakpoint disables skipPausing");
|
||||||
|
await addBreakpoint(dbg, "simple3", 3);
|
||||||
|
await waitForState(dbg, state => !state.skipPausing);
|
||||||
|
|
||||||
|
info("Enabling a breakpoint disables skipPausing");
|
||||||
|
await skipPausing(dbg);
|
||||||
|
await disableBreakpoint(dbg, 0);
|
||||||
|
await toggleBreakpoint(dbg, 0);
|
||||||
|
await waitForState(dbg, state => !state.skipPausing);
|
||||||
});
|
});
|
||||||
|
|
|
@ -192,7 +192,7 @@ skip-if = fission && debug # Leaks windows.
|
||||||
[browser_inspector_search-04.js]
|
[browser_inspector_search-04.js]
|
||||||
fail-if = fission
|
fail-if = fission
|
||||||
[browser_inspector_search-05.js]
|
[browser_inspector_search-05.js]
|
||||||
fail-if = fission
|
skip-if = fission # Timeouts
|
||||||
[browser_inspector_search-06.js]
|
[browser_inspector_search-06.js]
|
||||||
[browser_inspector_search-07.js]
|
[browser_inspector_search-07.js]
|
||||||
[browser_inspector_search-08.js]
|
[browser_inspector_search-08.js]
|
||||||
|
|
|
@ -430,6 +430,14 @@ editor.jumpToMappedLocation1.accesskey=m
|
||||||
downloadFile.label=Download file
|
downloadFile.label=Download file
|
||||||
downloadFile.accesskey=d
|
downloadFile.accesskey=d
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (inlinePreview.enable.label): Context menu item
|
||||||
|
# for enabling the inline preview feature
|
||||||
|
inlinePreview.enable.label=Enable inline preview
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (inlinePreview.disable.label): Context menu item
|
||||||
|
# for disabling the inline preview feature
|
||||||
|
inlinePreview.disable.label=Disable inline preview
|
||||||
|
|
||||||
# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the
|
# LOCALIZATION NOTE (framework.disableGrouping): This is the text that appears in the
|
||||||
# context menu to disable framework grouping.
|
# context menu to disable framework grouping.
|
||||||
framework.disableGrouping=Disable framework grouping
|
framework.disableGrouping=Disable framework grouping
|
||||||
|
|
|
@ -83,4 +83,4 @@ pref("devtools.debugger.features.event-listeners-breakpoints", true);
|
||||||
pref("devtools.debugger.features.dom-mutation-breakpoints", true);
|
pref("devtools.debugger.features.dom-mutation-breakpoints", true);
|
||||||
pref("devtools.debugger.features.log-points", true);
|
pref("devtools.debugger.features.log-points", true);
|
||||||
pref("devtools.debugger.features.overlay-step-buttons", false);
|
pref("devtools.debugger.features.overlay-step-buttons", false);
|
||||||
pref("devtools.debugger.features.inline-preview", false);
|
pref("devtools.debugger.features.inline-preview", true);
|
||||||
|
|
|
@ -79,7 +79,7 @@ support-files =
|
||||||
[browser_styleeditor_autocomplete-disabled.js]
|
[browser_styleeditor_autocomplete-disabled.js]
|
||||||
[browser_styleeditor_bom.js]
|
[browser_styleeditor_bom.js]
|
||||||
[browser_styleeditor_bug_740541_iframes.js]
|
[browser_styleeditor_bug_740541_iframes.js]
|
||||||
fail-if = fission
|
skip-if = fission # Timeouts
|
||||||
[browser_styleeditor_bug_851132_middle_click.js]
|
[browser_styleeditor_bug_851132_middle_click.js]
|
||||||
[browser_styleeditor_bug_870339.js]
|
[browser_styleeditor_bug_870339.js]
|
||||||
[browser_styleeditor_bug_1405342_serviceworker_iframes.js]
|
[browser_styleeditor_bug_1405342_serviceworker_iframes.js]
|
||||||
|
|
|
@ -18,6 +18,12 @@ loader.lazyRequireGetter(
|
||||||
"BrowserConsole",
|
"BrowserConsole",
|
||||||
"devtools/client/webconsole/browser-console"
|
"devtools/client/webconsole/browser-console"
|
||||||
);
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"PREFS",
|
||||||
|
"devtools/client/webconsole/constants",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
const BC_WINDOW_FEATURES =
|
const BC_WINDOW_FEATURES =
|
||||||
"chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
|
"chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
|
||||||
|
@ -46,12 +52,11 @@ class BrowserConsoleManager {
|
||||||
* The target that the browser console will connect to.
|
* The target that the browser console will connect to.
|
||||||
* @param nsIDOMWindow iframeWindow
|
* @param nsIDOMWindow iframeWindow
|
||||||
* The window where the browser console UI is already loaded.
|
* The window where the browser console UI is already loaded.
|
||||||
* @param Boolean fissionSupport
|
|
||||||
* @return object
|
* @return object
|
||||||
* A promise object for the opening of the new BrowserConsole instance.
|
* A promise object for the opening of the new BrowserConsole instance.
|
||||||
*/
|
*/
|
||||||
async openBrowserConsole(target, win, fissionSupport = false) {
|
async openBrowserConsole(target, win) {
|
||||||
const hud = new BrowserConsole(target, win, win, fissionSupport);
|
const hud = new BrowserConsole(target, win, win);
|
||||||
this._browserConsole = hud;
|
this._browserConsole = hud;
|
||||||
hud.once("destroyed", () => {
|
hud.once("destroyed", () => {
|
||||||
this._browserConsole = null;
|
this._browserConsole = null;
|
||||||
|
@ -73,11 +78,6 @@ class BrowserConsoleManager {
|
||||||
return this._browserConsoleInitializing;
|
return this._browserConsoleInitializing;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fissionSupport = Services.prefs.getBoolPref(
|
|
||||||
"devtools.browsertoolbox.fission",
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
async function connect() {
|
async function connect() {
|
||||||
// The Browser console ends up using the debugger in autocomplete.
|
// The Browser console ends up using the debugger in autocomplete.
|
||||||
// Because the debugger can't be running in the same compartment than its debuggee,
|
// Because the debugger can't be running in the same compartment than its debuggee,
|
||||||
|
@ -124,6 +124,9 @@ class BrowserConsoleManager {
|
||||||
win.addEventListener("DOMContentLoaded", resolve, { once: true });
|
win.addEventListener("DOMContentLoaded", resolve, { once: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const fissionSupport = Services.prefs.getBoolPref(
|
||||||
|
PREFS.FEATURES.BROWSER_TOOLBOX_FISSION
|
||||||
|
);
|
||||||
const title = fissionSupport
|
const title = fissionSupport
|
||||||
? `💥 Fission Browser Console 💥`
|
? `💥 Fission Browser Console 💥`
|
||||||
: l10n.getStr("browserConsole.title");
|
: l10n.getStr("browserConsole.title");
|
||||||
|
@ -137,11 +140,7 @@ class BrowserConsoleManager {
|
||||||
const target = await connect();
|
const target = await connect();
|
||||||
await target.attach();
|
await target.attach();
|
||||||
const win = await openWindow(target);
|
const win = await openWindow(target);
|
||||||
const browserConsole = await this.openBrowserConsole(
|
const browserConsole = await this.openBrowserConsole(target, win);
|
||||||
target,
|
|
||||||
win,
|
|
||||||
fissionSupport
|
|
||||||
);
|
|
||||||
return browserConsole;
|
return browserConsole;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
|
@ -35,10 +35,9 @@ class BrowserConsole extends WebConsole {
|
||||||
* The window where the browser console UI is already loaded.
|
* The window where the browser console UI is already loaded.
|
||||||
* @param nsIDOMWindow chromeWindow
|
* @param nsIDOMWindow chromeWindow
|
||||||
* The window of the browser console owner.
|
* The window of the browser console owner.
|
||||||
* @param Boolean fissionSupport
|
|
||||||
*/
|
*/
|
||||||
constructor(target, iframeWindow, chromeWindow, fissionSupport = false) {
|
constructor(target, iframeWindow, chromeWindow) {
|
||||||
super(null, iframeWindow, chromeWindow, true, fissionSupport);
|
super(null, iframeWindow, chromeWindow, true);
|
||||||
|
|
||||||
this._browserConsoleTarget = target;
|
this._browserConsoleTarget = target;
|
||||||
this._telemetry = new Telemetry();
|
this._telemetry = new Telemetry();
|
||||||
|
|
|
@ -83,6 +83,7 @@ const prefs = {
|
||||||
AUTOCOMPLETE: "devtools.webconsole.input.autocomplete",
|
AUTOCOMPLETE: "devtools.webconsole.input.autocomplete",
|
||||||
GROUP_WARNINGS: "devtools.webconsole.groupWarningMessages",
|
GROUP_WARNINGS: "devtools.webconsole.groupWarningMessages",
|
||||||
EDITOR: "devtools.webconsole.features.editor",
|
EDITOR: "devtools.webconsole.features.editor",
|
||||||
|
BROWSER_TOOLBOX_FISSION: "devtools.browsertoolbox.fission",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,10 @@ const TEST_URI =
|
||||||
"test/browser/test-eval-in-stackframe.html";
|
"test/browser/test-eval-in-stackframe.html";
|
||||||
|
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
|
// TODO: Remove this pref change when middleware for terminating requests
|
||||||
|
// when closing a panel is implemented
|
||||||
|
await pushPref("devtools.debugger.features.inline-preview", false);
|
||||||
|
|
||||||
info("open the console");
|
info("open the console");
|
||||||
const hud = await openNewTabAndConsole(TEST_URI);
|
const hud = await openNewTabAndConsole(TEST_URI);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ const TEST_URI =
|
||||||
"test/browser/test-eval-in-stackframe.html";
|
"test/browser/test-eval-in-stackframe.html";
|
||||||
|
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
|
// TODO: Remove this pref change when middleware for terminating requests
|
||||||
|
// when closing a panel is implemented
|
||||||
|
await pushPref("devtools.debugger.features.inline-preview", false);
|
||||||
|
|
||||||
info("open the console");
|
info("open the console");
|
||||||
const hud = await openNewTabAndConsole(TEST_URI);
|
const hud = await openNewTabAndConsole(TEST_URI);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@ const TEST_URI =
|
||||||
"test/browser/test-eval-in-stackframe.html";
|
"test/browser/test-eval-in-stackframe.html";
|
||||||
|
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
|
// TODO: Remove this pref change when middleware for terminating requests
|
||||||
|
// when closing a panel is implemented
|
||||||
|
await pushPref("devtools.debugger.features.inline-preview", false);
|
||||||
|
|
||||||
const hud = await openNewTabAndConsole(TEST_URI);
|
const hud = await openNewTabAndConsole(TEST_URI);
|
||||||
|
|
||||||
info("Switch to the debugger");
|
info("Switch to the debugger");
|
||||||
|
|
|
@ -20,13 +20,20 @@ class WebConsoleConnectionProxy {
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {WebConsoleUI} webConsoleUI
|
* @param {WebConsoleUI} webConsoleUI
|
||||||
* A WebConsoleUI instance that owns this connection proxy.
|
* A WebConsoleUI instance that owns this connection proxy.
|
||||||
* @param RemoteTarget target
|
* @param {RemoteTarget} target
|
||||||
* The target that the console will connect to.
|
* The target that the console will connect to.
|
||||||
|
* @param {Boolean} needContentProcessMessagesListener
|
||||||
|
* Set to true to specifically add a ContentProcessMessages listener. This is
|
||||||
|
* needed for non-fission Browser Console for example.
|
||||||
*/
|
*/
|
||||||
constructor(webConsoleUI, target) {
|
constructor(
|
||||||
|
webConsoleUI,
|
||||||
|
target,
|
||||||
|
needContentProcessMessagesListener = false
|
||||||
|
) {
|
||||||
this.webConsoleUI = webConsoleUI;
|
this.webConsoleUI = webConsoleUI;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.fissionSupport = this.webConsoleUI.fissionSupport;
|
this.needContentProcessMessagesListener = needContentProcessMessagesListener;
|
||||||
|
|
||||||
this._connecter = null;
|
this._connecter = null;
|
||||||
|
|
||||||
|
@ -116,7 +123,7 @@ class WebConsoleConnectionProxy {
|
||||||
// when we open the Browser Console or Toolbox without fission support. If Fission
|
// when we open the Browser Console or Toolbox without fission support. If Fission
|
||||||
// is enabled, we don't use the ContentProcessMessages listener, but attach to the
|
// is enabled, we don't use the ContentProcessMessages listener, but attach to the
|
||||||
// content processes directly.
|
// content processes directly.
|
||||||
if (this.target.chrome && !this.target.isAddon && !this.fissionSupport) {
|
if (this.needContentProcessMessagesListener) {
|
||||||
listeners.push("ContentProcessMessages");
|
listeners.push("ContentProcessMessages");
|
||||||
}
|
}
|
||||||
return this.webConsoleClient.startListeners(listeners);
|
return this.webConsoleClient.startListeners(listeners);
|
||||||
|
|
|
@ -24,6 +24,12 @@ loader.lazyRequireGetter(
|
||||||
"resource://gre/modules/AppConstants.jsm",
|
"resource://gre/modules/AppConstants.jsm",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
loader.lazyRequireGetter(
|
||||||
|
this,
|
||||||
|
"PREFS",
|
||||||
|
"devtools/client/webconsole/constants",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
const ZoomKeys = require("devtools/client/shared/zoom-keys");
|
const ZoomKeys = require("devtools/client/shared/zoom-keys");
|
||||||
|
|
||||||
|
@ -45,7 +51,6 @@ class WebConsoleUI {
|
||||||
this.hud = hud;
|
this.hud = hud;
|
||||||
this.hudId = this.hud.hudId;
|
this.hudId = this.hud.hudId;
|
||||||
this.isBrowserConsole = this.hud.isBrowserConsole;
|
this.isBrowserConsole = this.hud.isBrowserConsole;
|
||||||
this.fissionSupport = this.hud.fissionSupport;
|
|
||||||
this.window = this.hud.iframeWindow;
|
this.window = this.hud.iframeWindow;
|
||||||
|
|
||||||
this._onPanelSelected = this._onPanelSelected.bind(this);
|
this._onPanelSelected = this._onPanelSelected.bind(this);
|
||||||
|
@ -257,10 +262,20 @@ class WebConsoleUI {
|
||||||
* A promise object that is resolved/reject based on the proxies connections.
|
* A promise object that is resolved/reject based on the proxies connections.
|
||||||
*/
|
*/
|
||||||
async _initConnection() {
|
async _initConnection() {
|
||||||
this.proxy = new WebConsoleConnectionProxy(this, this.hud.currentTarget);
|
|
||||||
|
|
||||||
const target = this.hud.currentTarget;
|
const target = this.hud.currentTarget;
|
||||||
if (this.fissionSupport && target.chrome && !target.isAddon) {
|
const fissionSupport = Services.prefs.getBoolPref(
|
||||||
|
PREFS.FEATURES.BROWSER_TOOLBOX_FISSION
|
||||||
|
);
|
||||||
|
const needContentProcessMessagesListener =
|
||||||
|
target.isParentProcess && !target.isAddon && !fissionSupport;
|
||||||
|
|
||||||
|
this.proxy = new WebConsoleConnectionProxy(
|
||||||
|
this,
|
||||||
|
target,
|
||||||
|
needContentProcessMessagesListener
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fissionSupport && target.isParentProcess && !target.isAddon) {
|
||||||
const { mainRoot } = target.client;
|
const { mainRoot } = target.client;
|
||||||
const { processes } = await mainRoot.listProcesses();
|
const { processes } = await mainRoot.listProcesses();
|
||||||
|
|
||||||
|
|
|
@ -59,20 +59,13 @@ class WebConsole {
|
||||||
* The window of the web console owner.
|
* The window of the web console owner.
|
||||||
* @param bool isBrowserConsole
|
* @param bool isBrowserConsole
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(toolbox, iframeWindow, chromeWindow, isBrowserConsole = false) {
|
||||||
toolbox,
|
|
||||||
iframeWindow,
|
|
||||||
chromeWindow,
|
|
||||||
isBrowserConsole = false,
|
|
||||||
fissionSupport = false
|
|
||||||
) {
|
|
||||||
this.toolbox = toolbox;
|
this.toolbox = toolbox;
|
||||||
this.iframeWindow = iframeWindow;
|
this.iframeWindow = iframeWindow;
|
||||||
this.chromeWindow = chromeWindow;
|
this.chromeWindow = chromeWindow;
|
||||||
this.hudId = "hud_" + ++gHudId;
|
this.hudId = "hud_" + ++gHudId;
|
||||||
this.browserWindow = this.chromeWindow.top;
|
this.browserWindow = this.chromeWindow.top;
|
||||||
this.isBrowserConsole = isBrowserConsole;
|
this.isBrowserConsole = isBrowserConsole;
|
||||||
this.fissionSupport = fissionSupport;
|
|
||||||
|
|
||||||
const element = this.browserWindow.document.documentElement;
|
const element = this.browserWindow.document.documentElement;
|
||||||
if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
|
if (element.getAttribute("windowtype") != gDevTools.chromeWindowType) {
|
||||||
|
|
|
@ -21,9 +21,6 @@ const CONTENT_PROCESS_SERVER_STARTUP_SCRIPT =
|
||||||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||||
|
|
||||||
const ContentProcessConnector = {
|
const ContentProcessConnector = {
|
||||||
// Flag to check if the content process server startup script was already loaded.
|
|
||||||
_contentProcessServerStartupScriptLoaded: false,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a DevTools server in a content process (representing the entire process, not
|
* Start a DevTools server in a content process (representing the entire process, not
|
||||||
* just a single frame) and add it as a child server for an active connection.
|
* just a single frame) and add it as a child server for an active connection.
|
||||||
|
@ -36,8 +33,6 @@ const ContentProcessConnector = {
|
||||||
mm.addMessageListener("debug:content-process-actor", function listener(
|
mm.addMessageListener("debug:content-process-actor", function listener(
|
||||||
msg
|
msg
|
||||||
) {
|
) {
|
||||||
// Arbitrarily choose the first content process to reply
|
|
||||||
// XXX: This code needs to be updated if we use more than one content process
|
|
||||||
mm.removeMessageListener("debug:content-process-actor", listener);
|
mm.removeMessageListener("debug:content-process-actor", listener);
|
||||||
|
|
||||||
// Pipe Debugger message from/to parent/child via the message manager
|
// Pipe Debugger message from/to parent/child via the message manager
|
||||||
|
@ -58,13 +53,15 @@ const ContentProcessConnector = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load the content process server startup script only once.
|
// Load the content process server startup script only once.
|
||||||
if (!this._contentProcessServerStartupScriptLoaded) {
|
const isContentProcessServerStartupScripLoaded = Services.ppmm
|
||||||
|
.getDelayedProcessScripts()
|
||||||
|
.some(([uri]) => uri === CONTENT_PROCESS_SERVER_STARTUP_SCRIPT);
|
||||||
|
if (!isContentProcessServerStartupScripLoaded) {
|
||||||
// Load the process script that will receive the debug:init-content-server message
|
// Load the process script that will receive the debug:init-content-server message
|
||||||
Services.ppmm.loadProcessScript(
|
Services.ppmm.loadProcessScript(
|
||||||
CONTENT_PROCESS_SERVER_STARTUP_SCRIPT,
|
CONTENT_PROCESS_SERVER_STARTUP_SCRIPT,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
this._contentProcessServerStartupScriptLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message to the content process server startup script to forward it the
|
// Send a message to the content process server startup script to forward it the
|
||||||
|
|
|
@ -144,7 +144,7 @@ skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still di
|
||||||
[browser_storage_browser_toolbox_indexeddb.js]
|
[browser_storage_browser_toolbox_indexeddb.js]
|
||||||
[browser_storage_cookies-duplicate-names.js]
|
[browser_storage_cookies-duplicate-names.js]
|
||||||
[browser_storage_dynamic_windows.js]
|
[browser_storage_dynamic_windows.js]
|
||||||
fail-if = fission
|
skip-if = fission # Timeouts
|
||||||
[browser_storage_listings.js]
|
[browser_storage_listings.js]
|
||||||
fail-if = fission
|
fail-if = fission
|
||||||
[browser_storage_updates.js]
|
[browser_storage_updates.js]
|
||||||
|
|
|
@ -489,6 +489,11 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||||
|
|
||||||
UpdateEditableState(false);
|
UpdateEditableState(false);
|
||||||
|
|
||||||
|
// Ensure we only do these once, in the case we move the shadow host around.
|
||||||
|
if (aContext.SubtreeRootChanges()) {
|
||||||
|
HandleShadowDOMRelatedInsertionSteps(hadParent);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_ASSERT(OwnerDoc() == aParent.OwnerDoc(), "Bound to wrong document");
|
MOZ_ASSERT(OwnerDoc() == aParent.OwnerDoc(), "Bound to wrong document");
|
||||||
MOZ_ASSERT(IsInComposedDoc() == aContext.InComposedDoc());
|
MOZ_ASSERT(IsInComposedDoc() == aContext.InComposedDoc());
|
||||||
MOZ_ASSERT(IsInUncomposedDoc() == aContext.InUncomposedDoc());
|
MOZ_ASSERT(IsInUncomposedDoc() == aContext.InUncomposedDoc());
|
||||||
|
@ -506,6 +511,8 @@ void CharacterData::UnbindFromTree(bool aNullParent) {
|
||||||
// Unset frame flags; if we need them again later, they'll get set again.
|
// Unset frame flags; if we need them again later, they'll get set again.
|
||||||
UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
|
UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
|
||||||
|
|
||||||
|
HandleShadowDOMRelatedRemovalSteps(aNullParent);
|
||||||
|
|
||||||
Document* document = GetComposedDoc();
|
Document* document = GetComposedDoc();
|
||||||
|
|
||||||
if (aNullParent) {
|
if (aNullParent) {
|
||||||
|
|
|
@ -1721,6 +1721,7 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||||
if (HasID()) {
|
if (HasID()) {
|
||||||
AddToIdTable(DoGetID());
|
AddToIdTable(DoGetID());
|
||||||
}
|
}
|
||||||
|
HandleShadowDOMRelatedInsertionSteps(hadParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MayHaveStyle() && !IsXULElement()) {
|
if (MayHaveStyle() && !IsXULElement()) {
|
||||||
|
@ -1801,6 +1802,8 @@ bool WillDetachFromShadowOnUnbind(const Element& aElement, bool aNullParent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Element::UnbindFromTree(bool aNullParent) {
|
void Element::UnbindFromTree(bool aNullParent) {
|
||||||
|
HandleShadowDOMRelatedRemovalSteps(aNullParent);
|
||||||
|
|
||||||
const bool detachingFromShadow =
|
const bool detachingFromShadow =
|
||||||
WillDetachFromShadowOnUnbind(*this, aNullParent);
|
WillDetachFromShadowOnUnbind(*this, aNullParent);
|
||||||
// Make sure to only remove from the ID table if our subtree root is actually
|
// Make sure to only remove from the ID table if our subtree root is actually
|
||||||
|
@ -1922,7 +1925,6 @@ void Element::UnbindFromTree(bool aNullParent) {
|
||||||
|
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
if (nsXULElement* xulElem = nsXULElement::FromNode(this)) {
|
if (nsXULElement* xulElem = nsXULElement::FromNode(this)) {
|
||||||
;
|
|
||||||
xulElem->SetXULBindingParent(nullptr);
|
xulElem->SetXULBindingParent(nullptr);
|
||||||
clearBindingParent = false;
|
clearBindingParent = false;
|
||||||
}
|
}
|
||||||
|
@ -2629,19 +2631,25 @@ nsresult Element::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||||
const nsAttrValue* aOldValue,
|
const nsAttrValue* aOldValue,
|
||||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||||
bool aNotify) {
|
bool aNotify) {
|
||||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::part) {
|
if (aNamespaceID == kNameSpaceID_None) {
|
||||||
bool isPart = !!aValue;
|
if (aName == nsGkAtoms::part) {
|
||||||
if (HasPartAttribute() != isPart) {
|
bool isPart = !!aValue;
|
||||||
SetHasPartAttribute(isPart);
|
if (HasPartAttribute() != isPart) {
|
||||||
if (ShadowRoot* shadow = GetContainingShadow()) {
|
SetHasPartAttribute(isPart);
|
||||||
if (isPart) {
|
if (ShadowRoot* shadow = GetContainingShadow()) {
|
||||||
shadow->PartAdded(*this);
|
if (isPart) {
|
||||||
} else {
|
shadow->PartAdded(*this);
|
||||||
shadow->PartRemoved(*this);
|
} else {
|
||||||
|
shadow->PartRemoved(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MOZ_ASSERT(HasPartAttribute() == isPart);
|
||||||
|
} else if (aName == nsGkAtoms::slot && GetParent()) {
|
||||||
|
if (ShadowRoot* shadow = GetParent()->GetShadowRoot()) {
|
||||||
|
shadow->MaybeReassignElement(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(HasPartAttribute() == isPart);
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1118,7 +1118,7 @@ void nsIContent::AssertAnonymousSubtreeRelatedInvariants() const {
|
||||||
(GetParent() && GetBindingParent() == GetParent()),
|
(GetParent() && GetBindingParent() == GetParent()),
|
||||||
"root of native anonymous subtree must have parent equal "
|
"root of native anonymous subtree must have parent equal "
|
||||||
"to binding parent");
|
"to binding parent");
|
||||||
NS_ASSERTION(!GetParent() ||
|
NS_ASSERTION(!GetParent() || !IsInComposedDoc() ||
|
||||||
((GetBindingParent() == GetParent()) ==
|
((GetBindingParent() == GetParent()) ==
|
||||||
HasFlag(NODE_IS_ANONYMOUS_ROOT)) ||
|
HasFlag(NODE_IS_ANONYMOUS_ROOT)) ||
|
||||||
// Unfortunately default content for XBL insertion points
|
// Unfortunately default content for XBL insertion points
|
||||||
|
@ -1129,7 +1129,7 @@ void nsIContent::AssertAnonymousSubtreeRelatedInvariants() const {
|
||||||
(GetBindingParent() &&
|
(GetBindingParent() &&
|
||||||
(GetBindingParent() == GetParent()->GetBindingParent()) ==
|
(GetBindingParent() == GetParent()->GetBindingParent()) ==
|
||||||
HasFlag(NODE_IS_ANONYMOUS_ROOT)),
|
HasFlag(NODE_IS_ANONYMOUS_ROOT)),
|
||||||
"For nodes with parent, flag and GetBindingParent() check "
|
"For connected nodes, flag and GetBindingParent() check "
|
||||||
"should match");
|
"should match");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,15 +36,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
|
||||||
if (tmp->GetHost()) {
|
|
||||||
tmp->GetHost()->RemoveMutationObserver(tmp);
|
|
||||||
}
|
|
||||||
DocumentOrShadowRoot::Unlink(tmp);
|
DocumentOrShadowRoot::Unlink(tmp);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
|
||||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
|
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
|
||||||
NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
|
NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
|
||||||
|
|
||||||
|
@ -69,19 +65,9 @@ ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
||||||
|
|
||||||
ExtendedDOMSlots()->mBindingParent = aElement;
|
ExtendedDOMSlots()->mBindingParent = aElement;
|
||||||
ExtendedDOMSlots()->mContainingShadow = this;
|
ExtendedDOMSlots()->mContainingShadow = this;
|
||||||
|
|
||||||
// Add the ShadowRoot as a mutation observer on the host to watch
|
|
||||||
// for mutations because the insertion points in this ShadowRoot
|
|
||||||
// may need to be updated when the host children are modified.
|
|
||||||
GetHost()->AddMutationObserver(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadowRoot::~ShadowRoot() {
|
ShadowRoot::~ShadowRoot() {
|
||||||
if (auto* host = GetHost()) {
|
|
||||||
// mHost may have been unlinked.
|
|
||||||
host->RemoveMutationObserver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInComposedDoc()) {
|
if (IsInComposedDoc()) {
|
||||||
OwnerDoc()->RemoveComposedDocShadowRoot(*this);
|
OwnerDoc()->RemoveComposedDocShadowRoot(*this);
|
||||||
}
|
}
|
||||||
|
@ -158,13 +144,11 @@ void ShadowRoot::Unattach() {
|
||||||
MOZ_ASSERT(!HasSlots(), "Won't work!");
|
MOZ_ASSERT(!HasSlots(), "Won't work!");
|
||||||
if (!GetHost()) {
|
if (!GetHost()) {
|
||||||
// It is possible that we've been unlinked already. In such case host
|
// It is possible that we've been unlinked already. In such case host
|
||||||
// should have called Unbind and ShadowRoot's own unlink
|
// should have called Unbind and ShadowRoot's own unlink.
|
||||||
// RemoveMutationObserver.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unbind();
|
Unbind();
|
||||||
GetHost()->RemoveMutationObserver(this);
|
|
||||||
SetHost(nullptr);
|
SetHost(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +204,8 @@ void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
|
||||||
while (assignedNodes.Length() > 0) {
|
while (assignedNodes.Length() > 0) {
|
||||||
nsINode* assignedNode = assignedNodes[0];
|
nsINode* assignedNode = assignedNodes[0];
|
||||||
|
|
||||||
oldSlot->RemoveAssignedNode(assignedNode);
|
oldSlot->RemoveAssignedNode(*assignedNode->AsContent());
|
||||||
aSlot->AppendAssignedNode(assignedNode);
|
aSlot->AppendAssignedNode(*assignedNode->AsContent());
|
||||||
doEnqueueSlotChange = true;
|
doEnqueueSlotChange = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +229,7 @@ void ShadowRoot::AddSlot(HTMLSlotElement* aSlot) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
doEnqueueSlotChange = true;
|
doEnqueueSlotChange = true;
|
||||||
aSlot->AppendAssignedNode(child);
|
aSlot->AppendAssignedNode(*child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doEnqueueSlotChange) {
|
if (doEnqueueSlotChange) {
|
||||||
|
@ -299,8 +283,8 @@ void ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot) {
|
||||||
while (!assignedNodes.IsEmpty()) {
|
while (!assignedNodes.IsEmpty()) {
|
||||||
nsINode* assignedNode = assignedNodes[0];
|
nsINode* assignedNode = assignedNodes[0];
|
||||||
|
|
||||||
aSlot->RemoveAssignedNode(assignedNode);
|
aSlot->RemoveAssignedNode(*assignedNode->AsContent());
|
||||||
replacementSlot->AppendAssignedNode(assignedNode);
|
replacementSlot->AppendAssignedNode(*assignedNode->AsContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
aSlot->EnqueueSlotChangeEvent();
|
aSlot->EnqueueSlotChangeEvent();
|
||||||
|
@ -488,7 +472,7 @@ void ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent* aContent) {
|
ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent& aContent) {
|
||||||
nsAutoString slotName;
|
nsAutoString slotName;
|
||||||
// Note that if slot attribute is missing, assign it to the first default
|
// Note that if slot attribute is missing, assign it to the first default
|
||||||
// slot, if exists.
|
// slot, if exists.
|
||||||
|
@ -513,7 +497,7 @@ ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent* aContent) {
|
||||||
// Seek through the host's explicit children until the
|
// Seek through the host's explicit children until the
|
||||||
// assigned content is found.
|
// assigned content is found.
|
||||||
while (currentContent && currentContent != assignedNodes[i]) {
|
while (currentContent && currentContent != assignedNodes[i]) {
|
||||||
if (currentContent == aContent) {
|
if (currentContent == &aContent) {
|
||||||
insertionIndex.emplace(i);
|
insertionIndex.emplace(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -529,9 +513,9 @@ ShadowRoot::SlotAssignment ShadowRoot::SlotAssignmentFor(nsIContent* aContent) {
|
||||||
return {slot, insertionIndex};
|
return {slot, insertionIndex};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowRoot::MaybeReassignElement(Element* aElement) {
|
void ShadowRoot::MaybeReassignElement(Element& aElement) {
|
||||||
MOZ_ASSERT(aElement->GetParent() == GetHost());
|
MOZ_ASSERT(aElement.GetParent() == GetHost());
|
||||||
HTMLSlotElement* oldSlot = aElement->GetAssignedSlot();
|
HTMLSlotElement* oldSlot = aElement.GetAssignedSlot();
|
||||||
SlotAssignment assignment = SlotAssignmentFor(aElement);
|
SlotAssignment assignment = SlotAssignmentFor(aElement);
|
||||||
|
|
||||||
if (assignment.mSlot == oldSlot) {
|
if (assignment.mSlot == oldSlot) {
|
||||||
|
@ -541,7 +525,7 @@ void ShadowRoot::MaybeReassignElement(Element* aElement) {
|
||||||
|
|
||||||
if (Document* doc = GetComposedDoc()) {
|
if (Document* doc = GetComposedDoc()) {
|
||||||
if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
|
if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
|
||||||
presShell->SlotAssignmentWillChange(*aElement, oldSlot, assignment.mSlot);
|
presShell->SlotAssignmentWillChange(aElement, oldSlot, assignment.mSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,103 +599,56 @@ nsINode* ShadowRoot::CreateElementAndAppendChildAt(nsINode& aParentNode,
|
||||||
return aParentNode.AppendChild(*node, rv);
|
return aParentNode.AppendChild(*node, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowRoot::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
void ShadowRoot::MaybeUnslotHostChild(nsIContent& aChild) {
|
||||||
nsAtom* aAttribute, int32_t aModType,
|
// Need to null-check the host because we may be unlinked already.
|
||||||
const nsAttrValue* aOldValue) {
|
MOZ_ASSERT(!GetHost() || aChild.GetParent() == GetHost());
|
||||||
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
|
|
||||||
|
HTMLSlotElement* slot = aChild.GetAssignedSlot();
|
||||||
|
if (!slot) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aElement->GetParent() != GetHost()) {
|
MOZ_DIAGNOSTIC_ASSERT(!aChild.IsRootOfAnonymousSubtree(),
|
||||||
return;
|
"How did aChild end up assigned to a slot?");
|
||||||
|
// If the slot is going to start showing fallback content, we need to tell
|
||||||
|
// layout about it.
|
||||||
|
if (slot->AssignedNodes().Length() == 1) {
|
||||||
|
InvalidateStyleAndLayoutOnSubtree(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeReassignElement(aElement);
|
slot->RemoveAssignedNode(aChild);
|
||||||
|
slot->EnqueueSlotChangeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowRoot::ContentAppended(nsIContent* aFirstNewContent) {
|
void ShadowRoot::MaybeSlotHostChild(nsIContent& aChild) {
|
||||||
for (nsIContent* content = aFirstNewContent; content;
|
MOZ_ASSERT(aChild.GetParent() == GetHost());
|
||||||
content = content->GetNextSibling()) {
|
// Check to ensure that the child not an anonymous subtree root because even
|
||||||
ContentInserted(content);
|
// though its parent could be the host it may not be in the host's child list.
|
||||||
}
|
if (aChild.IsRootOfAnonymousSubtree()) {
|
||||||
}
|
|
||||||
|
|
||||||
void ShadowRoot::ContentInserted(nsIContent* aChild) {
|
|
||||||
// Check to ensure that the child not an anonymous subtree root because
|
|
||||||
// even though its parent could be the host it may not be in the host's child
|
|
||||||
// list.
|
|
||||||
if (aChild->IsRootOfAnonymousSubtree()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aChild->IsSlotable()) {
|
if (!aChild.IsSlotable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aChild->GetParent() == GetHost()) {
|
SlotAssignment assignment = SlotAssignmentFor(aChild);
|
||||||
SlotAssignment assignment = SlotAssignmentFor(aChild);
|
if (!assignment.mSlot) {
|
||||||
if (!assignment.mSlot) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback content will go away, let layout know.
|
|
||||||
if (assignment.mSlot->AssignedNodes().IsEmpty()) {
|
|
||||||
InvalidateStyleAndLayoutOnSubtree(assignment.mSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assignment.mIndex) {
|
|
||||||
assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aChild);
|
|
||||||
} else {
|
|
||||||
assignment.mSlot->AppendAssignedNode(aChild);
|
|
||||||
}
|
|
||||||
assignment.mSlot->EnqueueSlotChangeEvent();
|
|
||||||
|
|
||||||
SlotStateChanged(assignment.mSlot);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
// Fallback content will go away, let layout know.
|
||||||
// nodes is the empty list, then run signal a slot change for parent.
|
if (assignment.mSlot->AssignedNodes().IsEmpty()) {
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNodeOrNull(aChild->GetParent());
|
InvalidateStyleAndLayoutOnSubtree(assignment.mSlot);
|
||||||
if (slot && slot->GetContainingShadow() == this &&
|
|
||||||
slot->AssignedNodes().IsEmpty()) {
|
|
||||||
slot->EnqueueSlotChangeEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShadowRoot::ContentRemoved(nsIContent* aChild,
|
|
||||||
nsIContent* aPreviousSibling) {
|
|
||||||
// Check to ensure that the child not an anonymous subtree root because
|
|
||||||
// even though its parent could be the host it may not be in the host's child
|
|
||||||
// list.
|
|
||||||
if (aChild->IsRootOfAnonymousSubtree()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aChild->IsSlotable()) {
|
if (assignment.mIndex) {
|
||||||
return;
|
assignment.mSlot->InsertAssignedNode(*assignment.mIndex, aChild);
|
||||||
}
|
} else {
|
||||||
|
assignment.mSlot->AppendAssignedNode(aChild);
|
||||||
if (aChild->GetParent() == GetHost()) {
|
|
||||||
if (HTMLSlotElement* slot = aChild->GetAssignedSlot()) {
|
|
||||||
// If the slot is going to start showing fallback content, we need to tell
|
|
||||||
// layout about it.
|
|
||||||
if (slot->AssignedNodes().Length() == 1) {
|
|
||||||
InvalidateStyleAndLayoutOnSubtree(slot);
|
|
||||||
}
|
|
||||||
slot->RemoveAssignedNode(aChild);
|
|
||||||
slot->EnqueueSlotChangeEvent();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
|
||||||
// nodes is the empty list, then run signal a slot change for parent.
|
|
||||||
HTMLSlotElement* slot = HTMLSlotElement::FromNodeOrNull(aChild->GetParent());
|
|
||||||
if (slot && slot->GetContainingShadow() == this &&
|
|
||||||
slot->AssignedNodes().IsEmpty()) {
|
|
||||||
slot->EnqueueSlotChangeEvent();
|
|
||||||
}
|
}
|
||||||
|
assignment.mSlot->EnqueueSlotChangeEvent();
|
||||||
|
SlotStateChanged(assignment.mSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServoStyleRuleMap& ShadowRoot::ServoStyleRuleMap() {
|
ServoStyleRuleMap& ShadowRoot::ServoStyleRuleMap() {
|
||||||
|
|
|
@ -39,7 +39,6 @@ class HTMLInputElement;
|
||||||
|
|
||||||
class ShadowRoot final : public DocumentFragment,
|
class ShadowRoot final : public DocumentFragment,
|
||||||
public DocumentOrShadowRoot,
|
public DocumentOrShadowRoot,
|
||||||
public nsStubMutationObserver,
|
|
||||||
public nsIRadioGroupContainer {
|
public nsIRadioGroupContainer {
|
||||||
public:
|
public:
|
||||||
NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot());
|
NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot());
|
||||||
|
@ -47,16 +46,20 @@ class ShadowRoot final : public DocumentFragment,
|
||||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot, DocumentFragment)
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot, DocumentFragment)
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
|
|
||||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
|
||||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
|
||||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
||||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
|
||||||
|
|
||||||
ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
||||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||||
|
|
||||||
void AddSizeOfExcludingThis(nsWindowSizes&, size_t* aNodeSize) const final;
|
void AddSizeOfExcludingThis(nsWindowSizes&, size_t* aNodeSize) const final;
|
||||||
|
|
||||||
|
// Try to reassign an element to a slot.
|
||||||
|
void MaybeReassignElement(Element&);
|
||||||
|
// Called when an element is inserted as a direct child of our host. Tries to
|
||||||
|
// slot the child in one of our slots.
|
||||||
|
void MaybeSlotHostChild(nsIContent&);
|
||||||
|
// Called when a direct child of our host is removed. Tries to un-slot the
|
||||||
|
// child from the currently-assigned slot, if any.
|
||||||
|
void MaybeUnslotHostChild(nsIContent&);
|
||||||
|
|
||||||
// Shadow DOM v1
|
// Shadow DOM v1
|
||||||
Element* Host() const {
|
Element* Host() const {
|
||||||
MOZ_ASSERT(GetHost(),
|
MOZ_ASSERT(GetHost(),
|
||||||
|
@ -106,12 +109,6 @@ class ShadowRoot final : public DocumentFragment,
|
||||||
InsertSheetAt(SheetCount(), aSheet);
|
InsertSheetAt(SheetCount(), aSheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to reassign an element to a slot and returns whether the assignment
|
|
||||||
* changed.
|
|
||||||
*/
|
|
||||||
void MaybeReassignElement(Element* aElement);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the insertion point in a slot for a given node.
|
* Represents the insertion point in a slot for a given node.
|
||||||
*/
|
*/
|
||||||
|
@ -131,7 +128,7 @@ class ShadowRoot final : public DocumentFragment,
|
||||||
* It's the caller's responsibility to actually call InsertAssignedNode /
|
* It's the caller's responsibility to actually call InsertAssignedNode /
|
||||||
* AppendAssignedNode in the slot as needed.
|
* AppendAssignedNode in the slot as needed.
|
||||||
*/
|
*/
|
||||||
SlotAssignment SlotAssignmentFor(nsIContent* aContent);
|
SlotAssignment SlotAssignmentFor(nsIContent&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Explicitly invalidates the style and layout of the flattened-tree subtree
|
* Explicitly invalidates the style and layout of the flattened-tree subtree
|
||||||
|
|
|
@ -468,6 +468,12 @@ if CONFIG['INTEL_ARCHITECTURE']:
|
||||||
SOURCES += ['nsTextFragmentSSE2.cpp']
|
SOURCES += ['nsTextFragmentSSE2.cpp']
|
||||||
SOURCES['nsTextFragmentSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
SOURCES['nsTextFragmentSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||||
|
|
||||||
|
# Are we targeting PowerPC? If so, we can enable a SIMD version for
|
||||||
|
# nsTextFragment.cpp as well.
|
||||||
|
if CONFIG['CPU_ARCH'].startswith('ppc'):
|
||||||
|
SOURCES += ['nsTextFragmentVMX.cpp']
|
||||||
|
SOURCES['nsTextFragmentVMX.cpp'].flags += CONFIG['PPC_VMX_FLAGS']
|
||||||
|
|
||||||
EXTRA_JS_MODULES += [
|
EXTRA_JS_MODULES += [
|
||||||
'ContentAreaDropListener.jsm',
|
'ContentAreaDropListener.jsm',
|
||||||
'DOMRequestHelper.jsm',
|
'DOMRequestHelper.jsm',
|
||||||
|
|
|
@ -239,7 +239,8 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
||||||
nsresult SerializeToStringRecursive(nsINode* aNode, nsAString& aStr,
|
nsresult SerializeToStringRecursive(nsINode* aNode, nsAString& aStr,
|
||||||
bool aDontSerializeRoot,
|
bool aDontSerializeRoot,
|
||||||
uint32_t aMaxLength = 0);
|
uint32_t aMaxLength = 0);
|
||||||
nsresult SerializeNodeEnd(nsINode& aNode, nsAString& aStr);
|
nsresult SerializeNodeEnd(nsINode& aOriginalNode, nsAString& aStr,
|
||||||
|
nsINode* aFixupNode = nullptr);
|
||||||
// This serializes the content of aNode.
|
// This serializes the content of aNode.
|
||||||
nsresult SerializeToStringIterative(nsINode* aNode, nsAString& aStr);
|
nsresult SerializeToStringIterative(nsINode* aNode, nsAString& aStr);
|
||||||
nsresult SerializeRangeToString(nsRange* aRange, nsAString& aOutputString);
|
nsresult SerializeRangeToString(nsRange* aRange, nsAString& aOutputString);
|
||||||
|
@ -660,9 +661,8 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode& aOriginalNode,
|
||||||
nsLayoutUtils::IsInvisibleBreak(node)) {
|
nsLayoutUtils::IsInvisibleBreak(node)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
Element* originalElement = aOriginalNode.AsElement();
|
rv = mSerializer->AppendElementStart(node->AsElement(),
|
||||||
rv = mSerializer->AppendElementStart(node->AsElement(), originalElement,
|
aOriginalNode.AsElement(), aStr);
|
||||||
aStr);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,26 +697,33 @@ nsresult nsDocumentEncoder::SerializeNodeStart(nsINode& aOriginalNode,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode& aNode, nsAString& aStr) {
|
nsresult nsDocumentEncoder::SerializeNodeEnd(nsINode& aOriginalNode,
|
||||||
|
nsAString& aStr,
|
||||||
|
nsINode* aFixupNode) {
|
||||||
if (mNeedsPreformatScanning) {
|
if (mNeedsPreformatScanning) {
|
||||||
if (aNode.IsElement()) {
|
if (aOriginalNode.IsElement()) {
|
||||||
mSerializer->ForgetElementForPreformat(aNode.AsElement());
|
mSerializer->ForgetElementForPreformat(aOriginalNode.AsElement());
|
||||||
} else if (aNode.IsText()) {
|
} else if (aOriginalNode.IsText()) {
|
||||||
const nsCOMPtr<nsINode> parent = aNode.GetParent();
|
const nsCOMPtr<nsINode> parent = aOriginalNode.GetParent();
|
||||||
if (parent && parent->IsElement()) {
|
if (parent && parent->IsElement()) {
|
||||||
mSerializer->ForgetElementForPreformat(parent->AsElement());
|
mSerializer->ForgetElementForPreformat(parent->AsElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsInvisibleNodeAndShouldBeSkipped(aNode)) {
|
if (IsInvisibleNodeAndShouldBeSkipped(aOriginalNode)) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
if (aNode.IsElement()) {
|
FixupNodeDeterminer fixupNodeDeterminer{mNodeFixup, aFixupNode,
|
||||||
rv = mSerializer->AppendElementEnd(aNode.AsElement(), aStr);
|
aOriginalNode};
|
||||||
|
nsINode* node = &fixupNodeDeterminer.GetFixupNodeFallBackToOriginalNode();
|
||||||
|
|
||||||
|
if (node->IsElement()) {
|
||||||
|
rv = mSerializer->AppendElementEnd(node->AsElement(),
|
||||||
|
aOriginalNode.AsElement(), aStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -773,7 +780,7 @@ nsresult nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aDontSerializeRoot) {
|
if (!aDontSerializeRoot) {
|
||||||
rv = SerializeNodeEnd(*maybeFixedNode, aStr);
|
rv = SerializeNodeEnd(*aNode, aStr, maybeFixedNode);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,9 @@ nsHTMLContentSerializer::AppendElementStart(Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHTMLContentSerializer::AppendElementEnd(Element* aElement, nsAString& aStr) {
|
nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
|
||||||
|
Element* aOriginalElement,
|
||||||
|
nsAString& aStr) {
|
||||||
NS_ENSURE_ARG(aElement);
|
NS_ENSURE_ARG(aElement);
|
||||||
|
|
||||||
nsAtom* name = aElement->NodeInfo()->NameAtom();
|
nsAtom* name = aElement->NodeInfo()->NameAtom();
|
||||||
|
|
|
@ -29,6 +29,7 @@ class nsHTMLContentSerializer final : public nsXHTMLContentSerializer {
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
|
|
||||||
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
|
|
||||||
NS_IMETHOD AppendDocumentStart(mozilla::dom::Document* aDocument,
|
NS_IMETHOD AppendDocumentStart(mozilla::dom::Document* aDocument,
|
||||||
|
|
|
@ -492,6 +492,22 @@ class nsIContent : public nsINode {
|
||||||
*/
|
*/
|
||||||
inline nsIContent* GetFlattenedTreeParent() const;
|
inline nsIContent* GetFlattenedTreeParent() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Handles getting inserted or removed directly under a <slot> element.
|
||||||
|
// This is meant to only be called from the two functions below.
|
||||||
|
inline void HandleInsertionToOrRemovalFromSlot();
|
||||||
|
|
||||||
|
// Handles Shadow-DOM-related state tracking. Meant to be called near the
|
||||||
|
// end of BindToTree(), only if the tree we're in actually changed, that is,
|
||||||
|
// after the subtree has been bound to the new parent.
|
||||||
|
inline void HandleShadowDOMRelatedInsertionSteps(bool aHadParent);
|
||||||
|
|
||||||
|
// Handles Shadow-DOM related state tracking. Meant to be called near the
|
||||||
|
// beginning of UnbindFromTree(), before the node has lost the reference to
|
||||||
|
// its parent.
|
||||||
|
inline void HandleShadowDOMRelatedRemovalSteps(bool aNullParent);
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* API to check if this is a link that's traversed in response to user input
|
* API to check if this is a link that's traversed in response to user input
|
||||||
* (e.g. a click event). Specializations for HTML/SVG/generic XML allow for
|
* (e.g. a click event). Specializations for HTML/SVG/generic XML allow for
|
||||||
|
|
|
@ -221,4 +221,51 @@ inline bool nsIContent::IsInAnonymousSubtree() const {
|
||||||
return !bindingParent->GetShadowRoot();
|
return !bindingParent->GetShadowRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void nsIContent::HandleInsertionToOrRemovalFromSlot() {
|
||||||
|
using mozilla::dom::HTMLSlotElement;
|
||||||
|
|
||||||
|
MOZ_ASSERT(GetParentElement());
|
||||||
|
if (!IsInShadowTree() || IsRootOfAnonymousSubtree()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HTMLSlotElement* slot = HTMLSlotElement::FromNode(mParent);
|
||||||
|
if (!slot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If parent's root is a shadow root, and parent is a slot whose
|
||||||
|
// assigned nodes is the empty list, then run signal a slot change for
|
||||||
|
// parent.
|
||||||
|
if (slot->AssignedNodes().IsEmpty()) {
|
||||||
|
slot->EnqueueSlotChangeEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void nsIContent::HandleShadowDOMRelatedInsertionSteps(bool aHadParent) {
|
||||||
|
using mozilla::dom::Element;
|
||||||
|
using mozilla::dom::ShadowRoot;
|
||||||
|
|
||||||
|
if (!aHadParent) {
|
||||||
|
if (Element* parentElement = Element::FromNode(mParent)) {
|
||||||
|
if (ShadowRoot* shadow = parentElement->GetShadowRoot()) {
|
||||||
|
shadow->MaybeSlotHostChild(*this);
|
||||||
|
}
|
||||||
|
HandleInsertionToOrRemovalFromSlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void nsIContent::HandleShadowDOMRelatedRemovalSteps(bool aNullParent) {
|
||||||
|
using mozilla::dom::Element;
|
||||||
|
using mozilla::dom::ShadowRoot;
|
||||||
|
|
||||||
|
if (aNullParent) {
|
||||||
|
if (Element* parentElement = Element::FromNode(mParent)) {
|
||||||
|
if (ShadowRoot* shadow = parentElement->GetShadowRoot()) {
|
||||||
|
shadow->MaybeUnslotHostChild(*this);
|
||||||
|
}
|
||||||
|
HandleInsertionToOrRemovalFromSlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // nsIContentInlines_h
|
#endif // nsIContentInlines_h
|
||||||
|
|
|
@ -60,6 +60,7 @@ class nsIContentSerializer : public nsISupports {
|
||||||
nsAString& aStr) = 0;
|
nsAString& aStr) = 0;
|
||||||
|
|
||||||
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
nsAString& aStr) = 0;
|
nsAString& aStr) = 0;
|
||||||
|
|
||||||
NS_IMETHOD Flush(nsAString& aStr) = 0;
|
NS_IMETHOD Flush(nsAString& aStr) = 0;
|
||||||
|
|
|
@ -419,7 +419,9 @@ nsPlainTextSerializer::AppendElementStart(Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsPlainTextSerializer::AppendElementEnd(Element* aElement, nsAString& aStr) {
|
nsPlainTextSerializer::AppendElementEnd(Element* aElement,
|
||||||
|
Element* aOriginalElement,
|
||||||
|
nsAString& aStr) {
|
||||||
NS_ENSURE_ARG(aElement);
|
NS_ENSURE_ARG(aElement);
|
||||||
|
|
||||||
mElement = aElement;
|
mElement = aElement;
|
||||||
|
|
|
@ -69,6 +69,7 @@ class nsPlainTextSerializer final : public nsIContentSerializer {
|
||||||
mozilla::dom::Element* aOriginalElement,
|
mozilla::dom::Element* aOriginalElement,
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
NS_IMETHOD Flush(nsAString& aStr) override;
|
NS_IMETHOD Flush(nsAString& aStr) override;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
#include "mozilla/SSE.h"
|
#include "mozilla/SSE.h"
|
||||||
|
#include "mozilla/ppc.h"
|
||||||
#include "nsTextFragmentImpl.h"
|
#include "nsTextFragmentImpl.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -166,6 +167,14 @@ int32_t FirstNon8Bit(const char16_t* str, const char16_t* end);
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
namespace mozilla {
|
||||||
|
namespace VMX {
|
||||||
|
int32_t FirstNon8Bit(const char16_t* str, const char16_t* end);
|
||||||
|
} // namespace VMX
|
||||||
|
} // namespace mozilla
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function returns -1 if all characters in str are 8 bit characters.
|
* This function returns -1 if all characters in str are 8 bit characters.
|
||||||
* Otherwise, it returns a value less than or equal to the index of the first
|
* Otherwise, it returns a value less than or equal to the index of the first
|
||||||
|
@ -178,6 +187,10 @@ static inline int32_t FirstNon8Bit(const char16_t* str, const char16_t* end) {
|
||||||
if (mozilla::supports_sse2()) {
|
if (mozilla::supports_sse2()) {
|
||||||
return mozilla::SSE2::FirstNon8Bit(str, end);
|
return mozilla::SSE2::FirstNon8Bit(str, end);
|
||||||
}
|
}
|
||||||
|
#elif defined(__powerpc__)
|
||||||
|
if (mozilla::supports_vmx()) {
|
||||||
|
return mozilla::VMX::FirstNon8Bit(str, end);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return FirstNon8BitUnvectorized(str, end);
|
return FirstNon8BitUnvectorized(str, end);
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
// This file should only be compiled if you're on Power ISA.
|
||||||
|
|
||||||
|
#include "nscore.h"
|
||||||
|
#include "nsAlgorithm.h"
|
||||||
|
#include "nsTextFragmentImpl.h"
|
||||||
|
#include <altivec.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace VMX {
|
||||||
|
|
||||||
|
int32_t FirstNon8Bit(const char16_t* str, const char16_t* end) {
|
||||||
|
const uint32_t numUnicharsPerVector = 8;
|
||||||
|
const uint32_t numCharsPerVector = 16;
|
||||||
|
// Paranoia. If this assertion is wrong, change the vector loop below.
|
||||||
|
MOZ_ASSERT((numCharsPerVector / numUnicharsPerVector) == sizeof(char16_t));
|
||||||
|
|
||||||
|
typedef Non8BitParameters<sizeof(size_t)> p;
|
||||||
|
const uint32_t alignMask = p::alignMask();
|
||||||
|
const size_t mask = p::mask();
|
||||||
|
const uint32_t numUnicharsPerWord = p::numUnicharsPerWord();
|
||||||
|
|
||||||
|
const uint32_t len = end - str;
|
||||||
|
|
||||||
|
// i shall count the index in unichars; i2 shall count the index in chars.
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t i2 = 0;
|
||||||
|
|
||||||
|
// Align ourselves to a 16-byte boundary, as required by VMX loads.
|
||||||
|
uint32_t alignLen = std::min(
|
||||||
|
len, uint32_t(((-NS_PTR_TO_UINT32(str)) & 0xf) / sizeof(char16_t)));
|
||||||
|
|
||||||
|
if ((len - alignLen) >= numUnicharsPerVector) {
|
||||||
|
for (; i < alignLen; i++) {
|
||||||
|
if (str[i] > 255) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct a vector of shorts.
|
||||||
|
#if __LITTLE_ENDIAN__
|
||||||
|
register const vector unsigned short gtcompare =
|
||||||
|
reinterpret_cast<vector unsigned short>(
|
||||||
|
vec_mergel(vec_splat_s8(-1), vec_splat_s8(0)));
|
||||||
|
#else
|
||||||
|
register const vector unsigned short gtcompare =
|
||||||
|
reinterpret_cast<vector unsigned short>(
|
||||||
|
vec_mergel(vec_splat_s8(0), vec_splat_s8(-1)));
|
||||||
|
#endif
|
||||||
|
const uint32_t vectWalkEnd =
|
||||||
|
((len - i) / numUnicharsPerVector) * numUnicharsPerVector;
|
||||||
|
i2 = i * sizeof(char16_t);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
register vector unsigned short vect;
|
||||||
|
|
||||||
|
// Check one VMX register (8 unichars) at a time. The vec_any_gt
|
||||||
|
// intrinsic does exactly what we want. This loop is manually unrolled;
|
||||||
|
// it yields notable performance improvements this way.
|
||||||
|
#define CheckForASCII \
|
||||||
|
vect = vec_ld(i2, reinterpret_cast<const unsigned short*>(str)); \
|
||||||
|
if (vec_any_gt(vect, gtcompare)) return i; \
|
||||||
|
i += numUnicharsPerVector; \
|
||||||
|
if (!(i < vectWalkEnd)) break; \
|
||||||
|
i2 += numCharsPerVector;
|
||||||
|
|
||||||
|
CheckForASCII CheckForASCII
|
||||||
|
|
||||||
|
#undef CheckForASCII
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Align ourselves to a word boundary.
|
||||||
|
alignLen = std::min(len, uint32_t(((-NS_PTR_TO_UINT32(str)) & alignMask) /
|
||||||
|
sizeof(char16_t)));
|
||||||
|
for (; i < alignLen; i++) {
|
||||||
|
if (str[i] > 255) return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check one word at a time.
|
||||||
|
const uint32_t wordWalkEnd =
|
||||||
|
((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
|
||||||
|
for (; i < wordWalkEnd; i += numUnicharsPerWord) {
|
||||||
|
const size_t word = *reinterpret_cast<const size_t*>(str + i);
|
||||||
|
if (word & mask) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take care of the remainder one character at a time.
|
||||||
|
for (; i < len; i++) {
|
||||||
|
if (str[i] > 255) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VMX
|
||||||
|
} // namespace mozilla
|
|
@ -410,6 +410,7 @@ bool nsXHTMLContentSerializer::CheckElementStart(Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsXHTMLContentSerializer::CheckElementEnd(Element* aElement,
|
bool nsXHTMLContentSerializer::CheckElementEnd(Element* aElement,
|
||||||
|
Element* aOriginalElement,
|
||||||
bool& aForceFormat,
|
bool& aForceFormat,
|
||||||
nsAString& aStr) {
|
nsAString& aStr) {
|
||||||
NS_ASSERTION(!mIsHTMLSerializer,
|
NS_ASSERTION(!mIsHTMLSerializer,
|
||||||
|
@ -428,7 +429,8 @@ bool nsXHTMLContentSerializer::CheckElementEnd(Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dummyFormat;
|
bool dummyFormat;
|
||||||
return nsXMLContentSerializer::CheckElementEnd(aElement, dummyFormat, aStr);
|
return nsXMLContentSerializer::CheckElementEnd(aElement, aOriginalElement,
|
||||||
|
dummyFormat, aStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsXHTMLContentSerializer::AppendAndTranslateEntities(
|
bool nsXHTMLContentSerializer::AppendAndTranslateEntities(
|
||||||
|
|
|
@ -52,6 +52,7 @@ class nsXHTMLContentSerializer : public nsXMLContentSerializer {
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
|
|
||||||
virtual bool CheckElementEnd(mozilla::dom::Element* aContent,
|
virtual bool CheckElementEnd(mozilla::dom::Element* aContent,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
bool& aForceFormat, nsAString& aStr) override;
|
bool& aForceFormat, nsAString& aStr) override;
|
||||||
|
|
||||||
virtual void AfterElementEnd(nsIContent* aContent, nsAString& aStr) override;
|
virtual void AfterElementEnd(nsIContent* aContent, nsAString& aStr) override;
|
||||||
|
|
|
@ -955,13 +955,16 @@ bool nsXMLContentSerializer::AppendEndOfElementStart(Element* aElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLContentSerializer::AppendElementEnd(Element* aElement, nsAString& aStr) {
|
nsXMLContentSerializer::AppendElementEnd(Element* aElement,
|
||||||
|
Element* aOriginalElement,
|
||||||
|
nsAString& aStr) {
|
||||||
NS_ENSURE_ARG(aElement);
|
NS_ENSURE_ARG(aElement);
|
||||||
|
|
||||||
nsIContent* content = aElement;
|
nsIContent* content = aElement;
|
||||||
|
|
||||||
bool forceFormat = false, outputElementEnd;
|
bool forceFormat = false, outputElementEnd;
|
||||||
outputElementEnd = CheckElementEnd(aElement, forceFormat, aStr);
|
outputElementEnd =
|
||||||
|
CheckElementEnd(aElement, aOriginalElement, forceFormat, aStr);
|
||||||
|
|
||||||
nsAtom* name = content->NodeInfo()->NameAtom();
|
nsAtom* name = content->NodeInfo()->NameAtom();
|
||||||
|
|
||||||
|
@ -1083,15 +1086,12 @@ bool nsXMLContentSerializer::CheckElementStart(Element*, bool& aForceFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsXMLContentSerializer::CheckElementEnd(Element* aElement,
|
bool nsXMLContentSerializer::CheckElementEnd(Element* aElement,
|
||||||
|
Element* aOriginalElement,
|
||||||
bool& aForceFormat,
|
bool& aForceFormat,
|
||||||
nsAString& aStr) {
|
nsAString& aStr) {
|
||||||
// We don't output a separate end tag for empty element
|
// We don't output a separate end tag for empty element
|
||||||
aForceFormat = false;
|
aForceFormat = false;
|
||||||
|
return ElementNeedsSeparateEndTag(aElement, aOriginalElement);
|
||||||
// XXXbz this is a bit messed up, but by now we don't have our fixed-up
|
|
||||||
// version of aElement anymore. Let's hope fixup never changes the localName
|
|
||||||
// or namespace...
|
|
||||||
return ElementNeedsSeparateEndTag(aElement, aElement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nsXMLContentSerializer::AppendToString(const char16_t aChar,
|
bool nsXMLContentSerializer::AppendToString(const char16_t aChar,
|
||||||
|
|
|
@ -63,6 +63,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
|
|
||||||
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
nsAString& aStr) override;
|
nsAString& aStr) override;
|
||||||
|
|
||||||
NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; }
|
NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; }
|
||||||
|
@ -305,6 +306,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
||||||
* @return boolean true if the element can be output
|
* @return boolean true if the element can be output
|
||||||
*/
|
*/
|
||||||
virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
|
virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
|
||||||
|
mozilla::dom::Element* aOriginalElement,
|
||||||
bool& aForceFormat, nsAString& aStr);
|
bool& aForceFormat, nsAString& aStr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -154,26 +154,25 @@ const nsTArray<RefPtr<nsINode>>& HTMLSlotElement::AssignedNodes() const {
|
||||||
return mAssignedNodes;
|
return mAssignedNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsINode* aNode) {
|
void HTMLSlotElement::InsertAssignedNode(uint32_t aIndex, nsIContent& aNode) {
|
||||||
MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot(), "Losing track of a slot");
|
MOZ_ASSERT(!aNode.GetAssignedSlot(), "Losing track of a slot");
|
||||||
mAssignedNodes.InsertElementAt(aIndex, aNode);
|
mAssignedNodes.InsertElementAt(aIndex, &aNode);
|
||||||
aNode->AsContent()->SetAssignedSlot(this);
|
aNode.SetAssignedSlot(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSlotElement::AppendAssignedNode(nsINode* aNode) {
|
void HTMLSlotElement::AppendAssignedNode(nsIContent& aNode) {
|
||||||
MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot(), "Losing track of a slot");
|
MOZ_ASSERT(!aNode.GetAssignedSlot(), "Losing track of a slot");
|
||||||
mAssignedNodes.AppendElement(aNode);
|
mAssignedNodes.AppendElement(&aNode);
|
||||||
aNode->AsContent()->SetAssignedSlot(this);
|
aNode.SetAssignedSlot(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSlotElement::RemoveAssignedNode(nsINode* aNode) {
|
void HTMLSlotElement::RemoveAssignedNode(nsIContent& aNode) {
|
||||||
// This one runs from unlinking, so we can't guarantee that the slot pointer
|
// This one runs from unlinking, so we can't guarantee that the slot pointer
|
||||||
// hasn't been cleared.
|
// hasn't been cleared.
|
||||||
MOZ_ASSERT(!aNode->AsContent()->GetAssignedSlot() ||
|
MOZ_ASSERT(!aNode.GetAssignedSlot() || aNode.GetAssignedSlot() == this,
|
||||||
aNode->AsContent()->GetAssignedSlot() == this,
|
|
||||||
"How exactly?");
|
"How exactly?");
|
||||||
mAssignedNodes.RemoveElement(aNode);
|
mAssignedNodes.RemoveElement(&aNode);
|
||||||
aNode->AsContent()->SetAssignedSlot(nullptr);
|
aNode.SetAssignedSlot(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLSlotElement::ClearAssignedNodes() {
|
void HTMLSlotElement::ClearAssignedNodes() {
|
||||||
|
|
|
@ -54,9 +54,9 @@ class HTMLSlotElement final : public nsGenericHTMLElement {
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
const nsTArray<RefPtr<nsINode>>& AssignedNodes() const;
|
const nsTArray<RefPtr<nsINode>>& AssignedNodes() const;
|
||||||
void InsertAssignedNode(uint32_t aIndex, nsINode* aNode);
|
void InsertAssignedNode(uint32_t aIndex, nsIContent&);
|
||||||
void AppendAssignedNode(nsINode* aNode);
|
void AppendAssignedNode(nsIContent&);
|
||||||
void RemoveAssignedNode(nsINode* aNode);
|
void RemoveAssignedNode(nsIContent&);
|
||||||
void ClearAssignedNodes();
|
void ClearAssignedNodes();
|
||||||
|
|
||||||
void EnqueueSlotChangeEvent();
|
void EnqueueSlotChangeEvent();
|
||||||
|
|
|
@ -47,6 +47,7 @@ skip-if = toolkit == 'android'
|
||||||
[test_same_site_cookies_toplevel_nav.html]
|
[test_same_site_cookies_toplevel_nav.html]
|
||||||
skip-if = fission # Crashes: @ mozilla::dom::ContentParent::CommonCreateWindow(mozilla::dom::PBrowserParent*, bool, unsigned int const&, bool const&, bool const&, bool const&, nsIURI*, nsTString<char> const&, float const&, unsigned long, nsTString<char16_t> const&, nsresult&, nsCOMPtr<nsIRemoteTab>&, bool*, int&, nsIPrincipal*, nsIReferrerInfo*, bool, nsIContentSecurityPolicy*)
|
skip-if = fission # Crashes: @ mozilla::dom::ContentParent::CommonCreateWindow(mozilla::dom::PBrowserParent*, bool, unsigned int const&, bool const&, bool const&, bool const&, nsIURI*, nsTString<char> const&, float const&, unsigned long, nsTString<char16_t> const&, nsresult&, nsCOMPtr<nsIRemoteTab>&, bool*, int&, nsIPrincipal*, nsIReferrerInfo*, bool, nsIContentSecurityPolicy*)
|
||||||
[test_same_site_cookies_cross_origin_context.html]
|
[test_same_site_cookies_cross_origin_context.html]
|
||||||
|
fail-if = fission
|
||||||
[test_same_site_cookies_from_script.html]
|
[test_same_site_cookies_from_script.html]
|
||||||
[test_same_site_cookies_redirect.html]
|
[test_same_site_cookies_redirect.html]
|
||||||
[test_same_site_cookies_toplevel_set_cookie.html]
|
[test_same_site_cookies_toplevel_set_cookie.html]
|
||||||
|
|
|
@ -156,7 +156,6 @@ skip-if = toolkit == 'android'
|
||||||
[test_bug1112040.html]
|
[test_bug1112040.html]
|
||||||
[test_bug1160342_marquee.html]
|
[test_bug1160342_marquee.html]
|
||||||
[test_bug1171215.html]
|
[test_bug1171215.html]
|
||||||
fail-if = fission
|
|
||||||
support-files = window_bug1171215.html
|
support-files = window_bug1171215.html
|
||||||
[test_bug1530292.html]
|
[test_bug1530292.html]
|
||||||
fail-if = fission
|
fail-if = fission
|
||||||
|
|
|
@ -27,6 +27,7 @@ skip-if = os == "android" || verify # bug 962029
|
||||||
[test_cookieBlock.html]
|
[test_cookieBlock.html]
|
||||||
[test_embededNulls.html]
|
[test_embededNulls.html]
|
||||||
[test_keySync.html]
|
[test_keySync.html]
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageBase.html]
|
[test_localStorageBase.html]
|
||||||
skip-if = e10s
|
skip-if = e10s
|
||||||
[test_localStorageBaseSessionOnly.html]
|
[test_localStorageBaseSessionOnly.html]
|
||||||
|
@ -34,12 +35,17 @@ skip-if = e10s
|
||||||
[test_localStorageEnablePref.html]
|
[test_localStorageEnablePref.html]
|
||||||
[test_localStorageKeyOrder.html]
|
[test_localStorageKeyOrder.html]
|
||||||
[test_localStorageOriginsDiff.html]
|
[test_localStorageOriginsDiff.html]
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageOriginsDomainDiffs.html]
|
[test_localStorageOriginsDomainDiffs.html]
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageOriginsEquals.html]
|
[test_localStorageOriginsEquals.html]
|
||||||
skip-if = toolkit == 'android'
|
skip-if = toolkit == 'android'
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageOriginsPortDiffs.html]
|
[test_localStorageOriginsPortDiffs.html]
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageOriginsSchemaDiffs.html]
|
[test_localStorageOriginsSchemaDiffs.html]
|
||||||
skip-if = toolkit == 'android' #TIMED_OUT
|
skip-if = toolkit == 'android' #TIMED_OUT
|
||||||
|
fail-if = fission
|
||||||
[test_localStorageQuota.html]
|
[test_localStorageQuota.html]
|
||||||
skip-if = toolkit == 'android' #TIMED_OUT
|
skip-if = toolkit == 'android' #TIMED_OUT
|
||||||
[test_localStorageQuotaSessionOnly.html]
|
[test_localStorageQuotaSessionOnly.html]
|
||||||
|
|
|
@ -25,15 +25,11 @@ support-files =
|
||||||
skip-if = toolkit == 'android' #bug 894914 - wrong data - got FAIL, expected message
|
skip-if = toolkit == 'android' #bug 894914 - wrong data - got FAIL, expected message
|
||||||
[test_postMessage_hash.html]
|
[test_postMessage_hash.html]
|
||||||
[test_postMessage.html]
|
[test_postMessage.html]
|
||||||
fail-if = fission
|
|
||||||
[test_postMessage_idn.xhtml]
|
[test_postMessage_idn.xhtml]
|
||||||
fail-if = fission
|
|
||||||
[test_postMessage_joined.html]
|
[test_postMessage_joined.html]
|
||||||
fail-if = fission
|
|
||||||
[test_postMessage_onOther.html]
|
[test_postMessage_onOther.html]
|
||||||
skip-if = fission #Bug 1571273
|
skip-if = fission #Bug 1571273
|
||||||
[test_postMessage_origin.xhtml]
|
[test_postMessage_origin.xhtml]
|
||||||
fail-if = fission
|
|
||||||
[test_postMessage_override.html]
|
[test_postMessage_override.html]
|
||||||
skip-if = fission
|
skip-if = fission
|
||||||
[test_postMessage_special.xhtml]
|
[test_postMessage_special.xhtml]
|
||||||
|
@ -43,7 +39,6 @@ skip-if = fission #Bug 1570918
|
||||||
[test_postMessage_transfer.html]
|
[test_postMessage_transfer.html]
|
||||||
skip-if = fission #Bug 1571208
|
skip-if = fission #Bug 1571208
|
||||||
[test_postMessage_userpass.html]
|
[test_postMessage_userpass.html]
|
||||||
fail-if = fission
|
|
||||||
[test_bug500328.html]
|
[test_bug500328.html]
|
||||||
skip-if = true || toolkit=='android' # bug 696306, #TIMED_OUT android
|
skip-if = true || toolkit=='android' # bug 696306, #TIMED_OUT android
|
||||||
support-files = file_bug500328_1.html file_bug500328_2.html
|
support-files = file_bug500328_1.html file_bug500328_2.html
|
||||||
|
|
|
@ -16,6 +16,7 @@ support-files =
|
||||||
|
|
||||||
[test_bug1081686.html]
|
[test_bug1081686.html]
|
||||||
[test_bug1384658.html]
|
[test_bug1384658.html]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
support-files = window_bug1384658.html frame_bug1384658.html file_bug1384658.html
|
support-files = window_bug1384658.html frame_bug1384658.html file_bug1384658.html
|
||||||
[test_event_listener_leaks.html]
|
[test_event_listener_leaks.html]
|
||||||
support-files = file_websocket_bigBlob_wsh.py
|
support-files = file_websocket_bigBlob_wsh.py
|
||||||
|
|
|
@ -145,6 +145,7 @@ tags = mcb
|
||||||
[test_location.html]
|
[test_location.html]
|
||||||
[test_longThread.html]
|
[test_longThread.html]
|
||||||
[test_multi_sharedWorker.html]
|
[test_multi_sharedWorker.html]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
[test_multi_sharedWorker_lifetimes.html]
|
[test_multi_sharedWorker_lifetimes.html]
|
||||||
[test_navigator.html]
|
[test_navigator.html]
|
||||||
support-files =
|
support-files =
|
||||||
|
|
|
@ -58,6 +58,16 @@ struct SurfaceDescriptorMacIOSurface {
|
||||||
YUVColorSpace yUVColorSpace;
|
YUVColorSpace yUVColorSpace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SurfaceDescriptorDMABuf {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t format;
|
||||||
|
uint32_t flags;
|
||||||
|
FileDescriptor fd;
|
||||||
|
uint32_t stride;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct SurfaceTextureDescriptor {
|
struct SurfaceTextureDescriptor {
|
||||||
uint64_t handle;
|
uint64_t handle;
|
||||||
IntSize size;
|
IntSize size;
|
||||||
|
@ -148,6 +158,7 @@ union SurfaceDescriptor {
|
||||||
SurfaceDescriptorFileMapping;
|
SurfaceDescriptorFileMapping;
|
||||||
SurfaceDescriptorDXGIYCbCr;
|
SurfaceDescriptorDXGIYCbCr;
|
||||||
SurfaceDescriptorX11;
|
SurfaceDescriptorX11;
|
||||||
|
SurfaceDescriptorDMABuf;
|
||||||
SurfaceTextureDescriptor;
|
SurfaceTextureDescriptor;
|
||||||
EGLImageDescriptor;
|
EGLImageDescriptor;
|
||||||
SurfaceDescriptorMacIOSurface;
|
SurfaceDescriptorMacIOSurface;
|
||||||
|
|
|
@ -439,7 +439,7 @@ set_define('JS_BUILD_BINAST', depends_if('--enable-binast')(lambda x: True))
|
||||||
# ==============================================================
|
# ==============================================================
|
||||||
|
|
||||||
js_option('--enable-cranelift',
|
js_option('--enable-cranelift',
|
||||||
default=milestone.is_nightly & js_standalone,
|
default=milestone.is_nightly,
|
||||||
help='{Enable|Disable} Cranelift code generator for wasm')
|
help='{Enable|Disable} Cranelift code generator for wasm')
|
||||||
|
|
||||||
set_config('ENABLE_WASM_CRANELIFT', depends_if('--enable-cranelift')(lambda x: True))
|
set_config('ENABLE_WASM_CRANELIFT', depends_if('--enable-cranelift')(lambda x: True))
|
||||||
|
|
|
@ -291,6 +291,7 @@ struct LazyScriptCreationData {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!closedOverBindings.appendAll(COB)) {
|
if (!closedOverBindings.appendAll(COB)) {
|
||||||
|
ReportOutOfMemory(cx); // closedOverBindings uses SystemAllocPolicy.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// |jit-test| skip-if: !('oomTest' in this)
|
||||||
|
var sourceText = `
|
||||||
|
function Outer() {
|
||||||
|
var X00, X01, X02, X03, X04, X05, X06, X07;
|
||||||
|
var X08, X09, X10, X11, X12, X13, X14, X15;
|
||||||
|
var X16, X17, X18, X19, X20, X21, X22, X23;
|
||||||
|
var X24, X25, X26, X27, X28, X29, X30, X31;
|
||||||
|
|
||||||
|
function LazyFunction() {
|
||||||
|
// Lots of closed-over bindings.
|
||||||
|
{ X00 = true; };
|
||||||
|
{ X01 = true; };
|
||||||
|
{ X02 = true; };
|
||||||
|
{ X03 = true; };
|
||||||
|
{ X04 = true; };
|
||||||
|
{ X05 = true; };
|
||||||
|
{ X06 = true; };
|
||||||
|
{ X07 = true; };
|
||||||
|
{ X08 = true; };
|
||||||
|
{ X09 = true; };
|
||||||
|
{ X10 = true; };
|
||||||
|
{ X11 = true; };
|
||||||
|
{ X12 = true; };
|
||||||
|
{ X13 = true; };
|
||||||
|
{ X14 = true; };
|
||||||
|
{ X15 = true; };
|
||||||
|
{ X16 = true; };
|
||||||
|
{ X17 = true; };
|
||||||
|
{ X18 = true; };
|
||||||
|
{ X19 = true; };
|
||||||
|
{ X20 = true; };
|
||||||
|
{ X21 = true; };
|
||||||
|
{ X22 = true; };
|
||||||
|
{ X23 = true; };
|
||||||
|
{ X24 = true; };
|
||||||
|
{ X25 = true; };
|
||||||
|
{ X26 = true; };
|
||||||
|
{ X27 = true; };
|
||||||
|
{ X28 = true; };
|
||||||
|
{ X29 = true; };
|
||||||
|
{ X30 = true; };
|
||||||
|
{ X31 = true; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
oomTest(function() {
|
||||||
|
evaluate(sourceText);
|
||||||
|
});
|
|
@ -0,0 +1,44 @@
|
||||||
|
// |jit-test| skip-if: !('oomTest' in this)
|
||||||
|
var sourceText = `
|
||||||
|
function Outer() {
|
||||||
|
function LazyFunction() {
|
||||||
|
// Lots of inner functions.
|
||||||
|
function F00() { }
|
||||||
|
function F01() { }
|
||||||
|
function F02() { }
|
||||||
|
function F03() { }
|
||||||
|
function F04() { }
|
||||||
|
function F05() { }
|
||||||
|
function F06() { }
|
||||||
|
function F07() { }
|
||||||
|
function F08() { }
|
||||||
|
function F09() { }
|
||||||
|
function F10() { }
|
||||||
|
function F11() { }
|
||||||
|
function F12() { }
|
||||||
|
function F13() { }
|
||||||
|
function F14() { }
|
||||||
|
function F15() { }
|
||||||
|
function F16() { }
|
||||||
|
function F17() { }
|
||||||
|
function F18() { }
|
||||||
|
function F19() { }
|
||||||
|
function F20() { }
|
||||||
|
function F21() { }
|
||||||
|
function F22() { }
|
||||||
|
function F23() { }
|
||||||
|
function F24() { }
|
||||||
|
function F25() { }
|
||||||
|
function F26() { }
|
||||||
|
function F27() { }
|
||||||
|
function F28() { }
|
||||||
|
function F29() { }
|
||||||
|
function F30() { }
|
||||||
|
function F31() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
oomTest(function() {
|
||||||
|
evaluate(sourceText);
|
||||||
|
});
|
|
@ -47,6 +47,9 @@ for stlfile in ['jsdate.*', 'jsnum.*']:
|
||||||
with Files('builtin/intl/*'):
|
with Files('builtin/intl/*'):
|
||||||
BUG_COMPONENT = component_intl
|
BUG_COMPONENT = component_intl
|
||||||
|
|
||||||
|
if CONFIG['ENABLE_WASM_CRANELIFT']:
|
||||||
|
CONFIGURE_SUBST_FILES += ['rust/extra-bindgen-flags']
|
||||||
|
|
||||||
if not CONFIG['JS_DISABLE_SHELL']:
|
if not CONFIG['JS_DISABLE_SHELL']:
|
||||||
DIRS += [
|
DIRS += [
|
||||||
'rust',
|
'rust',
|
||||||
|
|
|
@ -18,8 +18,6 @@ if CONFIG['ENABLE_WASM_CRANELIFT']:
|
||||||
|
|
||||||
RustLibrary('jsrust', features)
|
RustLibrary('jsrust', features)
|
||||||
|
|
||||||
CONFIGURE_SUBST_FILES += ['extra-bindgen-flags']
|
|
||||||
|
|
||||||
if CONFIG['JS_SHARED_LIBRARY']:
|
if CONFIG['JS_SHARED_LIBRARY']:
|
||||||
FINAL_LIBRARY = 'js'
|
FINAL_LIBRARY = 'js'
|
||||||
|
|
||||||
|
|
|
@ -4012,9 +4012,7 @@ void PaintedLayerData::AccumulateHitTestItem(ContainerState* aState,
|
||||||
nsDisplayItem* aItem,
|
nsDisplayItem* aItem,
|
||||||
const DisplayItemClip& aClip,
|
const DisplayItemClip& aClip,
|
||||||
TransformClipNode* aTransform) {
|
TransformClipNode* aTransform) {
|
||||||
MOZ_ASSERT(aItem->HasHitTestInfo());
|
|
||||||
auto* item = static_cast<nsDisplayHitTestInfoItem*>(aItem);
|
auto* item = static_cast<nsDisplayHitTestInfoItem*>(aItem);
|
||||||
|
|
||||||
const HitTestInfo& info = item->GetHitTestInfo();
|
const HitTestInfo& info = item->GetHitTestInfo();
|
||||||
|
|
||||||
nsRect area = info.mArea;
|
nsRect area = info.mArea;
|
||||||
|
@ -4556,6 +4554,7 @@ void ContainerState::ProcessDisplayItems(nsDisplayList* aList) {
|
||||||
nsRect itemContent;
|
nsRect itemContent;
|
||||||
|
|
||||||
if (marker == DisplayItemEntryType::HitTestInfo) {
|
if (marker == DisplayItemEntryType::HitTestInfo) {
|
||||||
|
MOZ_ASSERT(item->IsHitTestItem());
|
||||||
const auto& hitTestInfo =
|
const auto& hitTestInfo =
|
||||||
static_cast<nsDisplayHitTestInfoItem*>(item)->GetHitTestInfo();
|
static_cast<nsDisplayHitTestInfoItem*>(item)->GetHitTestInfo();
|
||||||
|
|
||||||
|
|
|
@ -3874,8 +3874,8 @@ struct HitTestInfo {
|
||||||
nsRect mArea;
|
nsRect mArea;
|
||||||
mozilla::gfx::CompositorHitTestInfo mFlags;
|
mozilla::gfx::CompositorHitTestInfo mFlags;
|
||||||
|
|
||||||
AnimatedGeometryRoot* mAGR;
|
RefPtr<AnimatedGeometryRoot> mAGR;
|
||||||
const mozilla::ActiveScrolledRoot* mASR;
|
RefPtr<const mozilla::ActiveScrolledRoot> mASR;
|
||||||
RefPtr<const mozilla::DisplayItemClipChain> mClipChain;
|
RefPtr<const mozilla::DisplayItemClipChain> mClipChain;
|
||||||
const mozilla::DisplayItemClip* mClip;
|
const mozilla::DisplayItemClip* mClip;
|
||||||
};
|
};
|
||||||
|
@ -3893,7 +3893,10 @@ class nsDisplayHitTestInfoItem : public nsPaintedDisplayItem {
|
||||||
const nsDisplayHitTestInfoItem& aOther)
|
const nsDisplayHitTestInfoItem& aOther)
|
||||||
: nsPaintedDisplayItem(aBuilder, aOther) {}
|
: nsPaintedDisplayItem(aBuilder, aOther) {}
|
||||||
|
|
||||||
const HitTestInfo& GetHitTestInfo() const { return *mHitTestInfo; }
|
const HitTestInfo& GetHitTestInfo() const {
|
||||||
|
MOZ_ASSERT(HasHitTestInfo());
|
||||||
|
return *mHitTestInfo;
|
||||||
|
}
|
||||||
|
|
||||||
void SetActiveScrolledRoot(
|
void SetActiveScrolledRoot(
|
||||||
const ActiveScrolledRoot* aActiveScrolledRoot) override {
|
const ActiveScrolledRoot* aActiveScrolledRoot) override {
|
||||||
|
|
|
@ -456,7 +456,9 @@ this.tabs = class extends ExtensionAPI {
|
||||||
queryInfo = Object.assign({}, queryInfo);
|
queryInfo = Object.assign({}, queryInfo);
|
||||||
|
|
||||||
if (queryInfo.url !== null) {
|
if (queryInfo.url !== null) {
|
||||||
queryInfo.url = new MatchPatternSet([].concat(queryInfo.url));
|
queryInfo.url = new MatchPatternSet([].concat(queryInfo.url), {
|
||||||
|
restrictSchemes: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (queryInfo.title !== null) {
|
if (queryInfo.title !== null) {
|
||||||
queryInfo.title = new MatchGlob(queryInfo.title);
|
queryInfo.title = new MatchGlob(queryInfo.title);
|
||||||
|
|
|
@ -1240,4 +1240,41 @@ class NavigationDelegateTest : BaseSessionTest() {
|
||||||
mainSession.loadTestPath(HELLO_HTML_PATH)
|
mainSession.loadTestPath(HELLO_HTML_PATH)
|
||||||
sessionRule.waitForPageStop()
|
sessionRule.waitForPageStop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun setLocationHash() {
|
||||||
|
sessionRule.session.loadUri("$TEST_ENDPOINT$HELLO_HTML_PATH")
|
||||||
|
sessionRule.waitForPageStop()
|
||||||
|
|
||||||
|
sessionRule.session.evaluateJS("location.hash = 'test1';")
|
||||||
|
|
||||||
|
sessionRule.session.waitUntilCalled(object : Callbacks.NavigationDelegate {
|
||||||
|
@AssertCalled(count = 0)
|
||||||
|
override fun onLoadRequest(session: GeckoSession,
|
||||||
|
request: LoadRequest):
|
||||||
|
GeckoResult<AllowOrDeny>? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssertCalled(count = 1)
|
||||||
|
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||||
|
assertThat("URI should match", url, endsWith("#test1"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
sessionRule.session.evaluateJS("location.hash = 'test2';")
|
||||||
|
|
||||||
|
sessionRule.session.waitUntilCalled(object : Callbacks.NavigationDelegate {
|
||||||
|
@AssertCalled(count = 0)
|
||||||
|
override fun onLoadRequest(session: GeckoSession,
|
||||||
|
request: LoadRequest):
|
||||||
|
GeckoResult<AllowOrDeny>? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssertCalled(count = 1)
|
||||||
|
override fun onLocationChange(session: GeckoSession, url: String?) {
|
||||||
|
assertThat("URI should match", url, endsWith("#test2"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ skip-if = verify
|
||||||
[test_1503201.html]
|
[test_1503201.html]
|
||||||
[test_origin_header.html]
|
[test_origin_header.html]
|
||||||
[test_1502055.html]
|
[test_1502055.html]
|
||||||
|
skip-if = fission # Timeouts
|
||||||
support-files = sw_1502055.js file_1502055.sjs iframe_1502055.html
|
support-files = sw_1502055.js file_1502055.sjs iframe_1502055.html
|
||||||
[test_accept_header.html]
|
[test_accept_header.html]
|
||||||
support-files = test_accept_header.sjs
|
support-files = test_accept_header.sjs
|
||||||
|
|
|
@ -221,3 +221,45 @@ rustfmt:
|
||||||
when:
|
when:
|
||||||
files-changed:
|
files-changed:
|
||||||
- '**/*.rs'
|
- '**/*.rs'
|
||||||
|
|
||||||
|
|
||||||
|
file-whitespace:
|
||||||
|
description: Check for trailing whitespaces and Windows CR
|
||||||
|
platform: lint/opt
|
||||||
|
treeherder:
|
||||||
|
symbol: file-whitespace
|
||||||
|
run:
|
||||||
|
mach: lint -l file-whitespace -f treeherder -f json:/builds/worker/mozlint.json
|
||||||
|
when:
|
||||||
|
files-changed:
|
||||||
|
- '**/*.c'
|
||||||
|
- '**/*.cc'
|
||||||
|
- '**/*.cpp'
|
||||||
|
- '**/*.h'
|
||||||
|
- '**/*.py'
|
||||||
|
- '**/*.rs'
|
||||||
|
|
||||||
|
|
||||||
|
file-perm:
|
||||||
|
description: Check for incorrect permissions on source files
|
||||||
|
platform: lint/opt
|
||||||
|
treeherder:
|
||||||
|
symbol: file-perm
|
||||||
|
run:
|
||||||
|
mach: lint -l file-perm -f treeherder -f json:/builds/worker/mozlint.json
|
||||||
|
when:
|
||||||
|
files-changed:
|
||||||
|
- '**/*.c'
|
||||||
|
- '**/*.cc'
|
||||||
|
- '**/*.cpp'
|
||||||
|
- '**/*.h'
|
||||||
|
- '**/*.html'
|
||||||
|
- '**/*.js'
|
||||||
|
- '**/*.jsm'
|
||||||
|
- '**/*.jsx'
|
||||||
|
- '**/*.m'
|
||||||
|
- '**/*.mm'
|
||||||
|
- '**/*.rs'
|
||||||
|
- '**/*.xhtml'
|
||||||
|
- '**/*.xml'
|
||||||
|
- '**/*.xul'
|
||||||
|
|
|
@ -238,7 +238,8 @@ def use_fetches(config, jobs):
|
||||||
extract = artifact.get('extract', True)
|
extract = artifact.get('extract', True)
|
||||||
|
|
||||||
fetch = {
|
fetch = {
|
||||||
'artifact': '{prefix}/{path}'.format(prefix=prefix, path=path),
|
'artifact': '{prefix}/{path}'.format(prefix=prefix, path=path)
|
||||||
|
if not path.startswith('/') else path[1:],
|
||||||
'task': '<{dep}>'.format(dep=kind),
|
'task': '<{dep}>'.format(dep=kind),
|
||||||
'extract': extract,
|
'extract': extract,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
[multicol-breaking-005.html]
|
||||||
|
prefs: [layout.css.column-span.enabled:true]
|
|
@ -0,0 +1,2 @@
|
||||||
|
[multicol-breaking-nobackground-005.html]
|
||||||
|
prefs: [layout.css.column-span.enabled:true]
|
|
@ -0,0 +1,100 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>CSS Test Reference: breaking of a multicolumn</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
|
||||||
|
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org/">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
height: 200px;
|
||||||
|
width: 800px;
|
||||||
|
background: rgba(0, 0, 255, 0.3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blueborders {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 262px; /* 256px first column + (16px gap - 4px rule) / 2 */
|
||||||
|
width: 268px; /* 256px second column + (16px gap - 4px rule) */
|
||||||
|
height: 200px;
|
||||||
|
border-right: blue solid 4px;
|
||||||
|
border-left: blue solid 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerbg {
|
||||||
|
height: 100px;
|
||||||
|
width: 256px;
|
||||||
|
background: rgba(255, 0, 255, 0.3);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
height: 100px;
|
||||||
|
width: 120px;
|
||||||
|
font: 16px/1.25 sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lefthalf {
|
||||||
|
border-right: 2px solid fuchsia;
|
||||||
|
padding-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.righthalf {
|
||||||
|
padding-left: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="outer">
|
||||||
|
<div class="blueborders"></div>
|
||||||
|
<div class="innerbg" style="left: 0"></div>
|
||||||
|
<div class="inner lefthalf" style="left: 0">
|
||||||
|
AAAAA<br>
|
||||||
|
BBBBB<br>
|
||||||
|
CCCCC<br>
|
||||||
|
DDDDD<br>
|
||||||
|
EEEEE
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 129px">
|
||||||
|
FFFFF<br>
|
||||||
|
GGGGG<br>
|
||||||
|
HHHHH<br>
|
||||||
|
IIIII<br>
|
||||||
|
JJJJJ
|
||||||
|
</div>
|
||||||
|
<div class="innerbg" style="left: 272px"></div>
|
||||||
|
<div class="inner lefthalf" style="left: 272px">
|
||||||
|
KKKKK<br>
|
||||||
|
LLLLL<br>
|
||||||
|
MMMMM<br>
|
||||||
|
NNNNN<br>
|
||||||
|
OOOOO
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 401px">
|
||||||
|
PPPPP<br>
|
||||||
|
QQQQQ<br>
|
||||||
|
RRRRR<br>
|
||||||
|
SSSSS<br>
|
||||||
|
TTTTT
|
||||||
|
</div>
|
||||||
|
<div class="innerbg" style="left: 544px"></div>
|
||||||
|
<div class="inner lefthalf" style="left: 544px">
|
||||||
|
UUUUU<br>
|
||||||
|
VVVVV<br>
|
||||||
|
WWWWW<br>
|
||||||
|
XXXXX<br>
|
||||||
|
YYYYY
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 673px">
|
||||||
|
ZZZZZ<br>
|
||||||
|
aaaaa<br>
|
||||||
|
bbbbb<br>
|
||||||
|
ccccc<br>
|
||||||
|
ddddd
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,70 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>CSS Test: breaking of a multicolumn</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
|
||||||
|
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org/">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
|
||||||
|
<link rel="match" href="multicol-breaking-005-ref.html">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
height: 200px;
|
||||||
|
width: 800px;
|
||||||
|
column-fill: balance;
|
||||||
|
column-count: 3;
|
||||||
|
column-rule: 4px solid blue;
|
||||||
|
column-gap: 16px;
|
||||||
|
background: rgba(0, 0, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
column-count: 2;
|
||||||
|
column-fill: balance;
|
||||||
|
column-rule: 2px solid fuchsia;
|
||||||
|
column-gap: 16px;
|
||||||
|
background: rgba(255, 0, 255, 0.3);
|
||||||
|
font: 16px/1.25 sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- This test is similar to multicol-breaking-002.html,
|
||||||
|
but both outer and inner columns are balancing. The outer multi-column is
|
||||||
|
made explicitly taller than the inner columns' optimal balance height. -->
|
||||||
|
<div class="outer">
|
||||||
|
<div class="inner" style="height: 300px">
|
||||||
|
AAAAA<br>
|
||||||
|
BBBBB<br>
|
||||||
|
CCCCC<br>
|
||||||
|
DDDDD<br>
|
||||||
|
EEEEE<br>
|
||||||
|
FFFFF<br>
|
||||||
|
GGGGG<br>
|
||||||
|
HHHHH<br>
|
||||||
|
IIIII<br>
|
||||||
|
JJJJJ<br>
|
||||||
|
KKKKK<br>
|
||||||
|
LLLLL<br>
|
||||||
|
MMMMM<br>
|
||||||
|
NNNNN<br>
|
||||||
|
OOOOO<br>
|
||||||
|
PPPPP<br>
|
||||||
|
QQQQQ<br>
|
||||||
|
RRRRR<br>
|
||||||
|
SSSSS<br>
|
||||||
|
TTTTT<br>
|
||||||
|
UUUUU<br>
|
||||||
|
VVVVV<br>
|
||||||
|
WWWWW<br>
|
||||||
|
XXXXX<br>
|
||||||
|
YYYYY<br>
|
||||||
|
ZZZZZ<br>
|
||||||
|
aaaaa<br>
|
||||||
|
bbbbb<br>
|
||||||
|
ccccc<br>
|
||||||
|
ddddd
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,86 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>CSS Test Reference: breaking of a multicolumn</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
|
||||||
|
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org/">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
height: 200px;
|
||||||
|
width: 800px;
|
||||||
|
background: rgba(0, 0, 255, 0.3);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.innerbg {
|
||||||
|
height: 100px;
|
||||||
|
width: 256px;
|
||||||
|
background: rgba(255, 0, 255, 0.3);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
height: 100px;
|
||||||
|
width: 120px;
|
||||||
|
font: 16px/1.25 sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lefthalf {
|
||||||
|
border-right: 2px solid fuchsia;
|
||||||
|
padding-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.righthalf {
|
||||||
|
padding-left: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="outer">
|
||||||
|
<div class="inner lefthalf" style="left: 0">
|
||||||
|
AAAAA<br>
|
||||||
|
BBBBB<br>
|
||||||
|
CCCCC<br>
|
||||||
|
DDDDD<br>
|
||||||
|
EEEEE
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 129px">
|
||||||
|
FFFFF<br>
|
||||||
|
GGGGG<br>
|
||||||
|
HHHHH<br>
|
||||||
|
IIIII<br>
|
||||||
|
JJJJJ
|
||||||
|
</div>
|
||||||
|
<div class="inner lefthalf" style="left: 272px">
|
||||||
|
KKKKK<br>
|
||||||
|
LLLLL<br>
|
||||||
|
MMMMM<br>
|
||||||
|
NNNNN<br>
|
||||||
|
OOOOO
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 401px">
|
||||||
|
PPPPP<br>
|
||||||
|
QQQQQ<br>
|
||||||
|
RRRRR<br>
|
||||||
|
SSSSS<br>
|
||||||
|
TTTTT
|
||||||
|
</div>
|
||||||
|
<div class="inner lefthalf" style="left: 544px">
|
||||||
|
UUUUU<br>
|
||||||
|
VVVVV<br>
|
||||||
|
WWWWW<br>
|
||||||
|
XXXXX<br>
|
||||||
|
YYYYY
|
||||||
|
</div>
|
||||||
|
<div class="inner righthalf" style="left: 673px">
|
||||||
|
ZZZZZ<br>
|
||||||
|
aaaaa<br>
|
||||||
|
bbbbb<br>
|
||||||
|
ccccc<br>
|
||||||
|
ddddd
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<title>CSS Test: breaking of a multicolumn</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="author" title="L. David Baron" href="https://dbaron.org/">
|
||||||
|
<link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org/">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-multicol/#column-gaps-and-rules">
|
||||||
|
<link rel="help" href="https://drafts.csswg.org/css-multicol/#cf">
|
||||||
|
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/2309">
|
||||||
|
<link rel="match" href="multicol-breaking-nobackground-005-ref.html">
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
height: 200px;
|
||||||
|
width: 800px;
|
||||||
|
column-fill: balance;
|
||||||
|
column-count: 3;
|
||||||
|
column-gap: 16px;
|
||||||
|
background: rgba(0, 0, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
column-count: 2;
|
||||||
|
column-fill: balance;
|
||||||
|
column-rule: 2px solid fuchsia;
|
||||||
|
column-gap: 16px;
|
||||||
|
font: 16px/1.25 sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- This test is similar to multicol-breaking-nobackground-002.html,
|
||||||
|
but both outer and inner columns are balancing. The outer multi-column is
|
||||||
|
made explicitly taller than the inner columns' optimal balance height. -->
|
||||||
|
<div class="outer">
|
||||||
|
<div class="inner" style="height: 300px">
|
||||||
|
AAAAA<br>
|
||||||
|
BBBBB<br>
|
||||||
|
CCCCC<br>
|
||||||
|
DDDDD<br>
|
||||||
|
EEEEE<br>
|
||||||
|
FFFFF<br>
|
||||||
|
GGGGG<br>
|
||||||
|
HHHHH<br>
|
||||||
|
IIIII<br>
|
||||||
|
JJJJJ<br>
|
||||||
|
KKKKK<br>
|
||||||
|
LLLLL<br>
|
||||||
|
MMMMM<br>
|
||||||
|
NNNNN<br>
|
||||||
|
OOOOO<br>
|
||||||
|
PPPPP<br>
|
||||||
|
QQQQQ<br>
|
||||||
|
RRRRR<br>
|
||||||
|
SSSSS<br>
|
||||||
|
TTTTT<br>
|
||||||
|
UUUUU<br>
|
||||||
|
VVVVV<br>
|
||||||
|
WWWWW<br>
|
||||||
|
XXXXX<br>
|
||||||
|
YYYYY<br>
|
||||||
|
ZZZZZ<br>
|
||||||
|
aaaaa<br>
|
||||||
|
bbbbb<br>
|
||||||
|
ccccc<br>
|
||||||
|
ddddd
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1 +1 @@
|
||||||
{"files":{"CODE_OF_CONDUCT.md":"e85149c44f478f164f7d5f55f6e66c9b5ae236d4a11107d5e2a93fe71dd874b9","Cargo.toml":"cfc0416b0a1c11ade3b5c11ec579c8e26ed3fc3b5871dd99d4fbcc12bd2614d0","LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","README.md":"303ea5ec53d4e86f2c321056e8158e31aa061353a99e52de3d76859d40919efc","src/driver.rs":"913de08a578b38902f4eb0d78147289897af5d3b1ecdad818c4ea6f83da6c714","src/error.rs":"d4ef0cba5c7fc54959ed62da166f10435548d705e0a817eed449fb001fe4e21d","src/guid.rs":"c82af64fba3ad87948a9b599241e48753d17587e8c642f610949163be3d499bf","src/lib.rs":"0606e69b235650bf404ae0b03a1e85c2063bb4b7147fa4d5e8ff2c128a757453","src/merge.rs":"e74727171831585d304eee3a3c7ba24fec52a5e7c6999ed4e647fefa14b8be99","src/store.rs":"629410e44485c0473617911be0e06dc5ce504c7427782be02f05a2f4096b5351","src/tests.rs":"51bc77eb989974f7594dfa0cdf7741f8e26f2956eebc34d1f71cbfd137512940","src/tree.rs":"fcdc9a5ae0e3f1b0d62d01bf1024db2a0aa8660e6839ada607a6a20e0fe2ad83"},"package":"251a15c9a597d70eb53cbb0c5473d8d8c6241aef615c092030ebab27fb5b26ef"}
|
{"files":{"CODE_OF_CONDUCT.md":"e85149c44f478f164f7d5f55f6e66c9b5ae236d4a11107d5e2a93fe71dd874b9","Cargo.toml":"9c145c9ecdad0143f95fb00d5646fb3f46203779a201f2f2389961563ca37397","LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","README.md":"303ea5ec53d4e86f2c321056e8158e31aa061353a99e52de3d76859d40919efc","src/driver.rs":"913de08a578b38902f4eb0d78147289897af5d3b1ecdad818c4ea6f83da6c714","src/error.rs":"d4ef0cba5c7fc54959ed62da166f10435548d705e0a817eed449fb001fe4e21d","src/guid.rs":"c82af64fba3ad87948a9b599241e48753d17587e8c642f610949163be3d499bf","src/lib.rs":"0606e69b235650bf404ae0b03a1e85c2063bb4b7147fa4d5e8ff2c128a757453","src/merge.rs":"bfc83aa6f42c196a5c6c75e095d1e44470198a38f3a62a6537cd5854d51208cd","src/store.rs":"629410e44485c0473617911be0e06dc5ce504c7427782be02f05a2f4096b5351","src/tests.rs":"fd2f03fd47e02459b7a3c7f799896be71536054184a2eca7e30cdbe817da0a97","src/tree.rs":"30c7d0c80f180936d1f99d2a3fbe9add36f3fe36a64998e3176d0242f425c488"},"package":"57cd6ee785daa898686f3e2fb4a2b1ce490fcd6d69665c857d16fb61b48f4aae"}
|
|
@ -13,7 +13,7 @@
|
||||||
[package]
|
[package]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "dogear"
|
name = "dogear"
|
||||||
version = "0.3.1"
|
version = "0.3.3"
|
||||||
authors = ["Lina Cambridge <lina@mozilla.com>"]
|
authors = ["Lina Cambridge <lina@mozilla.com>"]
|
||||||
exclude = ["/.travis/**", ".travis.yml", "/docs/**", "book.toml"]
|
exclude = ["/.travis/**", ".travis.yml", "/docs/**", "book.toml"]
|
||||||
description = "A library for merging bookmark trees."
|
description = "A library for merging bookmark trees."
|
||||||
|
|
|
@ -1528,47 +1528,44 @@ impl<'t, D: Driver, A: AbortSignal> Merger<'t, D, A> {
|
||||||
for (local_position, local_child_node) in local_parent_node.children().enumerate() {
|
for (local_position, local_child_node) in local_parent_node.children().enumerate() {
|
||||||
self.signal.err_if_aborted()?;
|
self.signal.err_if_aborted()?;
|
||||||
if local_child_node.is_built_in_root() {
|
if local_child_node.is_built_in_root() {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(local_child_content) = local_child_node.content() {
|
|
||||||
if let Some(remote_child_node) =
|
|
||||||
self.remote_tree.node_for_guid(&local_child_node.guid)
|
|
||||||
{
|
|
||||||
trace!(
|
|
||||||
self.driver,
|
|
||||||
"Not deduping local child {}; already exists remotely as {}",
|
|
||||||
local_child_node,
|
|
||||||
remote_child_node
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if self.remote_tree.is_deleted(&local_child_node.guid) {
|
|
||||||
trace!(
|
|
||||||
self.driver,
|
|
||||||
"Not deduping local child {}; deleted remotely",
|
|
||||||
local_child_node
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Store matching local children in an array, in case multiple children
|
|
||||||
// have the same dupe key (for example, a toolbar containing multiple
|
|
||||||
// empty folders, as in bug 1213369).
|
|
||||||
let dupe_key = match local_child_content {
|
|
||||||
Content::Bookmark { .. } | Content::Folder { .. } => {
|
|
||||||
DupeKey::WithoutPosition(local_child_content)
|
|
||||||
}
|
|
||||||
Content::Separator => {
|
|
||||||
DupeKey::WithPosition(local_child_content, local_position)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let local_nodes_for_key = dupe_key_to_local_nodes.entry(dupe_key).or_default();
|
|
||||||
local_nodes_for_key.push_back(local_child_node);
|
|
||||||
} else {
|
|
||||||
trace!(
|
trace!(
|
||||||
self.driver,
|
self.driver,
|
||||||
"Not deduping local child {}; already uploaded",
|
"Not deduping local built-in root {}",
|
||||||
local_child_node
|
local_child_node
|
||||||
);
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.remote_tree.mentions(&local_child_node.guid) {
|
||||||
|
trace!(
|
||||||
|
self.driver,
|
||||||
|
"Not deduping local child {}; already deleted or exists remotely",
|
||||||
|
local_child_node
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match local_child_node.content() {
|
||||||
|
Some(local_child_content) => {
|
||||||
|
// Store matching local children in an array, in case multiple children
|
||||||
|
// have the same dupe key (for example, a toolbar containing multiple
|
||||||
|
// empty folders, as in bug 1213369).
|
||||||
|
let dupe_key = match local_child_content {
|
||||||
|
Content::Bookmark { .. } | Content::Folder { .. } => {
|
||||||
|
DupeKey::WithoutPosition(local_child_content)
|
||||||
|
}
|
||||||
|
Content::Separator => {
|
||||||
|
DupeKey::WithPosition(local_child_content, local_position)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let local_nodes_for_key = dupe_key_to_local_nodes.entry(dupe_key).or_default();
|
||||||
|
local_nodes_for_key.push_back(local_child_node);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
trace!(
|
||||||
|
self.driver,
|
||||||
|
"Not deduping local child {} without content info",
|
||||||
|
local_child_node
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1577,6 +1574,22 @@ impl<'t, D: Driver, A: AbortSignal> Merger<'t, D, A> {
|
||||||
|
|
||||||
for (remote_position, remote_child_node) in remote_parent_node.children().enumerate() {
|
for (remote_position, remote_child_node) in remote_parent_node.children().enumerate() {
|
||||||
self.signal.err_if_aborted()?;
|
self.signal.err_if_aborted()?;
|
||||||
|
if remote_child_node.is_built_in_root() {
|
||||||
|
trace!(
|
||||||
|
self.driver,
|
||||||
|
"Not deduping remote built-in root {}",
|
||||||
|
remote_child_node
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.local_tree.mentions(&remote_child_node.guid) {
|
||||||
|
trace!(
|
||||||
|
self.driver,
|
||||||
|
"Not deduping remote child {}; already deleted or exists locally",
|
||||||
|
remote_child_node
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if remote_to_local.contains_key(&remote_child_node.guid) {
|
if remote_to_local.contains_key(&remote_child_node.guid) {
|
||||||
trace!(
|
trace!(
|
||||||
self.driver,
|
self.driver,
|
||||||
|
@ -1588,47 +1601,52 @@ impl<'t, D: Driver, A: AbortSignal> Merger<'t, D, A> {
|
||||||
// Note that we don't need to check if the remote node is deleted
|
// Note that we don't need to check if the remote node is deleted
|
||||||
// locally, because it wouldn't have local content entries if it
|
// locally, because it wouldn't have local content entries if it
|
||||||
// were.
|
// were.
|
||||||
if let Some(remote_child_content) = remote_child_node.content() {
|
match remote_child_node.content() {
|
||||||
let dupe_key = match remote_child_content {
|
Some(remote_child_content) => {
|
||||||
Content::Bookmark { .. } | Content::Folder { .. } => {
|
let dupe_key = match remote_child_content {
|
||||||
DupeKey::WithoutPosition(remote_child_content)
|
Content::Bookmark { .. } | Content::Folder { .. } => {
|
||||||
}
|
DupeKey::WithoutPosition(remote_child_content)
|
||||||
Content::Separator => {
|
}
|
||||||
DupeKey::WithPosition(remote_child_content, remote_position)
|
Content::Separator => {
|
||||||
}
|
DupeKey::WithPosition(remote_child_content, remote_position)
|
||||||
};
|
}
|
||||||
if let Some(local_nodes_for_key) = dupe_key_to_local_nodes.get_mut(&dupe_key) {
|
};
|
||||||
if let Some(local_child_node) = local_nodes_for_key.pop_front() {
|
if let Some(local_nodes_for_key) = dupe_key_to_local_nodes.get_mut(&dupe_key) {
|
||||||
trace!(
|
if let Some(local_child_node) = local_nodes_for_key.pop_front() {
|
||||||
self.driver,
|
trace!(
|
||||||
"Deduping local child {} to remote child {}",
|
self.driver,
|
||||||
local_child_node,
|
"Deduping local child {} to remote child {}",
|
||||||
remote_child_node
|
local_child_node,
|
||||||
);
|
remote_child_node
|
||||||
local_to_remote.insert(local_child_node.guid.clone(), remote_child_node);
|
);
|
||||||
remote_to_local.insert(remote_child_node.guid.clone(), local_child_node);
|
local_to_remote
|
||||||
|
.insert(local_child_node.guid.clone(), remote_child_node);
|
||||||
|
remote_to_local
|
||||||
|
.insert(remote_child_node.guid.clone(), local_child_node);
|
||||||
|
} else {
|
||||||
|
trace!(
|
||||||
|
self.driver,
|
||||||
|
"Not deduping remote child {}; no remaining local content matches",
|
||||||
|
remote_child_node
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!(
|
trace!(
|
||||||
self.driver,
|
self.driver,
|
||||||
"Not deduping remote child {}; no remaining local content matches",
|
"Not deduping remote child {}; no local content matches",
|
||||||
remote_child_node
|
remote_child_node
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
None => {
|
||||||
trace!(
|
trace!(
|
||||||
self.driver,
|
self.driver,
|
||||||
"Not deduping remote child {}; no local content matches",
|
"Not deduping remote child {} without content info",
|
||||||
remote_child_node
|
remote_child_node
|
||||||
);
|
);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
trace!(
|
|
||||||
self.driver,
|
|
||||||
"Not deduping remote child {}; already merged",
|
|
||||||
remote_child_node
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ impl TryFrom<Node> for Builder {
|
||||||
_ => return Err(err),
|
_ => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.mutate(&guid).by_structure(&parent_guid)?;
|
b.parent_for(&guid).by_structure(&parent_guid)?;
|
||||||
for child in node.children {
|
for child in node.children {
|
||||||
inflate(b, &guid, child)?;
|
inflate(b, &guid, child)?;
|
||||||
}
|
}
|
||||||
|
@ -1323,6 +1323,82 @@ fn newer_move_to_deleted() {
|
||||||
assert_eq!(merged_root.counts(), &expected_telem);
|
assert_eq!(merged_root.counts(), &expected_telem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deduping_multiple_candidates() {
|
||||||
|
before_each();
|
||||||
|
|
||||||
|
let mut local_tree_builder = Builder::try_from(nodes!({
|
||||||
|
("menu________", Folder[needs_merge = true, age = 5], {
|
||||||
|
("folderAAAAA1", Folder[needs_merge = true, age = 5]),
|
||||||
|
("folderAAAAA2", Folder[needs_merge = true, age = 5])
|
||||||
|
}),
|
||||||
|
("toolbar_____", Folder[needs_merge = true], {
|
||||||
|
("folderBBBBB1", Folder[needs_merge = true])
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
local_tree_builder
|
||||||
|
.mutate(&"folderAAAAA1".into())
|
||||||
|
.content(Content::Folder { title: "A".into() });
|
||||||
|
local_tree_builder
|
||||||
|
.mutate(&"folderAAAAA2".into())
|
||||||
|
.content(Content::Folder { title: "A".into() });
|
||||||
|
local_tree_builder
|
||||||
|
.mutate(&"folderBBBBB1".into())
|
||||||
|
.content(Content::Folder { title: "B".into() });
|
||||||
|
let local_tree = local_tree_builder.into_tree().unwrap();
|
||||||
|
|
||||||
|
let mut remote_tree_builder = Builder::try_from(nodes!({
|
||||||
|
("menu________", Folder[needs_merge = true], {
|
||||||
|
("folderAAAAA1", Folder[needs_merge = true])
|
||||||
|
}),
|
||||||
|
("toolbar_____", Folder[needs_merge = true, age = 5], {
|
||||||
|
("folderBBBBB1", Folder[needs_merge = true, age = 5]),
|
||||||
|
("folderBBBBB2", Folder[needs_merge = true, age = 5])
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
remote_tree_builder
|
||||||
|
.mutate(&"folderAAAAA1".into())
|
||||||
|
.content(Content::Folder { title: "A".into() });
|
||||||
|
remote_tree_builder
|
||||||
|
.mutate(&"folderBBBBB1".into())
|
||||||
|
.content(Content::Folder { title: "B".into() });
|
||||||
|
remote_tree_builder
|
||||||
|
.mutate(&"folderBBBBB2".into())
|
||||||
|
.content(Content::Folder { title: "B".into() });
|
||||||
|
let remote_tree = remote_tree_builder.into_tree().unwrap();
|
||||||
|
|
||||||
|
let merger = Merger::new(&local_tree, &remote_tree);
|
||||||
|
let merged_root = merger.merge().unwrap();
|
||||||
|
|
||||||
|
let expected_tree = merged_nodes!({
|
||||||
|
("menu________", LocalWithNewLocalStructure, {
|
||||||
|
("folderAAAAA1", Remote),
|
||||||
|
("folderAAAAA2", Local)
|
||||||
|
}),
|
||||||
|
("toolbar_____", LocalWithNewLocalStructure, {
|
||||||
|
("folderBBBBB1", Local),
|
||||||
|
("folderBBBBB2", Remote)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let expected_telem = StructureCounts {
|
||||||
|
remote_revives: 0,
|
||||||
|
local_deletes: 0,
|
||||||
|
local_revives: 0,
|
||||||
|
remote_deletes: 0,
|
||||||
|
dupes: 0,
|
||||||
|
merged_nodes: 6,
|
||||||
|
merged_deletions: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(&expected_tree, merged_root.node());
|
||||||
|
|
||||||
|
assert_eq!(merged_root.deletions().count(), 0);
|
||||||
|
|
||||||
|
assert_eq!(merged_root.counts(), &expected_telem);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deduping_local_newer() {
|
fn deduping_local_newer() {
|
||||||
before_each();
|
before_each();
|
||||||
|
|
|
@ -499,52 +499,10 @@ impl<'b> ItemBuilder<'b> {
|
||||||
b.by_parent_guid(parent_guid)
|
b.by_parent_guid(parent_guid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Records a `parent_guid` from a valid tree structure. This is for
|
#[inline]
|
||||||
/// callers who already know their structure is consistent, like
|
|
||||||
/// `Store::fetch_local_tree()` on Desktop, and
|
|
||||||
/// `std::convert::TryInto<Tree>` in the tests.
|
|
||||||
///
|
|
||||||
/// Both the item and `parent_guid` must exist, and the `parent_guid` must
|
|
||||||
/// refer to a folder.
|
|
||||||
///
|
|
||||||
/// `by_structure(parent_guid)` is logically the same as:
|
|
||||||
///
|
|
||||||
/// ```no_run
|
|
||||||
/// # use dogear::{Item, Kind, Result, ROOT_GUID, Tree};
|
|
||||||
/// # fn main() -> Result<()> {
|
|
||||||
/// # let mut builder = Tree::with_root(Item::new(ROOT_GUID, Kind::Folder));
|
|
||||||
/// # let child_guid = "bookmarkAAAA".into();
|
|
||||||
/// # let parent_guid = "folderAAAAAA".into();
|
|
||||||
/// builder.parent_for(&child_guid)
|
|
||||||
/// .by_children(&parent_guid)?
|
|
||||||
/// .parent_for(&child_guid)
|
|
||||||
/// .by_parent_guid(parent_guid)?;
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ...But more convenient. It's also more efficient, because it avoids
|
|
||||||
/// multiple lookups for the item and parent, as well as an extra heap
|
|
||||||
/// allocation to store the parents.
|
|
||||||
pub fn by_structure(self, parent_guid: &Guid) -> Result<&'b mut Builder> {
|
pub fn by_structure(self, parent_guid: &Guid) -> Result<&'b mut Builder> {
|
||||||
let parent_index = match self.0.entry_index_by_guid.get(parent_guid) {
|
let b = ParentBuilder(self.0, BuilderEntryChild::Exists(self.1));
|
||||||
Some(&parent_index) if self.0.entries[parent_index].item.is_folder() => parent_index,
|
b.by_structure(parent_guid)
|
||||||
_ => {
|
|
||||||
return Err(ErrorKind::InvalidParent(
|
|
||||||
self.0.entries[self.1].item.guid.clone(),
|
|
||||||
parent_guid.clone(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.0.entries[self.1].parents_by(&[
|
|
||||||
BuilderParentBy::Children(parent_index),
|
|
||||||
BuilderParentBy::KnownItem(parent_index),
|
|
||||||
])?;
|
|
||||||
self.0.entries[parent_index]
|
|
||||||
.children
|
|
||||||
.push(BuilderEntryChild::Exists(self.1));
|
|
||||||
Ok(self.0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,6 +551,56 @@ impl<'b> ParentBuilder<'b> {
|
||||||
}
|
}
|
||||||
Ok(self.0)
|
Ok(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Records a `parent_guid` from a valid tree structure. This is for
|
||||||
|
/// callers who already know their structure is consistent, like
|
||||||
|
/// `Store::fetch_local_tree()` on Desktop, and
|
||||||
|
/// `std::convert::TryInto<Tree>` in the tests.
|
||||||
|
///
|
||||||
|
/// Both the item and `parent_guid` must exist, and the `parent_guid` must
|
||||||
|
/// refer to a folder.
|
||||||
|
///
|
||||||
|
/// `by_structure(parent_guid)` is logically the same as:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// # use dogear::{Item, Kind, Result, ROOT_GUID, Tree};
|
||||||
|
/// # fn main() -> Result<()> {
|
||||||
|
/// # let mut builder = Tree::with_root(Item::new(ROOT_GUID, Kind::Folder));
|
||||||
|
/// # let child_guid = "bookmarkAAAA".into();
|
||||||
|
/// # let parent_guid = "folderAAAAAA".into();
|
||||||
|
/// builder.parent_for(&child_guid)
|
||||||
|
/// .by_children(&parent_guid)?
|
||||||
|
/// .parent_for(&child_guid)
|
||||||
|
/// .by_parent_guid(parent_guid)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ...But more convenient. It's also more efficient, because it avoids
|
||||||
|
/// multiple lookups for the item and parent, as well as an extra heap
|
||||||
|
/// allocation to store the parents.
|
||||||
|
pub fn by_structure(self, parent_guid: &Guid) -> Result<&'b mut Builder> {
|
||||||
|
let parent_index = match self.0.entry_index_by_guid.get(parent_guid) {
|
||||||
|
Some(&parent_index) if self.0.entries[parent_index].item.is_folder() => parent_index,
|
||||||
|
_ => {
|
||||||
|
let child_guid = match &self.1 {
|
||||||
|
BuilderEntryChild::Exists(index) => &self.0.entries[*index].item.guid,
|
||||||
|
BuilderEntryChild::Missing(guid) => guid,
|
||||||
|
};
|
||||||
|
return Err(
|
||||||
|
ErrorKind::InvalidParent(child_guid.clone(), parent_guid.clone()).into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let BuilderEntryChild::Exists(child_index) = &self.1 {
|
||||||
|
self.0.entries[*child_index].parents_by(&[
|
||||||
|
BuilderParentBy::Children(parent_index),
|
||||||
|
BuilderParentBy::KnownItem(parent_index),
|
||||||
|
])?;
|
||||||
|
}
|
||||||
|
self.0.entries[parent_index].children.push(self.1);
|
||||||
|
Ok(self.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entry wraps a tree item with references to its parents and children,
|
/// An entry wraps a tree item with references to its parents and children,
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче