Bug 1317016 - Basic infrastructure for RestyleHint-driven traversal. r=emilio

MozReview-Commit-ID: 7wH5XcILVmX
This commit is contained in:
Bobby Holley 2016-11-01 23:11:24 -07:00
parent 43738b4026
commit f8c9d884fc
39 changed files with 542 additions and 694 deletions

View File

@ -1736,18 +1736,6 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
}
// It would be cleanest to mark nodes as dirty when (a) they're created and
// (b) they're unbound from a tree. However, we can't easily do (a) right now,
// because IsStyledByServo() is not always easy to check at node creation time,
// and the bits have different meaning in the non-IsStyledByServo case.
//
// So for now, we just mark nodes as dirty when they're inserted into a
// document or shadow tree.
if (IsStyledByServo() && IsInComposedDoc()) {
MOZ_ASSERT(!HasServoData());
SetIsDirtyForServo();
}
// XXXbz script execution during binding can trigger some of these
// postcondition asserts.... But we do want that, since things will
// generally be quite broken when that happens.
@ -3922,3 +3910,12 @@ Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32
}
return false;
}
void
Element::ClearServoData() {
#ifdef MOZ_STYLO
Servo_Element_ClearData(this);
#else
MOZ_CRASH("Accessing servo node data in non-stylo build");
#endif
}

View File

@ -16,6 +16,7 @@
#include "mozilla/dom/FragmentOrElement.h" // for base class
#include "nsChangeHint.h" // for enum
#include "mozilla/EventStates.h" // for member
#include "mozilla/ServoTypes.h"
#include "mozilla/dom/DirectionalityUtils.h"
#include "nsIDOMElement.h"
#include "nsILinkHandler.h"
@ -164,6 +165,14 @@ public:
"Bad NodeType in aNodeInfo");
SetIsElement();
}
~Element()
{
#ifdef MOZ_STYLO
NS_ASSERTION(!HasServoData(), "expected ServoData to be cleared earlier");
#endif
}
#endif // MOZILLA_INTERNAL_API
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ELEMENT_IID)
@ -391,6 +400,40 @@ public:
Directionality GetComputedDirectionality() const;
inline Element* GetFlattenedTreeParentElement() const;
bool HasDirtyDescendantsForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void SetHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void UnsetHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
UnsetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
inline void NoteDirtyDescendantsForServo();
#ifdef DEBUG
inline bool DirtyDescendantsBitIsPropagatedForServo();
#endif
bool HasServoData() {
#ifdef MOZ_STYLO
return !!mServoData.Get();
#else
MOZ_CRASH("Accessing servo node data in non-stylo build");
#endif
}
void ClearServoData();
protected:
/**
* Method to get the _intrinsic_ content state of this element. This is the
@ -1391,6 +1434,10 @@ private:
// Data members
EventStates mState;
#ifdef MOZ_STYLO
// Per-node data managed by Servo.
mozilla::ServoCell<ServoNodeData*> mServoData;
#endif
};
class RemoveFromBindingManagerRunnable : public mozilla::Runnable
@ -1488,7 +1535,7 @@ inline const mozilla::dom::Element* nsINode::AsElement() const
inline void nsINode::UnsetRestyleFlagsIfGecko()
{
if (IsElement() && !IsStyledByServo()) {
if (IsElement() && !AsElement()->IsStyledByServo()) {
UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS);
}
}

View File

@ -8,6 +8,7 @@
#define mozilla_dom_ElementInlines_h
#include "mozilla/dom/Element.h"
#include "nsIContentInlines.h"
#include "nsIDocument.h"
namespace mozilla {
@ -25,6 +26,46 @@ Element::UnregisterActivityObserver()
OwnerDoc()->UnregisterActivityObserver(this);
}
inline Element*
Element::GetFlattenedTreeParentElement() const
{
nsINode* parentNode = GetFlattenedTreeParentNode();
if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
return parentNode->AsElement();
}
return nullptr;
}
inline void
Element::NoteDirtyDescendantsForServo()
{
Element* curr = this;
while (curr && !curr->HasDirtyDescendantsForServo()) {
curr->SetHasDirtyDescendantsForServo();
curr = curr->GetFlattenedTreeParentElement();
}
MOZ_ASSERT(DirtyDescendantsBitIsPropagatedForServo());
}
#ifdef DEBUG
inline bool
Element::DirtyDescendantsBitIsPropagatedForServo()
{
Element* curr = this;
while (curr) {
if (!curr->HasDirtyDescendantsForServo()) {
return false;
}
nsINode* parentNode = curr->GetParentNode();
curr = curr->GetFlattenedTreeParentElement();
MOZ_ASSERT_IF(!curr, parentNode == OwnerDoc());
}
return true;
}
#endif
} // namespace dom
} // namespace mozilla

View File

@ -2344,51 +2344,3 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
shadowRoot = shadowRoot->GetOlderShadowRoot();
}
}
#ifdef DEBUG
static void
AssertDirtyDescendantsBitPropagated(nsINode* aNode)
{
MOZ_ASSERT(aNode->HasDirtyDescendantsForServo());
nsINode* parent = aNode->GetFlattenedTreeParentNode();
if (!parent->IsContent()) {
MOZ_ASSERT(parent == aNode->OwnerDoc());
MOZ_ASSERT(parent->HasDirtyDescendantsForServo());
} else {
AssertDirtyDescendantsBitPropagated(parent);
}
}
#else
static void AssertDirtyDescendantsBitPropagated(nsINode* aNode) {}
#endif
void
nsIContent::MarkAncestorsAsHavingDirtyDescendantsForServo()
{
MOZ_ASSERT(IsInComposedDoc());
// Get the parent in the flattened tree.
nsINode* parent = GetFlattenedTreeParentNode();
// Loop until we hit a base case.
while (true) {
// Base case: the document.
if (!parent->IsContent()) {
MOZ_ASSERT(parent == OwnerDoc());
parent->SetHasDirtyDescendantsForServo();
return;
}
// Base case: the parent is already marked, and therefore
// so are all its ancestors.
if (parent->HasDirtyDescendantsForServo()) {
AssertDirtyDescendantsBitPropagated(parent);
return;
}
// Mark the parent and iterate.
parent->SetHasDirtyDescendantsForServo();
parent = parent->GetFlattenedTreeParentNode();
}
}

View File

@ -552,18 +552,6 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
UpdateEditableState(false);
// It would be cleanest to mark nodes as dirty when (a) they're created and
// (b) they're unbound from a tree. However, we can't easily do (a) right now,
// because IsStyledByServo() is not always easy to check at node creation time,
// and the bits have different meaning in the non-IsStyledByServo case.
//
// So for now, we just mark nodes as dirty when they're inserted into a
// document or shadow tree.
if (IsStyledByServo() && IsInComposedDoc()) {
MOZ_ASSERT(!HasServoData());
SetIsDirtyForServo();
}
NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
NS_POSTCONDITION(aBindingParent == GetBindingParent(),
@ -595,16 +583,6 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
}
ClearInDocument();
// Computed styled data isn't useful for detached nodes, and we'll need to
// recomputed it anyway if we ever insert the nodes back into a document.
if (IsStyledByServo()) {
ClearServoData();
} else {
#ifdef MOZ_STYLO
MOZ_ASSERT(!HasServoData());
#endif
}
if (aNullParent || !mParent->IsInShadowTree()) {
UnsetFlags(NODE_IS_IN_SHADOW_TREE);

View File

@ -938,14 +938,6 @@ public:
*/
mozilla::dom::Element* GetEditingHost();
/**
* Set NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO all the way up the flattened
* parent chain to the document. If an ancestor is found with the bit already
* set, this method asserts that all of its ancestors also have the bit set.
*/
void MarkAncestorsAsHavingDirtyDescendantsForServo();
/**
* Determining language. Look at the nearest ancestor element that has a lang
* attribute in the XML namespace or is an HTML/SVG element and has a lang in

View File

@ -152,10 +152,6 @@ nsINode::~nsINode()
{
MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
#ifdef MOZ_STYLO
NS_ASSERTION(!HasServoData(), "expected ServoNodeData to be cleared earlier");
ClearServoData();
#endif
}
void*
@ -1400,15 +1396,6 @@ nsINode::UnoptimizableCCNode() const
AsElement()->IsInNamespace(kNameSpaceID_XBL));
}
void
nsINode::ClearServoData() {
#ifdef MOZ_STYLO
Servo_Node_ClearNodeData(this);
#else
MOZ_CRASH("Accessing servo node data in non-stylo build");
#endif
}
/* static */
bool
nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)

