зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1317016
- Basic infrastructure for RestyleHint-driven traversal. r=emilio
MozReview-Commit-ID: 7wH5XcILVmX
This commit is contained in:
Родитель
43738b4026
Коммит
f8c9d884fc
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -426,7 +426,6 @@ nsXBLBinding::GenerateAnonymousContent()
|
|||
nsIPresShell* presShell = mBoundElement->OwnerDoc()->GetShell();
|
||||
ServoStyleSet* servoSet = presShell->StyleSet()->GetAsServo();
|
||||
if (servoSet) {
|
||||
mBoundElement->SetHasDirtyDescendantsForServo();
|
||||
servoSet->StyleNewChildren(mBoundElement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,8 @@ public:
|
|||
// itself.
|
||||
nsresult ProcessRestyledFrames(nsStyleChangeList& aChangeList);
|
||||
|
||||
bool IsInStyleRefresh() const { return mInStyleRefresh; }
|
||||
|
||||
protected:
|
||||
void ContentStateChangedInternal(Element* aElement,
|
||||
EventStates aStateMask,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче