mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 09:45:41 +00:00
Bug 1611236 - Optimize adoptedStyleSheets append case r=emilio
- Generalize enumeration over unique sheets to take any array of sheets. - Add check if the new adoptedStyleSheets only appends sheets. - Handle append case for new adoptedStyleSheets. - Add WPT test case for duplicate sheets in the ShadowRoot. - Add WPT test cases for appending sheets. Differential Revision: https://phabricator.services.mozilla.com/D64686 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
f1666a5ee9
commit
ae085e705a
@ -127,14 +127,50 @@ void DocumentOrShadowRoot::SetAdoptedStyleSheets(
|
||||
auto* shadow = ShadowRoot::FromNode(AsNode());
|
||||
MOZ_ASSERT((mKind == Kind::ShadowRoot) == !!shadow);
|
||||
|
||||
ClearAdoptedStyleSheets();
|
||||
StyleSheetSet set(aAdoptedStyleSheets.Length());
|
||||
size_t commonPrefix = 0;
|
||||
|
||||
// Find the index at which the new array differs from the old array.
|
||||
// We don't want to do extra work for the sheets that both arrays have.
|
||||
size_t min =
|
||||
std::min(aAdoptedStyleSheets.Length(), mAdoptedStyleSheets.Length());
|
||||
for (size_t i = 0; i < min; ++i) {
|
||||
if (aAdoptedStyleSheets[i] != mAdoptedStyleSheets[i]) {
|
||||
break;
|
||||
}
|
||||
++commonPrefix;
|
||||
set.PutEntry(mAdoptedStyleSheets[i]);
|
||||
}
|
||||
|
||||
// Try to truncate the sheets to a common prefix.
|
||||
// If the prefix contains duplicates of sheets that we are removing,
|
||||
// we are just going to re-build everything from scratch.
|
||||
if (commonPrefix != mAdoptedStyleSheets.Length()) {
|
||||
StyleSheetSet removedSet(mAdoptedStyleSheets.Length() - commonPrefix);
|
||||
for (size_t i = mAdoptedStyleSheets.Length(); i != commonPrefix; --i) {
|
||||
RefPtr<StyleSheet> sheetToRemove = mAdoptedStyleSheets.PopLastElement();
|
||||
if (MOZ_UNLIKELY(set.Contains(sheetToRemove))) {
|
||||
// Fixing duplicate sheets would require insertions/removals from the
|
||||
// style set. We may as well just rebuild the whole thing from scratch.
|
||||
set.Clear();
|
||||
// Note that setting this to zero means we'll continue the loop until
|
||||
// all the sheets are cleared.
|
||||
commonPrefix = 0;
|
||||
}
|
||||
if (MOZ_LIKELY(removedSet.EnsureInserted(sheetToRemove))) {
|
||||
RemoveSheetFromStylesIfApplicable(*sheetToRemove);
|
||||
sheetToRemove->RemoveAdopter(*this);
|
||||
}
|
||||
}
|
||||
mAdoptedStyleSheets.TruncateLength(commonPrefix);
|
||||
}
|
||||
|
||||
// 3. Set the adopted style sheets to the new sheets
|
||||
mAdoptedStyleSheets.SetCapacity(aAdoptedStyleSheets.Length());
|
||||
|
||||
AdoptedStyleSheetSet set(aAdoptedStyleSheets.Length());
|
||||
for (const OwningNonNull<StyleSheet>& sheet : aAdoptedStyleSheets) {
|
||||
if (MOZ_UNLIKELY(!set.EnsureInserted(sheet.get()))) {
|
||||
// Only add sheets that are not already in the common prefix.
|
||||
for (const auto& sheet : MakeSpan(aAdoptedStyleSheets).From(commonPrefix)) {
|
||||
if (MOZ_UNLIKELY(!set.EnsureInserted(sheet))) {
|
||||
// The idea is that this case is rare, so we pay the price of removing the
|
||||
// old sheet from the styles and append it later rather than the other way
|
||||
// around.
|
||||
|
@ -231,7 +231,7 @@ class DocumentOrShadowRoot {
|
||||
// with them.
|
||||
template <typename Callback>
|
||||
void EnumerateUniqueAdoptedStyleSheetsBackToFront(Callback aCallback) {
|
||||
AdoptedStyleSheetSet set(mAdoptedStyleSheets.Length());
|
||||
StyleSheetSet set(mAdoptedStyleSheets.Length());
|
||||
for (StyleSheet* sheet : Reversed(mAdoptedStyleSheets)) {
|
||||
if (MOZ_UNLIKELY(!set.EnsureInserted(sheet))) {
|
||||
continue;
|
||||
@ -241,7 +241,7 @@ class DocumentOrShadowRoot {
|
||||
}
|
||||
|
||||
protected:
|
||||
using AdoptedStyleSheetSet = nsTHashtable<nsPtrHashKey<const StyleSheet>>;
|
||||
using StyleSheetSet = nsTHashtable<nsPtrHashKey<const StyleSheet>>;
|
||||
void RemoveSheetFromStylesIfApplicable(StyleSheet&);
|
||||
void ClearAdoptedStyleSheets();
|
||||
|
||||
|
@ -4,17 +4,81 @@
|
||||
<link rel="help" href="https://wicg.github.io/construct-stylesheets/">
|
||||
<script src = '/resources/testharness.js'></script>
|
||||
<script src = '/resources/testharnessreport.js'></script>
|
||||
<div></div>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
test(function() {
|
||||
let sheets = [];
|
||||
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
function attachShadowDiv(host) {
|
||||
const shadowRoot = host.attachShadow({mode: 'open'});
|
||||
const shadowDiv = document.createElement("div");
|
||||
shadowRoot.appendChild(shadowDiv);
|
||||
return shadowDiv;
|
||||
}
|
||||
|
||||
function blueSheetsWithIncreasingZIndex(n) {
|
||||
let sheets = [];
|
||||
for (let i = 0; i < n; ++i) {
|
||||
sheets.push(new CSSStyleSheet());
|
||||
sheets[i].replaceSync("div { z-index: " + i + " }");
|
||||
sheets[i].replaceSync("div { z-index: " + i + "; color: blue; }");
|
||||
}
|
||||
return sheets;
|
||||
}
|
||||
|
||||
let sheets = [];
|
||||
|
||||
test(function() {
|
||||
sheets = blueSheetsWithIncreasingZIndex(2);
|
||||
|
||||
document.adoptedStyleSheets = [sheets[1], sheets[0], sheets[1]];
|
||||
assert_equals(getComputedStyle(document.querySelector("div")).zIndex, "1", "duplicate stylesheet should take right position in the cascade");
|
||||
});
|
||||
|
||||
document.adoptedStyleSheets = [];
|
||||
}, "Duplicate stylesheets have the right cascade position in the Document");
|
||||
|
||||
test(function() {
|
||||
sheets = blueSheetsWithIncreasingZIndex(2);
|
||||
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync("div { color: red; }");
|
||||
|
||||
document.adoptedStyleSheets = [sheets[1], sheets[0]];
|
||||
assert_equals(getComputedStyle(document.querySelector("div")).zIndex, "0", "backmost stylesheet should take precedence");
|
||||
assert_equals(getComputedStyle(document.querySelector("div")).color, "rgb(0, 0, 255)", "backmost stylesheet should take precedence");
|
||||
|
||||
document.adoptedStyleSheets = [sheets[1], sheets[0], sheets[1], sheet];
|
||||
assert_equals(getComputedStyle(document.querySelector("div")).zIndex, "1", "duplicate stylesheet should take the right position in the cascade");
|
||||
assert_equals(getComputedStyle(document.querySelector("div")).color, "rgb(255, 0, 0)", "backmost stylesheet should take precedence");
|
||||
|
||||
document.adoptedStyleSheets = [];
|
||||
}, "Appending duplicate stylesheets yields the correct cascade position in the Document");
|
||||
|
||||
test(function() {
|
||||
sheets = blueSheetsWithIncreasingZIndex(2);
|
||||
|
||||
const span = document.createElement("span");
|
||||
target.appendChild(span);
|
||||
attachShadowDiv(span);
|
||||
|
||||
span.shadowRoot.adoptedStyleSheets = [sheets[1], sheets[0], sheets[1]];
|
||||
assert_equals(getComputedStyle(span.shadowRoot.querySelector("div")).zIndex, "1", "duplicate stylesheet should take right position in the cascade");
|
||||
}, "Duplicate stylesheets have the right cascade position in the ShadowRoot");
|
||||
|
||||
test(function() {
|
||||
sheets = blueSheetsWithIncreasingZIndex(2);
|
||||
|
||||
const sheet = new CSSStyleSheet();
|
||||
sheet.replaceSync("div { color: red; }");
|
||||
|
||||
const span = document.createElement("span");
|
||||
target.appendChild(span);
|
||||
attachShadowDiv(span);
|
||||
|
||||
span.shadowRoot.adoptedStyleSheets = [sheets[1], sheets[0]];
|
||||
assert_equals(getComputedStyle(span.shadowRoot.querySelector("div")).zIndex, "0", "backmost stylesheet should take precedence");
|
||||
assert_equals(getComputedStyle(span.shadowRoot.querySelector("div")).color, "rgb(0, 0, 255)", "backmost stylesheet should take precedence");
|
||||
|
||||
span.shadowRoot.adoptedStyleSheets = [sheets[1], sheets[0], sheets[1], sheet];
|
||||
assert_equals(getComputedStyle(span.shadowRoot.querySelector("div")).zIndex, "1", "duplicate stylesheet should take right position in the cascade");
|
||||
assert_equals(getComputedStyle(span.shadowRoot.querySelector("div")).color, "rgb(255, 0, 0)", "backmost stylesheet should take precedence");
|
||||
}, "Appending duplicate stylesheets yields the correct cascade position in the ShadowRoot");
|
||||
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user