Bug 1370793 - Part 1: Don't try to style unstyled children of elements with newly applied XBL bindings if in a display:none or unstyled subtree. r=bholley

MozReview-Commit-ID: EFi2Vp19AQm

--HG--
extra : rebase_source : 39ce54a1ffc4ec709afa552bc45cb6cd803ee827
This commit is contained in:
Cameron McCormack 2017-06-11 19:11:08 +08:00
parent 9ebc1a575e
commit a6661ab735
4 changed files with 45 additions and 12 deletions

View File

@ -420,17 +420,7 @@ public:
return;
}
if (ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo()) {
// In general the element is always styled by the time we're applying XBL
// bindings, because we need to style the element to know what the binding
// URI is. However, programmatic consumers of the XBL service (like the
// XML pretty printer) _can_ apply bindings without having styled the bound
// element. We could assert against this and require the callers manually
// resolve the style first, but it's easy enough to just handle here.
if (MOZ_UNLIKELY(!mElement->HasServoData())) {
servoSet->StyleNewSubtree(mElement);
} else {
servoSet->StyleNewChildren(mElement);
}
servoSet->StyleNewlyBoundElement(mElement);
}
}

View File

@ -374,9 +374,12 @@ ServoStyleSet::PrepareAndTraverseSubtree(
aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
bool forAnimationOnly =
aRestyleBehavior == TraversalRestyleBehavior::ForAnimationOnly;
bool forNewlyBoundElement =
aRestyleBehavior == TraversalRestyleBehavior::ForNewlyBoundElement;
bool postTraversalRequired = Servo_TraverseSubtree(
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
MOZ_ASSERT(!(isInitial || forReconstruct) || !postTraversalRequired);
MOZ_ASSERT(!(isInitial || forReconstruct || forNewlyBoundElement) ||
!postTraversalRequired);
// Don't need to trigger a second traversal if this restyle only needs
// animation-only restyle.
@ -955,6 +958,34 @@ ServoStyleSet::StyleNewChildren(Element* aParent)
// or some of its other children might have pending restyles.
}
void
ServoStyleSet::StyleNewlyBoundElement(Element* aElement)
{
PreTraverse();
// In general the element is always styled by the time we're applying XBL
// bindings, because we need to style the element to know what the binding
// URI is. However, programmatic consumers of the XBL service (like the
// XML pretty printer) _can_ apply bindings without having styled the bound
// element. We could assert against this and require the callers manually
// resolve the style first, but it's easy enough to just handle here.
//
// Also, when applying XBL bindings to elements within a display:none or
// unstyled subtree (for example, when <object> elements are wrapped to be
// exposed to JS), we need to tell the traversal that it is OK to
// skip restyling, rather than panic when trying to unwrap the styles
// it expects to have just computed.
TraversalRootBehavior rootBehavior =
MOZ_UNLIKELY(!aElement->HasServoData())
? TraversalRootBehavior::Normal
: TraversalRootBehavior::UnstyledChildrenOnly;
PrepareAndTraverseSubtree(aElement,
rootBehavior,
TraversalRestyleBehavior::ForNewlyBoundElement);
}
void
ServoStyleSet::StyleSubtreeForReconstruct(Element* aRoot)
{

View File

@ -305,6 +305,14 @@ public:
*/
void StyleNewChildren(dom::Element* aParent);
/**
* Eagerly styles the children of an element that has just had an XBL
* binding applied to it. Some XBL consumers attach bindings to elements
* that have not been styled yet, and in such cases, this will do the
* equivalent of StyleNewSubtree instead.
*/
void StyleNewlyBoundElement(dom::Element* aElement);
/**
* Like StyleNewSubtree, but in response to a request to reconstruct frames
* for the given subtree, and so works on elements that already have

View File

@ -63,6 +63,10 @@ enum class TraversalRootBehavior {
enum class TraversalRestyleBehavior {
// Normal processing.
Normal,
// Normal processing, but tolerant to calls to restyle elements in unstyled
// or display:none subtrees (which can occur when styling elements with
// newly applied XBL bindings).
ForNewlyBoundElement,
// Traverses in a mode that doesn't generate any change hints, which is what's
// required when handling frame reconstruction. The change hints in this case
// are unneeded, since the old frames have already been destroyed.