View File

@ -8,7 +8,6 @@
#define nsINode_h___
#include "mozilla/Likely.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h" // for member, local
#include "nsGkAtoms.h" // for nsGkAtoms::baseURIProperty
@ -186,14 +185,13 @@ enum {
// These two bits are shared by Gecko's and Servo's restyle systems for
// different purposes. They should not be accessed directly, and access to
// them should be properly guarded by asserts.
//
// FIXME(bholley): These should move to Element, and we only need one now.
NODE_SHARED_RESTYLE_BIT_1 = NODE_FLAG_BIT(21),
NODE_SHARED_RESTYLE_BIT_2 = NODE_FLAG_BIT(22),
// Whether this node is dirty for Servo's style system.
NODE_IS_DIRTY_FOR_SERVO = NODE_SHARED_RESTYLE_BIT_1,
// Whether this node has dirty descendants for Servo's style system.
NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO = NODE_SHARED_RESTYLE_BIT_2,
NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO = NODE_SHARED_RESTYLE_BIT_1,
// Remaining bits are node type specific.
NODE_TYPE_SPECIFIC_BITS_OFFSET = 23
@ -981,48 +979,6 @@ public:
bool IsStyledByServo() const { return false; }
#endif
bool IsDirtyForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_IS_DIRTY_FOR_SERVO);
}
bool HasDirtyDescendantsForServo() const
{
MOZ_ASSERT(IsStyledByServo());
return HasFlag(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void SetIsDirtyForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_IS_DIRTY_FOR_SERVO);
}
void SetHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void SetIsDirtyAndHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
SetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO | NODE_IS_DIRTY_FOR_SERVO);
}
void UnsetIsDirtyForServo() {
MOZ_ASSERT(IsStyledByServo());
UnsetFlags(NODE_IS_DIRTY_FOR_SERVO);
}
void UnsetHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
UnsetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
}
void UnsetIsDirtyAndHasDirtyDescendantsForServo() {
MOZ_ASSERT(IsStyledByServo());
UnsetFlags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO | NODE_IS_DIRTY_FOR_SERVO);
}
inline void UnsetRestyleFlagsIfGecko();
/**
@ -2061,16 +2017,6 @@ public:
#undef TOUCH_EVENT
#undef EVENT
bool HasServoData() {
#ifdef MOZ_STYLO
return !!mServoData.Get();
#else
MOZ_CRASH("Accessing servo node data in non-stylo build");
#endif
}
void ClearServoData();
protected:
static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
static void Unlink(nsINode *tmp);
@ -2108,11 +2054,6 @@ protected:
// Storage for more members that are usually not needed; allocated lazily.
nsSlots* mSlots;
#ifdef MOZ_STYLO
// Per-node data managed by Servo.
mozilla::ServoCell<ServoNodeData*> mServoData;
#endif
};
inline nsIDOMNode* GetAsDOMNode(nsINode* aNode)

View File

@ -2942,11 +2942,14 @@ IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
return false;
}
// XXXbholley: This could be done more directly with Servo's style system.
StyleSetHandle styleSet = aPresShell->StyleSet();
RefPtr<nsStyleContext> sc;
for (int32_t i = elementsToCheck.Length() - 1; i >= 0; --i) {
if (sc) {
sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc);
sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc,
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Assert);
} else {
sc = nsComputedDOMStyle::GetStyleContextForElementNoFlush(elementsToCheck[i],
nullptr, aPresShell);

View File

@ -426,7 +426,6 @@ nsXBLBinding::GenerateAnonymousContent()
nsIPresShell* presShell = mBoundElement->OwnerDoc()->GetShell();
ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo();
if (servoSet) {
mBoundElement->SetHasDirtyDescendantsForServo();
servoSet->StyleNewChildren(mBoundElement);
}
}

View File

@ -81,6 +81,8 @@ public:
// itself.
nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList);
bool IsInStyleRefresh() const { return mInStyleRefresh; }
protected:
void ContentStateChangedInternal(Element* aElement,
EventStates aStateMask,

View File

@ -17,6 +17,7 @@
namespace mozilla {
class RestyleManager;
class ServoRestyleManager;
class RestyleManagerBase;
namespace dom {
class Element;
} // namespace dom
@ -95,6 +96,14 @@ public:
const RestyleManager* GetAsGecko() const { return IsGecko() ? AsGecko() : nullptr; }
const ServoRestyleManager* GetAsServo() const { return IsServo() ? AsServo() : nullptr; }
const mozilla::RestyleManagerBase* AsBase() const {
return reinterpret_cast<const RestyleManagerBase*>(mValue & ~SERVO_BIT);
}
mozilla::RestyleManagerBase* AsBase() {
return reinterpret_cast<RestyleManagerBase*>(mValue & ~SERVO_BIT);
}
// These inline methods are defined in RestyleManagerHandleInlines.h.
inline MozExternalRefCountType AddRef();
inline MozExternalRefCountType Release();

View File

@ -18,6 +18,7 @@ namespace mozilla {
ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
: RestyleManagerBase(aPresContext)
, mReentrantChanges(nullptr)
{
}
@ -35,6 +36,19 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
return; // Nothing to do.
}
// We allow posting change hints during restyling, but not restyle hints
// themselves, since those would require us to re-traverse the tree.
MOZ_ASSERT_IF(mInStyleRefresh, aRestyleHint == 0);
// Processing change hints sometimes causes new change hints to be generated.
// Doing this after the gecko post-traversal is problematic, so instead we just
// queue them up for special handling.
if (mReentrantChanges) {
MOZ_ASSERT(aRestyleHint == 0);
mReentrantChanges->AppendElement(ReentrantChange { aElement, aMinChangeHint });
return;
}
// XXX This is a temporary hack to make style attribute change works.
// In the future, we should be able to use this hint directly.
if (aRestyleHint & eRestyle_StyleAttribute) {
@ -42,12 +56,8 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
aRestyleHint |= eRestyle_Self | eRestyle_Subtree;
}
// Note that unlike in Servo, we don't mark elements as dirty until we process
// the restyle hints in ProcessPendingRestyles.
if (aRestyleHint || aMinChangeHint) {
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
snapshot->AddExplicitRestyleHint(aRestyleHint);
snapshot->AddExplicitChangeHint(aMinChangeHint);
Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
}
PostRestyleEventInternal(false);
@ -73,123 +83,67 @@ ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
NS_WARNING("stylo: ServoRestyleManager::PostRebuildAllStyleDataEvent not implemented");
}
static void
MarkSelfAndDescendantsAsNotDirtyForServo(nsIContent* aContent)
/* static */ void
ServoRestyleManager::ClearServoDataFromSubtree(Element* aElement)
{
aContent->UnsetIsDirtyForServo();
aElement->ClearServoData();
if (aContent->HasDirtyDescendantsForServo()) {
aContent->UnsetHasDirtyDescendantsForServo();
StyleChildrenIterator it(aContent);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
MarkSelfAndDescendantsAsNotDirtyForServo(n);
StyleChildrenIterator it(aElement);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (n->IsElement()) {
ClearServoDataFromSubtree(n->AsElement());
}
}
aElement->UnsetHasDirtyDescendantsForServo();
}
/* static */ void
ServoRestyleManager::ClearServoDataFromSubtree(nsIContent* aContent)
ServoRestyleManager::ClearDirtyDescendantsFromSubtree(Element* aElement)
{
aContent->ClearServoData();
aContent->SetIsDirtyForServo();
aContent->UnsetHasDirtyDescendantsForServo();
AllChildrenIterator it(aContent, nsIContent::eAllChildren);
StyleChildrenIterator it(aElement);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
ClearServoDataFromSubtree(n);
if (n->IsElement()) {
ClearDirtyDescendantsFromSubtree(n->AsElement());
}
}
aElement->UnsetHasDirtyDescendantsForServo();
}
void
ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
ServoRestyleManager::RecreateStyleContexts(Element* aElement,
nsStyleContext* aParentContext,
ServoStyleSet* aStyleSet,
nsStyleChangeList& aChangeListToProcess)
{
MOZ_ASSERT(aContent->IsElement() || aContent->IsNodeOfType(nsINode::eTEXT));
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
if (!primaryFrame && !aContent->IsDirtyForServo()) {
// This happens when, for example, a display: none child of a
// HAS_DIRTY_DESCENDANTS content is reached as part of the traversal.
MarkSelfAndDescendantsAsNotDirtyForServo(aContent);
// FIXME(bholley): Once we transfer ownership of the styles to the frame, we
// can fast-reject without the FFI call by checking mServoData for null.
nsChangeHint changeHint = Servo_CheckChangeHint(aElement);
if (changeHint) {
aChangeListToProcess.AppendChange(primaryFrame, aElement, changeHint);
}
// If our change hint is reconstruct, we delegate to the frame constructor,
// which consumes the new style and expects the old style to be on the frame.
//
// XXXbholley: We should teach the frame constructor how to clear the dirty
// descendants bit to avoid the traversal here.
if (changeHint & nsChangeHint_ReconstructFrame) {
ClearDirtyDescendantsFromSubtree(aElement);
return;
}
// Work on text before.
if (!aContent->IsElement()) {
if (primaryFrame) {
RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
RefPtr<nsStyleContext> newContext =
aStyleSet->ResolveStyleForText(aContent, aParentContext);
for (nsIFrame* f = primaryFrame; f;
f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
f->SetStyleContext(newContext);
}
}
aContent->UnsetIsDirtyForServo();
return;
}
Element* element = aContent->AsElement();
if (element->IsDirtyForServo()) {
RefPtr<ServoComputedValues> computedValues =
Servo_ComputedValues_Get(aContent).Consume();
MOZ_ASSERT(computedValues);
nsChangeHint changeHint = nsChangeHint(0);
// Add an explicit change hint if appropriate.
ServoElementSnapshot* snapshot;
if (mModifiedElements.Get(element, &snapshot)) {
changeHint |= snapshot->ExplicitChangeHint();
}
// Add the stored change hint if there's a frame. If there isn't a frame,
// generate a ReconstructFrame change hint if the new display value
// (which we can get from the ComputedValues stored on the node) is not
// none.
if (primaryFrame) {
changeHint |= primaryFrame->StyleContext()->ConsumeStoredChangeHint();
} else {
const nsStyleDisplay* currentDisplay =
Servo_GetStyleDisplay(computedValues);
if (currentDisplay->mDisplay != StyleDisplay::None) {
changeHint |= nsChangeHint_ReconstructFrame;
}
}
// Add the new change hint to the list of elements to process if
// we need to do any work.
if (changeHint) {
aChangeListToProcess.AppendChange(primaryFrame, element, changeHint);
}
// The frame reconstruction step (if needed) will ask for the descendants'
// style correctly. If not needed, we're done too.
//
// Note that we must leave the old style on an existing frame that is
// about to be reframed, since some frame constructor code wants to
// inspect the old style to work out what to do.
if (changeHint & nsChangeHint_ReconstructFrame) {
// Since we might still have some dirty bits set on descendants,
// inconsistent with the clearing of HasDirtyDescendants we will do as
// we return from these recursive RecreateStyleContexts calls, we
// explicitly clear them here. Otherwise we will trigger assertions
// when we soon process the frame reconstruction.
MarkSelfAndDescendantsAsNotDirtyForServo(element);
return;
}
// If there is no frame, and we didn't generate a ReconstructFrame change
// hint, then we don't need to do any more work.
if (!primaryFrame) {
aContent->UnsetIsDirtyForServo();
return;
}
// If we have a frame and a non-zero + non-reconstruct change hint, we need to
// attach a new style context.
bool recreateContext = primaryFrame && changeHint;
if (recreateContext) {
RefPtr<ServoComputedValues> computedValues
= Servo_ResolveStyle(aElement, aStyleSet->mRawSet.get(),
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Assert).Consume();
// Hold the old style context alive, because it could become a dangling
// pointer during the replacement. In practice it's not a huge deal (on
@ -219,69 +173,68 @@ ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
for (CSSPseudoElementType pseudoType : pseudosToRestyle) {
nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(pseudoType);
if (nsIFrame* pseudoFrame = FrameForPseudoElement(element, pseudoTag)) {
if (nsIFrame* pseudoFrame = FrameForPseudoElement(aElement, pseudoTag)) {
// TODO: we could maybe make this more performant via calling into
// Servo just once to know which pseudo-elements we've got to restyle?
RefPtr<nsStyleContext> pseudoContext =
aStyleSet->ProbePseudoElementStyle(element, pseudoType, newContext);
aStyleSet->ProbePseudoElementStyle(aElement, pseudoType, newContext);
MOZ_ASSERT(pseudoContext, "should have taken the ReconstructFrame path above");
pseudoFrame->SetStyleContext(pseudoContext);
// If pseudoContext is null here, it means the frame is going away, so
// our change hint computation should have already indicated we need
// to reframe.
MOZ_ASSERT_IF(!pseudoContext,
changeHint & nsChangeHint_ReconstructFrame);
if (pseudoContext) {
pseudoFrame->SetStyleContext(pseudoContext);
// We only care restyling text nodes, since other type of nodes
// (images), are still not supported. If that eventually changes, we
// may have to write more code here... Or not, I don't think too
// many inherited properties can affect those other frames.
StyleChildrenIterator it(pseudoFrame->GetContent());
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (n->IsNodeOfType(nsINode::eTEXT)) {
RefPtr<nsStyleContext> childContext =
aStyleSet->ResolveStyleForText(n, pseudoContext);
MOZ_ASSERT(n->GetPrimaryFrame(),
"How? This node is created at FC time!");
n->GetPrimaryFrame()->SetStyleContext(childContext);
}
// We only care restyling text nodes, since other type of nodes
// (images), are still not supported. If that eventually changes, we
// may have to write more code here... Or not, I don't think too
// many inherited properties can affect those other frames.
StyleChildrenIterator it(pseudoFrame->GetContent());
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (n->IsNodeOfType(nsINode::eTEXT)) {
RefPtr<nsStyleContext> childContext =
aStyleSet->ResolveStyleForText(n, pseudoContext);
MOZ_ASSERT(n->GetPrimaryFrame(),
"How? This node is created at FC time!");
n->GetPrimaryFrame()->SetStyleContext(childContext);
}
}
}
}
aContent->UnsetIsDirtyForServo();
}
if (aContent->HasDirtyDescendantsForServo()) {
MOZ_ASSERT(primaryFrame,
"Frame construction should be scheduled, and it takes the "
"correct style for the children, so no need to be here.");
StyleChildrenIterator it(aContent);
bool traverseElementChildren = aElement->HasDirtyDescendantsForServo();
bool traverseTextChildren = recreateContext;
if (traverseElementChildren || traverseTextChildren) {
StyleChildrenIterator it(aElement);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
if (n->IsElement() || n->IsNodeOfType(nsINode::eTEXT)) {
RecreateStyleContexts(n, primaryFrame->StyleContext(),
if (traverseElementChildren && n->IsElement()) {
MOZ_ASSERT(primaryFrame,
"Frame construction should be scheduled, and it takes the "
"correct style for the children, so no need to be here.");
RecreateStyleContexts(n->AsElement(), primaryFrame->StyleContext(),
aStyleSet, aChangeListToProcess);
} else if (traverseTextChildren && n->IsNodeOfType(nsINode::eTEXT)) {
RecreateStyleContextsForText(n, primaryFrame->StyleContext(),
aStyleSet);
}
}
aContent->UnsetHasDirtyDescendantsForServo();
}
aElement->UnsetHasDirtyDescendantsForServo();
}
static void
MarkChildrenAsDirtyForServo(nsIContent* aContent)
void
ServoRestyleManager::RecreateStyleContextsForText(nsIContent* aTextNode,
nsStyleContext* aParentContext,
ServoStyleSet* aStyleSet)
{
StyleChildrenIterator it(aContent);
nsIFrame* primaryFrame = aTextNode->GetPrimaryFrame();
if (primaryFrame) {
RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
RefPtr<nsStyleContext> newContext =
aStyleSet->ResolveStyleForText(aTextNode, aParentContext);
nsIContent* n = it.GetNextChild();
bool hadChildren = bool(n);
for (; n; n = it.GetNextChild()) {
n->SetIsDirtyForServo();
}
if (hadChildren) {
aContent->SetHasDirtyDescendantsForServo();
for (nsIFrame* f = primaryFrame; f;
f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
f->SetStyleContext(newContext);
}
}
}
@ -315,43 +268,6 @@ ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
return nullptr;
}
/* static */ void
ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
{
const nsRestyleHint HANDLED_RESTYLE_HINTS = eRestyle_Self |
eRestyle_Subtree |
eRestyle_LaterSiblings |
eRestyle_SomeDescendants;
// NB: For Servo, at least for now, restyling and running selector-matching
// against the subtree is necessary as part of restyling the element, so
// processing eRestyle_Self will perform at least as much work as
// eRestyle_Subtree.
if (aHint & (eRestyle_Self | eRestyle_Subtree)) {
aElement->SetIsDirtyForServo();
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
// NB: Servo gives us a eRestyle_SomeDescendants when it expects us to run
// selector matching on all the descendants. There's a bug on Servo to align
// meanings here (#12710) to avoid this potential source of confusion.
} else if (aHint & eRestyle_SomeDescendants) {
MarkChildrenAsDirtyForServo(aElement);
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
}
if (aHint & eRestyle_LaterSiblings) {
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
for (nsIContent* cur = aElement->GetNextSibling(); cur;
cur = cur->GetNextSibling()) {
cur->SetIsDirtyForServo();
}
}
// TODO: Handle all other nsRestyleHint values.
if (aHint & ~HANDLED_RESTYLE_HINTS) {
NS_WARNING(nsPrintfCString("stylo: Unhandled restyle hint %s",
RestyleManagerBase::RestyleHintToString(aHint).get()).get());
}
}
void
ServoRestyleManager::ProcessPendingRestyles()
{
@ -374,66 +290,48 @@ ServoRestyleManager::ProcessPendingRestyles()
ServoStyleSet* styleSet = StyleSet();
nsIDocument* doc = PresContext()->Document();
Element* root = doc->GetRootElement();
if (root) {
// ProcessPendingRestyles can generate new restyles (e.g. from the
// frame constructor if it decides that a ReconstructFrame change must
// apply to the parent of the element that generated that hint). So
// we loop while mModifiedElements still has some restyles in it, clearing
// it after each RecreateStyleContexts call below.
while (!mModifiedElements.IsEmpty()) {
for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) {
ServoElementSnapshot* snapshot = iter.UserData();
Element* element = iter.Key();
// The element is no longer in the document, so don't bother computing
// a final restyle hint for it.
//
// XXXheycam RestyleTracker checks that the element's GetComposedDoc()
// matches the document we're restyling. Do we need to do that too?
if (!element->IsInComposedDoc()) {
continue;
}
// XXXbholley: Should this be while() per bug 1316247?
if (HasPendingRestyles()) {
MOZ_ASSERT(root);
mInStyleRefresh = true;
styleSet->StyleDocument();
// TODO: avoid the ComputeRestyleHint call if we already have the highest
// explicit restyle hint?
nsRestyleHint hint = styleSet->ComputeRestyleHint(element, snapshot);
hint |= snapshot->ExplicitRestyleHint();
// First do any queued-up frame creation. (see bugs 827239 and 997506).
//
// XXXEmilio I'm calling this to avoid random behavior changes, since we
// delay frame construction after styling we should re-check once our
// model is more stable whether we can skip this call.
//
// Note this has to be *after* restyling, because otherwise frame
// construction will find unstyled nodes, and that's not funny.
PresContext()->FrameConstructor()->CreateNeededFrames();
if (hint) {
NoteRestyleHint(element, hint);
}
// Recreate style contexts and queue up change hints.
nsStyleChangeList currentChanges;
RecreateStyleContexts(root, nullptr, styleSet, currentChanges);
// Process the change hints.
//
// Unfortunately, the frame constructor can generate new change hints while
// processing existing ones. We redirect those into a secondary queue and
// iterate until there's nothing left.
ReentrantChangeList newChanges;
mReentrantChanges = &newChanges;
while (!currentChanges.IsEmpty()) {
ProcessRestyledFrames(currentChanges);
MOZ_ASSERT(currentChanges.IsEmpty());
for (ReentrantChange& change: newChanges) {
currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
change.mContent, change.mHint);
}
if (!root->IsDirtyForServo() && !root->HasDirtyDescendantsForServo()) {
mModifiedElements.Clear();
break;
}
mInStyleRefresh = true;
styleSet->StyleDocument(/* aLeaveDirtyBits = */ true);
// First do any queued-up frame creation. (see bugs 827239 and 997506).
//
// XXXEmilio I'm calling this to avoid random behavior changes, since we
// delay frame construction after styling we should re-check once our
// model is more stable whether we can skip this call.
//
// Note this has to be *after* restyling, because otherwise frame
// construction will find unstyled nodes, and that's not funny.
PresContext()->FrameConstructor()->CreateNeededFrames();
nsStyleChangeList changeList;
RecreateStyleContexts(root, nullptr, styleSet, changeList);
mModifiedElements.Clear();
ProcessRestyledFrames(changeList);
mInStyleRefresh = false;
newChanges.Clear();
}
}
mReentrantChanges = nullptr;
MOZ_ASSERT(!doc->IsDirtyForServo());
doc->UnsetHasDirtyDescendantsForServo();
styleSet->AssertTreeIsClean();
mInStyleRefresh = false;
}
IncrementRestyleGeneration();
}
@ -454,31 +352,6 @@ ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
void
ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild)
{
if (aContainer == aContainer->OwnerDoc()) {
// If we're getting this notification for the insertion of a root element,
// that means either:
// (a) We initialized the PresShell before the root element existed, or
// (b) The root element was removed and it or another root is being
// inserted.
//
// Either way the whole tree is dirty, so we should style the document.
MOZ_ASSERT(aChild == aChild->OwnerDoc()->GetRootElement());
MOZ_ASSERT(aChild->IsDirtyForServo());
StyleSet()->StyleDocument(/* aLeaveDirtyBits = */ false);
return;
}
if (!aContainer->HasServoData()) {
// This can happen with display:none. Bug 1297249 tracks more investigation
// and assertions here.
return;
}
// Style the new subtree because we will most likely need it during subsequent
// frame construction. Bug 1298281 tracks deferring this work in the lazy
// frame construction case.
StyleSet()->StyleNewSubtree(aChild);
RestyleForInsertOrChange(aContainer, aChild);
}
@ -499,22 +372,6 @@ void
ServoRestyleManager::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent)
{
if (!aContainer->HasServoData()) {
// This can happen with display:none. Bug 1297249 tracks more investigation
// and assertions here.
return;
}
// Style the new subtree because we will most likely need it during subsequent
// frame construction. Bug 1298281 tracks deferring this work in the lazy
// frame construction case.
if (aFirstNewContent->GetNextSibling()) {
aContainer->SetHasDirtyDescendantsForServo();
StyleSet()->StyleNewChildren(aContainer);
} else {
StyleSet()->StyleNewSubtree(aFirstNewContent);
}
RestyleForAppend(aContainer, aFirstNewContent);
}
@ -561,10 +418,12 @@ ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
&restyleHint);
EventStates previousState = aElement->StyleState() ^ aChangedBits;
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
snapshot->AddState(previousState);
ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
if (snapshot) {
snapshot->AddState(previousState);
PostRestyleEvent(aElement, restyleHint, changeHint);
}
PostRestyleEvent(aElement, restyleHint, changeHint);
return NS_OK;
}
@ -574,8 +433,10 @@ ServoRestyleManager::AttributeWillChange(Element* aElement,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aNewValue)
{
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
snapshot->AddAttrs(aElement);
ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
if (snapshot) {
snapshot->AddAttrs(aElement);
}
}
void
@ -583,7 +444,10 @@ ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue)
{
MOZ_ASSERT(SnapshotForElement(aElement)->HasAttrs());
#ifdef DEBUG
ServoElementSnapshot* snapshot = Servo_Element_GetSnapshot(aElement);
MOZ_ASSERT_IF(snapshot, snapshot->HasAttrs());
#endif
if (aAttribute == nsGkAtoms::style) {
PostRestyleEvent(aElement, eRestyle_StyleAttribute, nsChangeHint(0));
}
@ -596,12 +460,4 @@ ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
return NS_OK;
}
ServoElementSnapshot*
ServoRestyleManager::SnapshotForElement(Element* aElement)
{
// NB: aElement is the argument for the construction of the snapshot in the
// not found case.
return mModifiedElements.LookupOrAdd(aElement, aElement);
}
} // namespace mozilla

View File

@ -9,6 +9,7 @@
#include "mozilla/EventStates.h"
#include "mozilla/RestyleManagerBase.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoElementSnapshot.h"
#include "nsChangeHint.h"
#include "nsHashKeys.h"
@ -79,8 +80,8 @@ public:
bool HasPendingRestyles()
{
return !mModifiedElements.IsEmpty() ||
PresContext()->Document()->HasDirtyDescendantsForServo();
Element* root = PresContext()->Document()->GetRootElement();
return root && root->HasDirtyDescendantsForServo();
}
@ -94,37 +95,33 @@ public:
nsIAtom* aPseudoTagOrNull);
/**
* Clears the ServoNodeData from all content nodes in the subtree rooted
* at aContent, and sets the IsDirtyForServo bit and clears the
* HasDirtyDescendantsForServo bit on them too.
* Clears the ServoElementData and HasDirtyDescendants from all elements
* in the subtree rooted at aElement.
*/
static void ClearServoDataFromSubtree(nsIContent* aContent);
protected:
~ServoRestyleManager() {}
private:
ServoElementSnapshot* SnapshotForElement(Element* aElement);
static void ClearServoDataFromSubtree(Element* aElement);
/**
* The element-to-element snapshot table to compute restyle hints.
* Clears HasDirtyDescendants from all elements in the subtree rooted at
* aElement.
*/
nsClassHashtable<nsRefPtrHashKey<Element>, ServoElementSnapshot>
mModifiedElements;
static void ClearDirtyDescendantsFromSubtree(Element* aElement);
protected:
~ServoRestyleManager() { MOZ_ASSERT(!mReentrantChanges); }
private:
/**
* Traverses a tree of content that Servo has just restyled, recreating style
* contexts for their frames with the new style data.
*/
void RecreateStyleContexts(nsIContent* aContent,
void RecreateStyleContexts(Element* aElement,
nsStyleContext* aParentContext,
ServoStyleSet* aStyleSet,
nsStyleChangeList& aChangeList);
/**
* Marks the tree with the appropriate dirty flags for the given restyle hint.
*/
static void NoteRestyleHint(Element* aElement, nsRestyleHint aRestyleHint);
void RecreateStyleContextsForText(nsIContent* aTextNode,
nsStyleContext* aParentContext,
ServoStyleSet* aStyleSet);
inline ServoStyleSet* StyleSet() const
{
@ -133,6 +130,19 @@ private:
"style backend");
return PresContext()->StyleSet()->AsServo();
}
// We use a separate data structure from nsStyleChangeList because we need a
// frame to create nsStyleChangeList entries, and the primary frame may not be
// attached yet.
struct ReentrantChange {
nsCOMPtr<nsIContent> mContent;
nsChangeHint mHint;
};
typedef AutoTArray<ReentrantChange, 10> ReentrantChangeList;
// Only non-null while processing change hints. See the comment in
// ProcessPendingRestyles.
ReentrantChangeList* mReentrantChanges;
};
} // namespace mozilla

View File

@ -2429,7 +2429,9 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
// do so for the construction of a style context for an element.)
RefPtr<nsStyleContext> styleContext;
styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
nullptr);
nullptr,
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Allow);
const nsStyleDisplay* display = styleContext->StyleDisplay();
@ -2464,11 +2466,19 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
// don't do so for the construction of a style context for an
// element.)
styleContext = mPresShell->StyleSet()->ResolveStyleFor(aDocElement,
nullptr);
nullptr,
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Allow);
display = styleContext->StyleDisplay();
}
}
// We delay traversing the entire document until here, since we per above we
// may invalidate the root style when we load doc stylesheets.
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
set->StyleDocument();
}
// --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
NS_ASSERTION(!display->IsScrollableOverflow() ||
@ -5022,10 +5032,14 @@ nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
if (aState) {
result = styleSet->ResolveStyleFor(aContent->AsElement(),
aParentStyleContext,
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Assert,
aState->mTreeMatchContext);
} else {
result = styleSet->ResolveStyleFor(aContent->AsElement(),
aParentStyleContext);
aParentStyleContext,
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Assert);
}
} else {
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
@ -5713,6 +5727,11 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
aState.AddPendingBinding(newPendingBinding.forget());
}
if (aContent->IsStyledByServo()) {
NS_WARNING("stylo: Skipping Unsupported binding re-resolve. This needs fixing.");
resolveStyle = false;
}
if (resolveStyle) {
styleContext =
ResolveStyleContext(styleContext->GetParent(), aContent, &aState);
@ -7342,9 +7361,28 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
if (aAllowLazyConstruction &&
MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
if (aContainer->IsStyledByServo()) {
aContainer->AsElement()->NoteDirtyDescendantsForServo();
}
return NS_OK;
}
// We couldn't construct lazily. Make Servo eagerly traverse the subtree.
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
// We use the same codepaths to handle both of the following cases:
// (a) Newly-appended content for which lazy frame construction is disallowed.
// (b) Lazy frame construction driven by the restyle manager.
// We need the styles for (a). In the case of (b), the Servo traversal has
// already happened, so we don't need to do it again.
if (!RestyleManager()->AsBase()->IsInStyleRefresh()) {
if (aFirstNewContent->GetNextSibling()) {
set->StyleNewChildren(aContainer);
} else {
set->StyleNewSubtree(aFirstNewContent);
}
}
}
LAYOUT_PHASE_TEMP_EXIT();
InsertionPoint insertion =
GetRangeInsertionPoint(aContainer, aFirstNewContent, nullptr,
@ -7787,10 +7825,25 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
if (aAllowLazyConstruction &&
MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
if (aContainer->IsStyledByServo()) {
aContainer->AsElement()->NoteDirtyDescendantsForServo();
}
return NS_OK;
}
}
// We couldn't construct lazily. Make Servo eagerly traverse the subtree.
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
// We use the same codepaths to handle both of the following cases:
// (a) Newly-appended content for which lazy frame construction is disallowed.
// (b) Lazy frame construction driven by the restyle manager.
// We need the styles for (a). In the case of (b), the Servo traversal has
// already happened, so we don't need to do it again.
if (!RestyleManager()->AsBase()->IsInStyleRefresh()) {
set->StyleNewSubtree(aStartChild);
}
}
InsertionPoint insertion;
if (isSingleInsert) {
// See if we have an XBL insertion point. If so, then that's our
@ -9255,7 +9308,9 @@ nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
// The parent has a frame, so try resolving a new context.
RefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
ResolveStyleFor(aElement, oldContext->GetParent());
ResolveStyleFor(aElement, oldContext->GetParent(),
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Assert);
if (oldDisplay == StyleDisplay::None) {
ChangeUndisplayedContent(aElement, newContext);
@ -10627,14 +10682,15 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
// This happens when a native anonymous node is used to implement a
// pseudo-element. Allowing Servo to traverse these nodes would be wasted
// work, so assert that we didn't do that.
MOZ_ASSERT_IF(content->IsStyledByServo(), !content->HasServoData());
MOZ_ASSERT_IF(content->IsStyledByServo(),
!content->IsElement() || !content->AsElement()->HasServoData());
styleContext = aAnonymousItems[i].mStyleContext.forget();
} else {
// If we don't have an explicit style context, that means we need the
// ordinary computed values. Make sure we eagerly cascaded them when the
// anonymous nodes were created.
MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
content->HasServoData());
content->AsElement()->HasServoData());
styleContext = ResolveStyleContext(aFrame, content, &aState);
}

