--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -272,16 +272,18 @@
#include "nsISpeculativeConnect.h"
#include "mozilla/MediaManager.h"
#ifdef MOZ_WEBRTC
#include "IPeerConnection.h"
#endif // MOZ_WEBRTC
#include "nsIURIClassifier.h"
+#include "mozilla/DocumentStyleRootIterator.h"
+#include "mozilla/ServoRestyleManager.h"
using namespace mozilla;
using namespace mozilla::dom;
typedef nsTArray<Link*> LinkArray;
static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
static LazyLogModule gCspPRLog("CSP");
@@ -1345,16 +1347,17 @@ nsIDocument::nsIDocument()
mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mPostedFlushUserFontSet(false),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false),
mIsTopLevelContentDocument(false),
mIsContentDocument(false),
+ mMightHaveStaleServoData(false),
mIsScopedStyleEnabled(eScopedStyle_Unknown),
mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
mStyleBackendType(StyleBackendType::None),
#ifdef MOZILLA_INTERNAL_API
mVisibilityState(dom::VisibilityState::Hidden),
#else
mDummy(0),
@@ -3878,16 +3881,21 @@ nsDocument::CreateShell(nsPresContext* a
StyleSetHandle aStyleSet)
{
NS_ASSERTION(!mPresShell, "We have a presshell already!");
NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
FillStyleSet(aStyleSet);
+ if (aStyleSet->IsServo()) {
+ // Ensure we start with no stale data in the tree.
+ ClearStaleServoDataFromDocument();
+ }
+
RefPtr<PresShell> shell = new PresShell;
shell->Init(this, aContext, aViewManager, aStyleSet);
// Note: we don't hold a ref to the shell (it holds a ref to us)
mPresShell = shell;
// Make sure to never paint if we belong to an invisible DocShell.
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
@@ -3997,16 +4005,22 @@ nsDocument::DeleteShell()
// Now that we no longer have a shell, we need to forget about any FontFace
// objects for @font-face rules that came from the style set.
RebuildUserFontSet();
nsIPresShell* oldShell = mPresShell;
mPresShell = nullptr;
UpdateFrameRequestCallbackSchedulingState(oldShell);
mStyleSetFilled = false;
+
+ // Record that the tree might have stale Servo element data in it
+ // that would need to be cleared if we ever get a new pres shell
+ // or if we call ServoStyleSet style resolving functions on
+ // elements in the document.
+ mMightHaveStaleServoData = true;
}
static void
SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
{
SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
NS_RELEASE(e->mKey);
@@ -13524,8 +13538,22 @@ nsIDocument::IsScopedStyleEnabled()
mIsScopedStyleEnabled = nsContentUtils::IsChromeDoc(this) ||
IsAboutReader(mDocumentURI) ||
nsContentUtils::IsScopedStylePrefEnabled()
? eScopedStyle_Enabled
: eScopedStyle_Disabled;
}
return mIsScopedStyleEnabled == eScopedStyle_Enabled;
}
+
+void
+nsIDocument::ClearStaleServoDataFromDocument()
+{
+ if (!mMightHaveStaleServoData) {
+ return;
+ }
+
+ DocumentStyleRootIterator iter(this);
+ while (Element* root = iter.GetNextStyleRoot()) {
+ ServoRestyleManager::ClearServoDataFromSubtree(root);
+ }
+ mMightHaveStaleServoData = false;
+}
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -855,16 +855,21 @@ public:
mozilla::StyleSetHandle aStyleSet) = 0;
virtual void DeleteShell() = 0;
nsIPresShell* GetShell() const
{
return GetBFCacheEntry() ? nullptr : mPresShell;
}
+ bool HasShellOrBFCacheEntry() const
+ {
+ return mPresShell || mBFCacheEntry;
+ }
+
// Instead using this method, what you probably want is
// RemoveFromBFCacheSync() as we do in MessagePort and BroadcastChannel.
void DisallowBFCaching()
{
NS_ASSERTION(!mBFCacheEntry, "We're already in the bfcache!");
mBFCacheDisallowed = true;
}
@@ -1697,16 +1702,28 @@ public:
bool IsContentDocument() const { return mIsContentDocument; }
void SetIsContentDocument(bool aIsContentDocument)
{
mIsContentDocument = aIsContentDocument;
}
/**
+ * Checks if this document has no pres shell, and if so, clears any Servo
+ * element data stored on Elements in the document.
+ */
+ void ClearStaleServoDataFromDocument();
+
+ /**
+ * Returns true if there may be Servo element data on Elements in the document
+ * that were created for a pres shell that no longer exists.
+ */
+ bool MightHaveStaleServoData() const { return mMightHaveStaleServoData; }
+
+ /**
* Create an element with the specified name, prefix and namespace ID.
* Returns null if element name parsing failed.
*/
virtual already_AddRefed<Element> CreateElem(const nsAString& aName,
nsIAtom* aPrefix,
int32_t aNamespaceID,
const nsAString* aIs = nullptr) = 0;
@@ -3280,16 +3297,20 @@ protected:
// This should generally be updated only via
// UpdateFrameRequestCallbackSchedulingState.
bool mFrameRequestCallbacksScheduled : 1;
bool mIsTopLevelContentDocument : 1;
bool mIsContentDocument : 1;
+ // True if there may be Servo element data on Elements in the document that
+ // were created for a pres shell that no longer exists.
+ bool mMightHaveStaleServoData : 1;
+
// Whether <style scoped> support is enabled in this document.
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
unsigned int mIsScopedStyleEnabled : 2;
// Compatibility mode
nsCompatibility mCompatMode;
// Our readyState
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2973,16 +2973,21 @@ nsGenericHTMLElement::NewURIFromString(c
}
return NS_OK;
}
static bool
IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
{
+ // Let's pretend everything is display:none if we're in the bfcache.
+ if (aElement->OwnerDoc()->GetBFCacheEntry()) {
+ return true;
+ }
+
AutoTArray<Element*, 10> elementsToCheck;
// Style and layout work on the flattened tree, so this is what we need to
// check in order to figure out whether we're in a display: none subtree.
for (Element* e = aElement; e; e = e->GetFlattenedTreeParentElement()) {
if (e->GetPrimaryFrame()) {
// e definitely isn't display:none and doesn't have a display:none
// ancestor.
break;
@@ -2993,17 +2998,20 @@ IsOrHasAncestorWithDisplayNone(Element*
if (elementsToCheck.IsEmpty()) {
return false;
}
StyleSetHandle styleSet = aPresShell->StyleSet();
RefPtr<nsStyleContext> sc;
for (auto* element : Reversed(elementsToCheck)) {
if (sc) {
- sc = styleSet->ResolveStyleFor(element, sc, LazyComputeBehavior::Assert);
+ // Call ResolveCleanStyleFor to protect against stale element data in the
+ // tree when styled by Servo.
+ sc = styleSet->ResolveCleanStyleFor(element, sc,
+ LazyComputeBehavior::Assert);
} else {
sc = nsComputedDOMStyle::GetStyleContextNoFlush(element,
nullptr, aPresShell);
}
if (sc->StyleDisplay()->mDisplay == StyleDisplay::None) {
return true;
}
}
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -534,17 +534,18 @@ SERVO_BINDING_FUNC(Servo_HasAuthorSpecif
//
// The tree must be in a consistent state such that a normal traversal could be
// performed, and this function maintains that invariant.
SERVO_BINDING_FUNC(Servo_ResolveStyleLazily, ServoStyleContextStrong,
RawGeckoElementBorrowed element,
mozilla::CSSPseudoElementType pseudo_type,
mozilla::StyleRuleInclusion rule_inclusion,
const mozilla::ServoElementSnapshotTable* snapshots,
- RawServoStyleSetBorrowed set)
+ RawServoStyleSetBorrowed set,
+ bool ignore_existing_styles)
// Reparents style to the new parents.
SERVO_BINDING_FUNC(Servo_ReparentStyle, ServoStyleContextStrong,
ServoStyleContextBorrowed style_to_reparent,
ServoStyleContextBorrowed parent_style,
ServoStyleContextBorrowed parent_style_ignoring_first_line,
ServoStyleContextBorrowed layout_parent_style,
// element is null if there is no content node involved, or
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -180,16 +180,59 @@ ServoStyleSet::ResolveStyleFor(Element*
PreTraverseSync();
return ResolveStyleLazily(
aElement, CSSPseudoElementType::NotPseudo, nullptr, aParentContext);
}
return ResolveServoStyle(aElement, ServoTraversalFlags::Empty);
}
+/**
+ * Clears any stale Servo element data that might existing in the specified
+ * element's document. Upon destruction, asserts that the element and all
+ * its ancestors still have no element data, if the document has no pres shell.
+ */
+class MOZ_STACK_CLASS AutoClearStaleData
+{
+public:
+ explicit AutoClearStaleData(Element* aElement)
+ : mElement(aElement)
+ {
+ aElement->OwnerDoc()->ClearStaleServoDataFromDocument();
+ }
+
+ ~AutoClearStaleData()
+ {
+#ifdef DEBUG
+ // Assert that the element and its ancestors are all unstyled, if the
+ // document has no pres shell.
+ if (mElement->OwnerDoc()->HasShellOrBFCacheEntry()) {
+ return;
+ }
+ for (Element* e = mElement; e; e = e->GetParentElement()) {
+ MOZ_ASSERT(!e->HasServoData(), "expected element to be unstyled");
+ }
+#endif
+ }
+
+private:
+ Element* mElement;
+};
+
+already_AddRefed<ServoStyleContext>
+ServoStyleSet::ResolveCleanStyleFor(Element* aElement,
+ ServoStyleContext* aParentContext,
+ LazyComputeBehavior aMayCompute)
+{
+ // We don't handle ignoring existing element data for bfcached documents.
+ MOZ_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
+
+ AutoClearStaleData guard(aElement);
+ return ResolveStyleFor(aElement, aParentContext, aMayCompute);
+}
const ServoElementSnapshotTable&
ServoStyleSet::Snapshots()
{
return mPresContext->RestyleManager()->AsServo()->Snapshots();
}
void
@@ -426,30 +469,33 @@ ServoStyleSet::ResolvePseudoElementStyle
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveTransientStyle(Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
StyleRuleInclusion aRuleInclusion)
{
- RefPtr<ServoStyleContext> result =
- ResolveTransientServoStyle(aElement, aPseudoType, aPseudoTag, aRuleInclusion);
- return result.forget();
+ return ResolveTransientServoStyle(aElement, aPseudoType, aPseudoTag,
+ aRuleInclusion);
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveTransientServoStyle(
Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
StyleRuleInclusion aRuleInclusion)
{
+ bool ignoreExistingStyles = aElement->OwnerDoc()->GetBFCacheEntry();
+
+ AutoClearStaleData guard(aElement);
PreTraverseSync();
- return ResolveStyleLazily(aElement, aPseudoType, aPseudoTag, nullptr, aRuleInclusion);
+ return ResolveStyleLazily(aElement, aPseudoType, aPseudoTag, nullptr,
+ aRuleInclusion, ignoreExistingStyles);
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
ServoStyleContext* aParentContext)
{
MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
!nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
@@ -902,16 +948,21 @@ ServoStyleSet::GetKeyframesForName(const
}
nsTArray<ComputedKeyframeValues>
ServoStyleSet::GetComputedKeyframeValuesFor(
const nsTArray<Keyframe>& aKeyframes,
Element* aElement,
const ServoStyleContext* aContext)
{
+ // Servo_GetComputedKeyframeValues below won't handle ignoring existing
+ // element data for bfcached documents.
+ MOZ_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
+
+ AutoClearStaleData guard(aElement);
nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
// Construct each nsTArray<PropertyStyleAnimationValuePair> here.
result.AppendElements(aKeyframes.Length());
Servo_GetComputedKeyframeValues(&aKeyframes,
aElement,
aContext,
@@ -922,45 +973,60 @@ ServoStyleSet::GetComputedKeyframeValues
void
ServoStyleSet::GetAnimationValues(
RawServoDeclarationBlock* aDeclarations,
Element* aElement,
const ServoStyleContext* aStyleContext,
nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues)
{
+ // Servo_GetAnimationValues below won't handle ignoring existing element
+ // data for bfcached documents.
+ MOZ_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
+
+ AutoClearStaleData guard(aElement);
Servo_GetAnimationValues(aDeclarations,
aElement,
aStyleContext,
mRawSet.get(),
&aAnimationValues);
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::GetBaseContextForElement(
Element* aElement,
ServoStyleContext* aParentContext,
nsPresContext* aPresContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
const ServoStyleContext* aStyle)
{
+ MOZ_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry(),
+ "GetBaseContextForElement does not support documents in the "
+ "bfcache");
+
+ AutoClearStaleData guard(aElement);
return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
aElement,
aStyle,
&Snapshots(),
aPseudoType).Consume();
}
already_AddRefed<RawServoAnimationValue>
ServoStyleSet::ComputeAnimationValue(
Element* aElement,
RawServoDeclarationBlock* aDeclarations,
const ServoStyleContext* aContext)
{
+ // Servo_AnimationValue_Compute below won't handle ignoring existing element
+ // data for bfcached documents.
+ MOZ_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
+
+ AutoClearStaleData guard(aElement);
return Servo_AnimationValue_Compute(aElement,
aDeclarations,
aContext,
mRawSet.get()).Consume();
}
bool
ServoStyleSet::EnsureUniqueInnerOnCSSSheets()
@@ -1062,17 +1128,18 @@ ServoStyleSet::ClearNonInheritingStyleCo
}
}
already_AddRefed<ServoStyleContext>
ServoStyleSet::ResolveStyleLazily(Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
const ServoStyleContext* aParentContext,
- StyleRuleInclusion aRuleInclusion)
+ StyleRuleInclusion aRuleInclusion,
+ bool aIgnoreExistingStyles)
{
mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
MOZ_ASSERT(!StylistNeedsUpdate());
AutoSetInServoTraversal guard(this);
/**
* NB: This is needed because we process animations and transitions on the
@@ -1099,25 +1166,27 @@ ServoStyleSet::ResolveStyleLazily(Elemen
}
}
RefPtr<ServoStyleContext> computedValues =
Servo_ResolveStyleLazily(elementForStyleResolution,
pseudoTypeForStyleResolution,
aRuleInclusion,
&Snapshots(),
- mRawSet.get()).Consume();
+ mRawSet.get(),
+ aIgnoreExistingStyles).Consume();
if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
computedValues =
Servo_ResolveStyleLazily(elementForStyleResolution,
pseudoTypeForStyleResolution,
aRuleInclusion,
&Snapshots(),
- mRawSet.get()).Consume();
+ mRawSet.get(),
+ aIgnoreExistingStyles).Consume();
}
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
UpdateBodyTextColorIfNeeded(*aElement, *computedValues, *mPresContext);
}
return computedValues.forget();
}
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -130,16 +130,23 @@ public:
void BeginUpdate();
nsresult EndUpdate();
already_AddRefed<ServoStyleContext>
ResolveStyleFor(dom::Element* aElement,
ServoStyleContext* aParentContext,
LazyComputeBehavior aMayCompute);
+ // Same as ResolveStyleFor, but additionally ensures that any stale
+ // element data in the tree has been cleared before resolving style.
+ already_AddRefed<ServoStyleContext>
+ ResolveCleanStyleFor(dom::Element* aElement,
+ ServoStyleContext* aParentContext,
+ LazyComputeBehavior aMayCompute);
+
// Get a style context for a text node (which no rules will match).
//
// The returned style context will have nsCSSAnonBoxes::mozText as its pseudo.
//
// (Perhaps mozText should go away and we shouldn't even create style
// contexts for such content nodes, when text-combine-upright is not
// present. However, not doing any rule matching for them is a first step.)
already_AddRefed<ServoStyleContext>
@@ -189,16 +196,19 @@ public:
ResolveTransientStyle(dom::Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
StyleRuleInclusion aRules =
StyleRuleInclusion::All);
// Similar to ResolveTransientStyle() but doesn't update the context state
// Unlike ResolveServoStyle() this function calls PreTraverseSync().
+ //
+ // XXXheycam There's no longer any difference between ResolveTransientStyle
+ // and ResolveTransientServoStyle so we should merge them.
already_AddRefed<ServoStyleContext>
ResolveTransientServoStyle(dom::Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
StyleRuleInclusion aRules =
StyleRuleInclusion::All);
// Get a style context for an anonymous box. aPseudoTag is the pseudo-tag to
@@ -564,17 +574,18 @@ private:
void UpdateStylist();
already_AddRefed<ServoStyleContext>
ResolveStyleLazily(dom::Element* aElement,
CSSPseudoElementType aPseudoType,
nsIAtom* aPseudoTag,
const ServoStyleContext* aParentContext,
StyleRuleInclusion aRules =
- StyleRuleInclusion::All);
+ StyleRuleInclusion::All,
+ bool aIgnoreExistingStyles = false);
void RunPostTraversalTasks();
void PrependSheetOfType(SheetType aType,
ServoStyleSheet* aSheet);
void AppendSheetOfType(SheetType aType,
ServoStyleSheet* aSheet);
--- a/layout/style/StyleSetHandle.h
+++ b/layout/style/StyleSetHandle.h
@@ -122,16 +122,20 @@ public:
nsStyleContext* aParentContext,
LazyComputeBehavior aMayCompute);
inline already_AddRefed<nsStyleContext>
ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext,
LazyComputeBehavior aMayCompute,
TreeMatchContext* aTreeMatchContext);
inline already_AddRefed<nsStyleContext>
+ ResolveCleanStyleFor(dom::Element* aElement,
+ nsStyleContext* aParentContext,
+ LazyComputeBehavior aMayCompute);
+ inline already_AddRefed<nsStyleContext>
ResolveStyleForText(nsIContent* aTextNode,
nsStyleContext* aParentContext);
inline already_AddRefed<nsStyleContext>
ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext);
inline already_AddRefed<nsStyleContext>
ResolveStyleForPlaceholder();
inline already_AddRefed<nsStyleContext>
ResolvePseudoElementStyle(dom::Element* aParentElement,
--- a/layout/style/StyleSetHandleInlines.h
+++ b/layout/style/StyleSetHandleInlines.h
@@ -107,16 +107,25 @@ StyleSetHandle::Ptr::ResolveStyleFor(dom
return AsGecko()->ResolveStyleFor(aElement, parent, aMayCompute, *aTreeMatchContext);
} else {
auto* parent = aParentContext ? aParentContext->AsServo() : nullptr;
return AsServo()->ResolveStyleFor(aElement, parent, aMayCompute);
}
}
already_AddRefed<nsStyleContext>
+StyleSetHandle::Ptr::ResolveCleanStyleFor(dom::Element* aElement,
+ nsStyleContext* aParentContext,
+ LazyComputeBehavior aMayCompute)
+{
+ FORWARD_WITH_PARENT(ResolveCleanStyleFor, aParentContext,
+ (aElement, parent, aMayCompute));
+}
+
+already_AddRefed<nsStyleContext>
StyleSetHandle::Ptr::ResolveStyleForText(nsIContent* aTextNode,
nsStyleContext* aParentContext)
{
FORWARD_WITH_PARENT(ResolveStyleForText, aParentContext, (aTextNode, parent));
}
already_AddRefed<nsStyleContext>
StyleSetHandle::Ptr::ResolveStyleForPlaceholder()
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -583,16 +583,25 @@ nsComputedDOMStyle::DoGetStyleContextNoF
bool inDocWithShell = true;
if (!presShell) {
inDocWithShell = false;
presShell = aPresShell;
if (!presShell)
return nullptr;
}
+ // We do this check to avoid having to add too much special casing of
+ // Servo functions we call to explicitly ignore any element data in
+ // the tree.
+ MOZ_ASSERT((aStyleType == eAll && aAnimationFlag == eWithAnimation) ||
+ !aElement->OwnerDoc()->GetBFCacheEntry(),
+ "nsComputedDOMStyle doesn't support getting styles without "
+ "document rules or without animation for documents in the "
+ "bfcache");
+
auto pseudoType = CSSPseudoElementType::NotPseudo;
if (aPseudo) {
pseudoType = nsCSSPseudoElements::
GetPseudoType(aPseudo, CSSEnabledState::eIgnoreEnabledState);
if (pseudoType >= CSSPseudoElementType::Count) {
return nullptr;
}
}
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -121,16 +121,24 @@ class nsStyleSet final
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
mozilla::LazyComputeBehavior)
{
return ResolveStyleFor(aElement, aParentContext);
}
already_AddRefed<mozilla::GeckoStyleContext>
+ ResolveCleanStyleFor(mozilla::dom::Element* aElement,
+ mozilla::GeckoStyleContext* aParentContext,
+ mozilla::LazyComputeBehavior)
+ {
+ return ResolveStyleFor(aElement, aParentContext);
+ }
+
+ already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
TreeMatchContext& aTreeMatchContext);
already_AddRefed<mozilla::GeckoStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
mozilla::GeckoStyleContext* aParentContext,
mozilla::LazyComputeBehavior aMayCompute,
--- a/servo/components/style/traversal.rs
+++ b/servo/components/style/traversal.rs
@@ -386,61 +386,67 @@ pub trait DomTraversal<E: TElement> : Sy
/// Manually resolve style by sequentially walking up the parent chain to the
/// first styled Element, ignoring pending restyles. The resolved style is made
/// available via a callback, and can be dropped by the time this function
/// returns in the display:none subtree case.
pub fn resolve_style<E>(
context: &mut StyleContext<E>,
element: E,
rule_inclusion: RuleInclusion,
+ ignore_existing_style: bool,
) -> ElementStyles
where
E: TElement,
{
use style_resolver::StyleResolverForElement;
debug_assert!(rule_inclusion == RuleInclusion::DefaultOnly ||
+ ignore_existing_style ||
element.borrow_data().map_or(true, |d| !d.has_styles()),
"Why are we here?");
let mut ancestors_requiring_style_resolution = SmallVec::<[E; 16]>::new();
// Clear the bloom filter, just in case the caller is reusing TLS.
context.thread_local.bloom_filter.clear();
let mut style = None;
let mut ancestor = element.traversal_parent();
while let Some(current) = ancestor {
- if rule_inclusion == RuleInclusion::All {
+ if rule_inclusion == RuleInclusion::All && !ignore_existing_style {
if let Some(data) = current.borrow_data() {
if let Some(ancestor_style) = data.styles.get_primary() {
style = Some(ancestor_style.clone());
break;
}
}
}
ancestors_requiring_style_resolution.push(current);
ancestor = current.traversal_parent();
}
if let Some(ancestor) = ancestor {
context.thread_local.bloom_filter.rebuild(ancestor);
context.thread_local.bloom_filter.push(ancestor);
}
- let mut layout_parent_style = style.clone();
- while let Some(style) = layout_parent_style.take() {
- if !style.is_display_contents() {
- layout_parent_style = Some(style);
- break;
+ let mut layout_parent_style = None;
+
+ if !ignore_existing_style {
+ layout_parent_style = style.clone();
+ while let Some(style) = layout_parent_style.take() {
+ if !style.is_display_contents() {
+ layout_parent_style = Some(style);
+ break;
+ }
+
+ ancestor = ancestor.unwrap().traversal_parent();
+ layout_parent_style = ancestor.map(|a| {
+ a.borrow_data().unwrap().styles.primary().clone()
+ });
}
-
- ancestor = ancestor.unwrap().traversal_parent();
- layout_parent_style = ancestor.map(|a| {
- a.borrow_data().unwrap().styles.primary().clone()
- });
}
for ancestor in ancestors_requiring_style_resolution.iter().rev() {
context.thread_local.bloom_filter.assert_complete(*ancestor);
let primary_style =
StyleResolverForElement::new(*ancestor, context, rule_inclusion)
.resolve_primary_style(
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2826,17 +2826,18 @@ pub extern "C" fn Servo_ResolveStyleAllo
data.styles.primary().clone().into()
}
#[no_mangle]
pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
pseudo_type: CSSPseudoElementType,
rule_inclusion: StyleRuleInclusion,
snapshots: *const ServoElementSnapshotTable,
- raw_data: RawServoStyleSetBorrowed)
+ raw_data: RawServoStyleSetBorrowed,
+ ignore_existing_styles: bool)
-> ServoStyleContextStrong
{
debug_assert!(!snapshots.is_null());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data);
let data = doc_data.borrow();
@@ -2857,18 +2858,19 @@ pub extern "C" fn Servo_ResolveStyleLazi
back")
}
None => styles.primary().clone(),
}
};
// In the common case we already have the style. Check that before setting
// up all the computation machinery. (Don't use it when we're getting
- // default styles, though.)
- if rule_inclusion == RuleInclusion::All {
+ // default styles or in a bfcached document (as indicated by
+ // ignore_existing_styles), though.)
+ if rule_inclusion == RuleInclusion::All && !ignore_existing_styles {
let styles = element.mutate_data().and_then(|d| {
if d.has_styles() {
Some(finish(&d.styles))
} else {
None
}
});
if let Some(result) = styles {
@@ -2883,17 +2885,17 @@ pub extern "C" fn Servo_ResolveStyleLazi
TraversalFlags::empty(),
unsafe { &*snapshots });
let mut tlc = ThreadLocalStyleContext::new(&shared);
let mut context = StyleContext {
shared: &shared,
thread_local: &mut tlc,
};
- let styles = resolve_style(&mut context, element, rule_inclusion);
+ let styles = resolve_style(&mut context, element, rule_inclusion, ignore_existing_styles);
finish(&styles).into()
}
#[no_mangle]
pub extern "C" fn Servo_ReparentStyle(style_to_reparent: ServoStyleContextBorrowed,
parent_style: ServoStyleContextBorrowed,
parent_style_ignoring_first_line: ServoStyleContextBorrowed,
layout_parent_style: ServoStyleContextBorrowed,