1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/css/ActiveStyleSheets.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/RuleSet.h"
#include "core/css/resolver/ScopedStyleResolver.h"
#include "core/dom/ContainerNode.h"
#include "core/dom/StyleChangeReason.h"
#include "core/dom/StyleEngine.h"
namespace blink {
ActiveSheetsChange compareActiveStyleSheets(
const ActiveStyleSheetVector& oldStyleSheets,
const ActiveStyleSheetVector& newStyleSheets,
HeapHashSet<Member<RuleSet>>& changedRuleSets) {
unsigned newStyleSheetCount = newStyleSheets.size();
unsigned oldStyleSheetCount = oldStyleSheets.size();
unsigned minCount = std::min(newStyleSheetCount, oldStyleSheetCount);
unsigned index = 0;
// Walk the common prefix of stylesheets. If the stylesheet rules were
// modified since last time, add them to the list of changed rulesets.
for (; index < minCount &&
newStyleSheets[index].first == oldStyleSheets[index].first;
index++) {
if (newStyleSheets[index].second == oldStyleSheets[index].second)
continue;
if (newStyleSheets[index].second)
changedRuleSets.add(newStyleSheets[index].second);
if (oldStyleSheets[index].second)
changedRuleSets.add(oldStyleSheets[index].second);
}
if (index == oldStyleSheetCount) {
// The old stylesheet vector is a prefix of the new vector in terms of
// StyleSheets. If none of the RuleSets changed, we only need to add the new
// sheets to the ScopedStyleResolver (ActiveSheetsAppended).
bool ruleSetsChangedInCommonPrefix = !changedRuleSets.isEmpty();
for (; index < newStyleSheetCount; index++) {
if (newStyleSheets[index].second)
changedRuleSets.add(newStyleSheets[index].second);
}
if (ruleSetsChangedInCommonPrefix)
return ActiveSheetsChanged;
if (changedRuleSets.isEmpty())
return NoActiveSheetsChanged;
return ActiveSheetsAppended;
}
if (index == newStyleSheetCount) {
// Sheets removed from the end.
for (; index < oldStyleSheetCount; index++) {
if (oldStyleSheets[index].second)
changedRuleSets.add(oldStyleSheets[index].second);
}
return changedRuleSets.isEmpty() ? NoActiveSheetsChanged
: ActiveSheetsChanged;
}
DCHECK(index < oldStyleSheetCount && index < newStyleSheetCount);
// Both the new and old active stylesheet vectors have stylesheets following
// the common prefix. Figure out which were added or removed by sorting the
// merged vector of old and new sheets.
ActiveStyleSheetVector mergedSorted;
mergedSorted.reserveCapacity(oldStyleSheetCount + newStyleSheetCount -
2 * index);
mergedSorted.appendRange(oldStyleSheets.begin() + index,
oldStyleSheets.end());
mergedSorted.appendRange(newStyleSheets.begin() + index,
newStyleSheets.end());
std::sort(mergedSorted.begin(), mergedSorted.end());
auto mergedIterator = mergedSorted.begin();
while (mergedIterator != mergedSorted.end()) {
const auto& sheet1 = *mergedIterator++;
if (mergedIterator == mergedSorted.end() ||
(*mergedIterator).first != sheet1.first) {
// Sheet either removed or inserted.
if (sheet1.second)
changedRuleSets.add(sheet1.second);
continue;
}
// Sheet present in both old and new.
const auto& sheet2 = *mergedIterator++;
if (sheet1.second == sheet2.second)
continue;
// Active rules for the given stylesheet changed.
// DOM, CSSOM, or media query changes.
if (sheet1.second)
changedRuleSets.add(sheet1.second);
if (sheet2.second)
changedRuleSets.add(sheet2.second);
}
return changedRuleSets.isEmpty() ? NoActiveSheetsChanged
: ActiveSheetsChanged;
}
} // namespace blink
|