View File

@ -17,6 +17,8 @@ struct nsCSSSelector;
// Defines for various style related constants
enum nsChangeHint {
nsChangeHint_Empty = 0,
// change was visual only (e.g., COLOR=)
// Invalidates all descendant frames (including following
// placeholders to out-of-flow frames).

View File

@ -6,6 +6,7 @@
/* container for a document and its presentation */
#include "mozilla/ServoRestyleManager.h"
#include "mozilla/ServoStyleSet.h"
#include "nsAutoPtr.h"
#include "nscore.h"
@ -4469,6 +4470,15 @@ NS_IMETHODIMP nsDocumentViewer::SetPageMode(bool aPageMode, nsIPrintSettings* aP
mViewManager = nullptr;
mWindow = nullptr;
// We're creating a new presentation context for an existing document.
// Drop any associated Servo data.
#ifdef MOZ_STYLO
Element* root = mDocument->GetRootElement();
if (root && root->IsStyledByServo()) {
ServoRestyleManager::ClearServoDataFromSubtree(root);
}
#endif
NS_ENSURE_STATE(mDocument);
if (aPageMode)
{

View File

@ -1384,7 +1384,9 @@ GetPropagatedScrollbarStylesForViewport(nsPresContext* aPresContext,
// Check the style on the document root element
StyleSetHandle styleSet = aPresContext->StyleSet();
RefPtr<nsStyleContext> rootStyle;
rootStyle = styleSet->ResolveStyleFor(docElement, nullptr);
rootStyle = styleSet->ResolveStyleFor(docElement, nullptr,
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
if (CheckOverflow(rootStyle->StyleDisplay(), aStyles)) {
// tell caller we stole the overflow style from the root element
return docElement;
@ -1412,7 +1414,9 @@ GetPropagatedScrollbarStylesForViewport(nsPresContext* aPresContext,
}
RefPtr<nsStyleContext> bodyStyle;
bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle);
bodyStyle = styleSet->ResolveStyleFor(bodyElement->AsElement(), rootStyle,
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
if (CheckOverflow(bodyStyle->StyleDisplay(), aStyles)) {
// tell caller we stole the overflow style from the body element

View File

@ -1692,17 +1692,6 @@ PresShell::Initialize(nscoord aWidth, nscoord aHeight)
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
if (mStyleSet->IsServo() && mDocument->GetRootElement()) {
// If we have the root element already, go ahead style it along with any
// descendants.
//
// Some things, like nsDocumentViewer::GetPageMode, recreate the PresShell
// while keeping the content tree alive (see bug 1292280) - so we
// unconditionally mark the root as dirty.
mDocument->GetRootElement()->SetIsDirtyForServo();
mStyleSet->AsServo()->StyleDocument(/* aLeaveDirtyBits = */ false);
}
// Get the root frame from the frame manager
// XXXbz it would be nice to move this somewhere else... like frame manager
// Init(), say. But we need to make sure our views are all set up by the

View File

@ -302,7 +302,9 @@ nsHTMLFramesetFrame::Init(nsIContent* aContent,
RefPtr<nsStyleContext> kidSC;
kidSC = shell->StyleSet()->ResolveStyleFor(child->AsElement(),
mStyleContext);
mStyleContext,
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
if (child->IsHTMLElement(nsGkAtoms::frameset)) {
frame = NS_NewHTMLFramesetFrame(shell, kidSC);

View File

@ -2058,7 +2058,9 @@ nsImageFrame::GetCursor(const nsPoint& aPoint,
// specified will inherit the style from the image.
RefPtr<nsStyleContext> areaStyle =
PresContext()->PresShell()->StyleSet()->
ResolveStyleFor(area->AsElement(), StyleContext());
ResolveStyleFor(area->AsElement(), StyleContext(),
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
FillCursorInformationFromStyle(areaStyle->StyleUserInterface(),
aCursor);
if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {

View File

@ -18,8 +18,8 @@
* before including this file.
*/
// Node data
SERVO_BINDING_FUNC(Servo_Node_ClearNodeData, void, RawGeckoNodeBorrowed node)
// Element data
SERVO_BINDING_FUNC(Servo_Element_ClearData, void, RawGeckoElementBorrowed node)
// Styleset and Stylesheet management
SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
@ -133,8 +133,6 @@ SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
const nsACString* name, const nsACString* value)
// Computed style data
SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong,
RawGeckoNodeBorrowed node)
SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
ServoComputedValuesStrong,
ServoComputedValuesBorrowedOrNull parent_style_or_null,
@ -156,14 +154,26 @@ SERVO_BINDING_FUNC(Servo_Initialize, void)
// Shut down Servo components. Should be called exactly once at shutdown.
SERVO_BINDING_FUNC(Servo_Shutdown, void)
// Restyle hints
SERVO_BINDING_FUNC(Servo_ComputeRestyleHint, nsRestyleHint,
RawGeckoElementBorrowed element, ServoElementSnapshot* snapshot,
RawServoStyleSetBorrowed set)
// Gets the snapshot for the element. This will return null if the element
// has never been styled, since snapshotting in that case is wasted work.
SERVO_BINDING_FUNC(Servo_Element_GetSnapshot, ServoElementSnapshot*,
RawGeckoElementBorrowed element)
// Restyle and change hints.
SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
nsRestyleHint restyle_hint, nsChangeHint change_hint)
SERVO_BINDING_FUNC(Servo_CheckChangeHint, nsChangeHint, RawGeckoElementBorrowed element)
SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoComputedValuesStrong,
RawGeckoElementBorrowed element, RawServoStyleSetBorrowed set,
mozilla::ConsumeStyleBehavior consume, mozilla::LazyComputeBehavior compute)
// Restyle the given subtree.
SERVO_BINDING_FUNC(Servo_RestyleSubtree, void,
RawGeckoNodeBorrowed node, RawServoStyleSetBorrowed set)
SERVO_BINDING_FUNC(Servo_TraverseSubtree, void,
RawGeckoElementBorrowed root, RawServoStyleSetBorrowed set,
mozilla::SkipRootBehavior skip_root)
// Assert that the tree has no pending or unconsumed restyles.
SERVO_BINDING_FUNC(Servo_AssertTreeIsClean, void, RawGeckoElementBorrowed root)
// Style-struct management.
#define STYLE_STRUCT(name, checkdata_cb) \

View File

@ -18,6 +18,7 @@ struct RawServoDeclarationBlock;
struct RawServoStyleRule;
namespace mozilla {
class ServoElementSnapshot;
namespace dom {
class Element;
class StyleChildrenIterator;
@ -29,6 +30,7 @@ class nsIDocument;
class nsINode;
using mozilla::dom::StyleChildrenIterator;
using mozilla::ServoElementSnapshot;
typedef nsINode RawGeckoNode;
typedef mozilla::dom::Element RawGeckoElement;
@ -85,6 +87,7 @@ DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
DECL_OWNED_REF_TYPE_FOR(ServoElementSnapshot)
// We don't use BorrowedMut because the nodes may alias
// Servo itself doesn't directly read or mutate these;
@ -98,6 +101,7 @@ DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoElement)
DECL_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
DECL_BORROWED_MUT_REF_TYPE_FOR(StyleChildrenIterator)
DECL_BORROWED_MUT_REF_TYPE_FOR(ServoElementSnapshot)
DECL_BORROWED_REF_TYPE_FOR(nsCSSValue)
DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSValue)

View File

@ -97,8 +97,7 @@ Gecko_GetNextSibling(RawGeckoNodeBorrowed aNode)
RawGeckoElementBorrowedOrNull
Gecko_GetParentElement(RawGeckoElementBorrowed aElement)
{
nsINode* parentNode = aElement->GetFlattenedTreeParentNode();
return parentNode->IsElement() ? parentNode->AsElement() : nullptr;
return aElement->GetFlattenedTreeParentElement();
}
RawGeckoElementBorrowedOrNull
@ -275,45 +274,18 @@ Gecko_CalcStyleDifference(nsStyleContext* aOldStyleContext,
return result;
}
void
Gecko_StoreStyleDifference(RawGeckoNodeBorrowed aNode, nsChangeHint aChangeHintToStore)
ServoElementSnapshotOwned
Gecko_CreateElementSnapshot(RawGeckoElementBorrowed aElement)
{
#ifdef MOZ_STYLO
MOZ_ASSERT(aNode->IsElement());
MOZ_ASSERT(aNode->IsDirtyForServo(),
"Change hint stored in a not-dirty node");
return new ServoElementSnapshot(aElement);
}
const Element* aElement = aNode->AsElement();
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (!primaryFrame) {
// If there's no primary frame, that means that either this content is
// undisplayed (so we only need to check at the restyling phase for the
// display value on the element), or is a display: contents element.
//
// In this second case, we should store it in the frame constructor display
// contents map. Note that while this operation looks hairy, this would be
// thread-safe because the content should be there already (we'd only need
// to read the map and modify our entry).
//
// That being said, we still don't support display: contents anyway, so it's
// probably not worth it to do all the roundtrip just yet until we have a
// more concrete plan.
return;
}
if ((aChangeHintToStore & nsChangeHint_ReconstructFrame) &&
aNode->IsInNativeAnonymousSubtree())
{
NS_WARNING("stylo: Removing forbidden frame reconstruction hint on native "
"anonymous content. Fix this in bug 1297857!");
aChangeHintToStore &= ~nsChangeHint_ReconstructFrame;
}
primaryFrame->StyleContext()->StoreChangeHint(aChangeHintToStore);
#else
MOZ_CRASH("stylo: Shouldn't call Gecko_StoreStyleDifference in "
"non-stylo build");
#endif
void
Gecko_DropElementSnapshot(ServoElementSnapshotOwned aSnapshot)
{
MOZ_ASSERT(NS_IsMainThread(),
"ServoAttrSnapshots can only be dropped on the main thread");
delete aSnapshot;
}
RawServoDeclarationBlockStrongBorrowedOrNull
@ -581,7 +553,7 @@ ClassOrClassList(Implementor* aElement, nsIAtom** aClass, nsIAtom*** aClassList)
}
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, ServoElementSnapshot*)
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, const ServoElementSnapshot*)
#undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS

View File

@ -138,7 +138,7 @@ nsIAtom* Gecko_GetElementId(RawGeckoElementBorrowed element);
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
ServoElementSnapshot*)
const ServoElementSnapshot*)
#undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
@ -220,17 +220,16 @@ void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
// Incremental restyle.
// TODO: We would avoid a few ffi calls if we decide to make an API like the
// former CalcAndStoreStyleDifference, but that would effectively mean breaking
// some safety guarantees in the servo side.
//
// Also, we might want a ComputedValues to ComputedValues API for animations?
// Not if we do them in Gecko...
nsStyleContext* Gecko_GetStyleContext(RawGeckoNodeBorrowed node,
nsIAtom* aPseudoTagOrNull);
nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
ServoComputedValuesBorrowed newstyle);
void Gecko_StoreStyleDifference(RawGeckoNodeBorrowed node, nsChangeHint change);
// Element snapshot.
ServoElementSnapshotOwned Gecko_CreateElementSnapshot(RawGeckoElementBorrowed element);
void Gecko_DropElementSnapshot(ServoElementSnapshotOwned snapshot);
// `array` must be an nsTArray
// If changing this signature, please update the

View File

@ -11,18 +11,22 @@
namespace mozilla {
ServoElementSnapshot::ServoElementSnapshot(Element* aElement)
ServoElementSnapshot::ServoElementSnapshot(const Element* aElement)
: mContains(Flags(0))
, mState(0)
, mExplicitRestyleHint(nsRestyleHint(0))
, mExplicitChangeHint(nsChangeHint(0))
{
MOZ_COUNT_CTOR(ServoElementSnapshot);
mIsHTMLElementInHTMLDocument =
aElement->IsHTMLElement() && aElement->IsInHTMLDocument();
mIsInChromeDocument =
nsContentUtils::IsChromeDoc(aElement->OwnerDoc());
}
ServoElementSnapshot::~ServoElementSnapshot()
{
MOZ_COUNT_DTOR(ServoElementSnapshot);
}
void
ServoElementSnapshot::AddAttrs(Element* aElement)
{

View File

@ -67,7 +67,8 @@ class ServoElementSnapshot
public:
typedef ServoElementSnapshotFlags Flags;
explicit ServoElementSnapshot(Element* aElement);
explicit ServoElementSnapshot(const Element* aElement);
~ServoElementSnapshot();
bool HasAttrs() { return HasAny(Flags::Attributes); }
@ -89,20 +90,6 @@ public:
*/
void AddAttrs(Element* aElement);
void AddExplicitChangeHint(nsChangeHint aMinChangeHint)
{
mExplicitChangeHint |= aMinChangeHint;
}
void AddExplicitRestyleHint(nsRestyleHint aRestyleHint)
{
mExplicitRestyleHint |= aRestyleHint;
}
nsRestyleHint ExplicitRestyleHint() { return mExplicitRestyleHint; }
nsChangeHint ExplicitChangeHint() { return mExplicitChangeHint; }
/**
* Needed methods for attribute matching.
*/
@ -158,8 +145,6 @@ private:
Flags mContains;
nsTArray<ServoAttrSnapshot> mAttrs;
ServoStateType mState;
nsRestyleHint mExplicitRestyleHint;
nsChangeHint mExplicitChangeHint;
bool mIsHTMLElementInHTMLDocument;
bool mIsInChromeDocument;
};

View File

@ -89,20 +89,26 @@ ServoStyleSet::EndUpdate()
already_AddRefed<nsStyleContext>
ServoStyleSet::ResolveStyleFor(Element* aElement,
nsStyleContext* aParentContext)
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute)
{
return GetContext(aElement, aParentContext, nullptr,
CSSPseudoElementType::NotPseudo);
CSSPseudoElementType::NotPseudo, aConsume, aMayCompute);
}
already_AddRefed<nsStyleContext>
ServoStyleSet::GetContext(nsIContent* aContent,
nsStyleContext* aParentContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType)
CSSPseudoElementType aPseudoType,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute)
{
MOZ_ASSERT(aContent->IsElement());
Element* element = aContent->AsElement();
RefPtr<ServoComputedValues> computedValues =
Servo_ComputedValues_Get(aContent).Consume();
Servo_ResolveStyle(element, mRawSet.get(), aConsume, aMayCompute).Consume();
MOZ_ASSERT(computedValues);
return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
}
@ -126,12 +132,14 @@ ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
already_AddRefed<nsStyleContext>
ServoStyleSet::ResolveStyleFor(Element* aElement,
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext)
{
// aTreeMatchContext is used to speed up selector matching,
// but if the element already has a ServoComputedValues computed in
// advance, then we shouldn't need to use it.
return ResolveStyleFor(aElement, aParentContext);
return ResolveStyleFor(aElement, aParentContext, aConsume, aMayCompute);
}
already_AddRefed<nsStyleContext>
@ -437,58 +445,39 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
return nsRestyleHint(0);
}
nsRestyleHint
ServoStyleSet::ComputeRestyleHint(dom::Element* aElement,
ServoElementSnapshot* aSnapshot)
{
return Servo_ComputeRestyleHint(aElement, aSnapshot, mRawSet.get());
}
static void
ClearDirtyBits(nsIContent* aContent)
{
bool traverseDescendants = aContent->HasDirtyDescendantsForServo();
aContent->UnsetIsDirtyAndHasDirtyDescendantsForServo();
if (!traverseDescendants) {
return;
}
StyleChildrenIterator it(aContent);
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
ClearDirtyBits(n);
}
}
void
ServoStyleSet::StyleDocument(bool aLeaveDirtyBits)
ServoStyleSet::StyleDocument()
{
// Grab the root.
nsIDocument* doc = mPresContext->Document();
nsIContent* root = doc->GetRootElement();
Element* root = doc->GetRootElement();
MOZ_ASSERT(root);
// Restyle the document, clearing the dirty bits if requested.
Servo_RestyleSubtree(root, mRawSet.get());
if (!aLeaveDirtyBits) {
ClearDirtyBits(root);
doc->UnsetHasDirtyDescendantsForServo();
}
// Restyle the document.
Servo_TraverseSubtree(root, mRawSet.get(), SkipRootBehavior::DontSkip);
}
void
ServoStyleSet::StyleNewSubtree(nsIContent* aContent)
{
MOZ_ASSERT(aContent->IsDirtyForServo());
if (aContent->IsElement() || aContent->IsNodeOfType(nsINode::eTEXT)) {
Servo_RestyleSubtree(aContent, mRawSet.get());
if (aContent->IsElement()) {
Servo_TraverseSubtree(aContent->AsElement(), mRawSet.get(), SkipRootBehavior::DontSkip);
}
ClearDirtyBits(aContent);
}
void
ServoStyleSet::StyleNewChildren(nsIContent* aParent)
{
MOZ_ASSERT(aParent->HasDirtyDescendantsForServo());
Servo_RestyleSubtree(aParent, mRawSet.get());
ClearDirtyBits(aParent);
MOZ_ASSERT(aParent->IsElement());
Servo_TraverseSubtree(aParent->AsElement(), mRawSet.get(), SkipRootBehavior::Skip);
}
#ifdef DEBUG
void
ServoStyleSet::AssertTreeIsClean()
{
if (Element* root = mPresContext->Document()->GetRootElement()) {
Servo_AssertTreeIsClean(root);
}
}
#endif

View File

@ -56,11 +56,15 @@ public:
already_AddRefed<nsStyleContext>
ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext);
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute);
already_AddRefed<nsStyleContext>
ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext);
already_AddRefed<nsStyleContext>
@ -117,20 +121,11 @@ public:
dom::Element* aElement, mozilla::CSSPseudoElementType aPseudoType,
dom::Element* aPseudoElement, EventStates aStateMask);
/**
* Computes a restyle hint given a element and a previous element snapshot.
*/
nsRestyleHint ComputeRestyleHint(dom::Element* aElement,
ServoElementSnapshot* aSnapshot);
/**
* Performs a Servo traversal to compute style for all dirty nodes in the
* document. The root element must be non-null.
*
* If aLeaveDirtyBits is true, the dirty/dirty-descendant bits are not
* cleared.
*/
void StyleDocument(bool aLeaveDirtyBits);
void StyleDocument();
/**
* Eagerly styles a subtree of dirty nodes that were just appended to the
@ -152,6 +147,12 @@ public:
*/
void StyleNewChildren(nsIContent* aParent);
#ifdef DEBUG
void AssertTreeIsClean();
#else
void AssertTreeIsClean() {}
#endif
private:
already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
nsStyleContext* aParentContext,
@ -161,7 +162,9 @@ private:
already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent,
nsStyleContext* aParentContext,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType);
CSSPseudoElementType aPseudoType,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute);
nsPresContext* mPresContext;
UniquePtr<RawServoStyleSet> mRawSet;

View File

@ -35,6 +35,29 @@ struct ServoCell {
ServoCell() : value() {};
};
// Indicates whether a style resolution should be considered to consume the style
// for the construction of a layout frame, or whether the caller is just
// peeking.
enum class ConsumeStyleBehavior {
Consume,
DontConsume,
};
// Indicates whether the Servo style system should expect the style on an element
// to have already been resolved (i.e. via a parallel traversal), or whether it
// may be lazily computed.
enum class LazyComputeBehavior {
Allow,
Assert,
};
// Indicates whether the Servo style system should skip processing on the root
// element and start processing with its children.
enum class SkipRootBehavior {
Skip,
DontSkip,
};
} // namespace mozilla
#endif // mozilla_ServoTypes_h

View File

@ -9,6 +9,7 @@
#include "mozilla/EventStates.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/SheetType.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
@ -114,10 +115,14 @@ public:
inline nsresult EndUpdate();
inline already_AddRefed<nsStyleContext>
ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext);
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute);
inline already_AddRefed<nsStyleContext>
ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext);
inline already_AddRefed<nsStyleContext>
ResolveStyleForText(nsIContent* aTextNode,

View File

@ -79,17 +79,21 @@ StyleSetHandle::Ptr::EndUpdate()
// resolve a style context
already_AddRefed<nsStyleContext>
StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext)
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute)
{
FORWARD(ResolveStyleFor, (aElement, aParentContext));
FORWARD(ResolveStyleFor, (aElement, aParentContext, aConsume, aMayCompute));
}
already_AddRefed<nsStyleContext>
StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
nsStyleContext* aParentContext,
ConsumeStyleBehavior aConsume,
LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext)
{
FORWARD(ResolveStyleFor, (aElement, aParentContext, aTreeMatchContext));
FORWARD(ResolveStyleFor, (aElement, aParentContext, aConsume, aMayCompute, aTreeMatchContext));
}
already_AddRefed<nsStyleContext>

View File

@ -495,7 +495,8 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
pseudoElement);
} else {
sc = styleSet->ResolveStyleFor(aElement, parentContext);
sc = styleSet->ResolveStyleFor(aElement, parentContext, ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
}
if (aStyleType == eDefaultOnly) {

View File

@ -563,8 +563,8 @@ static nscoord CalcLengthWith(const nsCSSValue& aValue,
if (rootFrame) {
rootStyle = rootFrame->StyleContext();
} else {
rootStyle = aPresContext->StyleSet()->ResolveStyleFor(docElement,
nullptr);
rootStyle = aPresContext->StyleSet()->AsGecko()->ResolveStyleFor(docElement,
nullptr);
}
rootStyleFont = rootStyle->StyleFont();
}

View File

@ -91,12 +91,6 @@ nsStyleContext::nsStyleContext(nsStyleContext* aParent,
, mCachedResetData(nullptr)
, mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
, mRefCnt(0)
#ifdef MOZ_STYLO
, mStoredChangeHint(nsChangeHint(0))
#ifdef DEBUG
, mConsumedChangeHint(false)
#endif
#endif
#ifdef DEBUG
, mFrameRefCnt(0)
, mComputingStruct(nsStyleStructID_None)
@ -796,7 +790,7 @@ nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
mozilla::dom::Element* docElement = presContext->Document()->GetRootElement();
if (docElement) {
RefPtr<nsStyleContext> rootStyle =
presContext->StyleSet()->ResolveStyleFor(docElement, nullptr);
presContext->StyleSet()->AsGecko()->ResolveStyleFor(docElement, nullptr);
auto dir = rootStyle->StyleVisibility()->mDirection;
if (dir != StyleVisibility()->mDirection) {
nsStyleVisibility* uniqueVisibility = GET_UNIQUE_STYLE_DATA(Visibility);

View File

@ -512,45 +512,6 @@ public:
mozilla::NonOwningStyleContextSource StyleSource() const { return mSource.AsRaw(); }
#ifdef MOZ_STYLO
// NOTE: It'd be great to assert here that the previous change hint is always
// consumed.
//
// This is not the case right now, since the changes of childs of frames that
// go through frame construction are not consumed.
void StoreChangeHint(nsChangeHint aHint)
{
MOZ_ASSERT(!IsShared());
mStoredChangeHint = aHint;
#ifdef DEBUG
mConsumedChangeHint = false;
#endif
}
nsChangeHint ConsumeStoredChangeHint()
{
MOZ_ASSERT(!mConsumedChangeHint, "Re-consuming the same change hint!");
nsChangeHint result = mStoredChangeHint;
mStoredChangeHint = nsChangeHint(0);
#ifdef DEBUG
mConsumedChangeHint = true;
#endif
return result;
}
#else
void StoreChangeHint(nsChangeHint aHint)
{
MOZ_CRASH("stylo: Called nsStyleContext::StoreChangeHint in a non MOZ_STYLO "
"build.");
}
nsChangeHint ConsumeStoredChangeHint()
{
MOZ_CRASH("stylo: Called nsStyleContext::ComsumeStoredChangeHint in a non "
"MOZ_STYLO build.");
}
#endif
private:
// Private destructor, to discourage deletion outside of Release():
~nsStyleContext();
@ -809,15 +770,6 @@ private:
uint32_t mRefCnt;
// For now we store change hints on the style context during parallel traversal.
// We should improve this - see bug 1289861.
#ifdef MOZ_STYLO
nsChangeHint mStoredChangeHint;
#ifdef DEBUG
bool mConsumedChangeHint;
#endif
#endif
#ifdef DEBUG
uint32_t mFrameRefCnt; // number of frames that use this
// as their style context

View File

@ -17,6 +17,7 @@
#include "mozilla/EnumeratedArray.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoTypes.h"
#include "mozilla/SheetType.h"
#include "nsIStyleRuleProcessor.h"
@ -112,11 +113,30 @@ class nsStyleSet final
ResolveStyleFor(mozilla::dom::Element* aElement,
nsStyleContext* aParentContext);
already_AddRefed<nsStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
nsStyleContext* aParentContext,
mozilla::ConsumeStyleBehavior,
mozilla::LazyComputeBehavior)
{
return ResolveStyleFor(aElement, aParentContext);
}
already_AddRefed<nsStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
nsStyleContext* aParentContext,
TreeMatchContext& aTreeMatchContext);
already_AddRefed<nsStyleContext>
ResolveStyleFor(mozilla::dom::Element* aElement,
nsStyleContext* aParentContext,
mozilla::ConsumeStyleBehavior aConsume,
mozilla::LazyComputeBehavior aMayCompute,
TreeMatchContext& aTreeMatchContext)
{
return ResolveStyleFor(aElement, aParentContext, aTreeMatchContext);
}
// Get a style context (with the given parent) for the
// sequence of style rules in the |aRules| array.
already_AddRefed<nsStyleContext>

View File

@ -702,7 +702,9 @@ nsListBoxBodyFrame::ComputeIntrinsicISize(nsBoxLayoutState& aBoxLayoutState)
RefPtr<nsStyleContext> styleContext;
nsPresContext *presContext = aBoxLayoutState.PresContext();
styleContext = presContext->StyleSet()->
ResolveStyleFor(firstRowContent->AsElement(), nullptr);
ResolveStyleFor(firstRowContent->AsElement(), nullptr,
ConsumeStyleBehavior::DontConsume,
LazyComputeBehavior::Allow);
nscoord width = 0;
nsMargin margin(0,0,0,0);

View File

@ -286,7 +286,9 @@ nsSplitterFrame::Init(nsIContent* aContent,
NS_LITERAL_STRING("vertical"), false);
nsStyleContext* parentStyleContext = StyleContext()->GetParent();
RefPtr<nsStyleContext> newContext = PresContext()->StyleSet()->
ResolveStyleFor(aContent->AsElement(), parentStyleContext);
ResolveStyleFor(aContent->AsElement(), parentStyleContext,
ConsumeStyleBehavior::Consume,
LazyComputeBehavior::Allow);
SetStyleContextWithoutNotification(newContext);
}
}