зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1286445: stylo: Support restyles of non-pseudo content on state change. r=heycam
This includes, for example :hover. Also removes the call to IsStyledByServo() in the document constructor, it's not only unnecessary, but also we call UpdateStyleBackendType() too early. MozReview-Commit-ID: 4YfCdmLoSxu
This commit is contained in:
Родитель
2adb931c36
Коммит
1a49c35a07
|
@ -1459,9 +1459,6 @@ nsIDocument::nsIDocument()
|
|||
mUserHasInteracted(false)
|
||||
{
|
||||
SetIsDocument();
|
||||
if (IsStyledByServo()) {
|
||||
SetFlags(NODE_IS_DIRTY_FOR_SERVO | NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
|
||||
}
|
||||
|
||||
PR_INIT_CLIST(&mDOMMediaQueryLists);
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem
|
|||
#endif
|
||||
|
||||
if (servoStyleSet) {
|
||||
servoStyleSet->RestyleSubtree(child);
|
||||
servoStyleSet->RestyleSubtree(child, /* aForce = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,26 @@ ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::Disconnect()
|
||||
/* static */ void
|
||||
ServoRestyleManager::DirtyTree(nsIContent* aContent)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::Disconnect not implemented");
|
||||
if (aContent->IsDirtyForServo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
aContent->SetIsDirtyForServo();
|
||||
|
||||
FlattenedChildIterator it(aContent);
|
||||
|
||||
nsIContent* n = it.GetNextChild();
|
||||
bool hadChildren = bool(n);
|
||||
for ( ; n; n = it.GetNextChild()) {
|
||||
DirtyTree(n);
|
||||
}
|
||||
|
||||
if (hadChildren) {
|
||||
aContent->SetHasDirtyDescendantsForServo();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -32,13 +48,21 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aRestyleHint == 0 && !aMinChangeHint) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* presShell = PresContext()->PresShell();
|
||||
if (!ObservingRefreshDriver()) {
|
||||
SetObservingRefreshDriver(PresContext()->RefreshDriver()->
|
||||
AddStyleFlushObserver(presShell));
|
||||
}
|
||||
|
||||
aElement->SetIsDirtyForServo();
|
||||
// Propagate the IS_DIRTY flag down the tree.
|
||||
DirtyTree(aElement);
|
||||
|
||||
// Propagate the HAS_DIRTY_DESCENDANTS flag to the root.
|
||||
nsINode* cur = aElement;
|
||||
while ((cur = cur->GetParentNode())) {
|
||||
if (cur->HasDirtyDescendantsForServo())
|
||||
|
@ -69,10 +93,59 @@ ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
|||
MOZ_CRASH("stylo: ServoRestyleManager::PostRebuildAllStyleDataEvent not implemented");
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
|
||||
nsStyleContext* aParentContext,
|
||||
ServoStyleSet* aStyleSet)
|
||||
{
|
||||
if (!(aContent->IsDirtyForServo() || aContent->HasDirtyDescendantsForServo())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
|
||||
|
||||
// TODO: AFAIK this can happen when we have, let's say, display: none. Here we
|
||||
// should trigger frame construction if the element is actually dirty (I
|
||||
// guess), but we'd better do that once we have all the restyle hints thing
|
||||
// figured out.
|
||||
if (!primaryFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
dont_AddRef(Servo_GetComputedValues(aContent));
|
||||
|
||||
// TODO: Figure out what pseudos does this content have, and do the proper
|
||||
// thing with them.
|
||||
RefPtr<nsStyleContext> context =
|
||||
aStyleSet->GetContext(computedValues.forget(),
|
||||
aParentContext,
|
||||
nullptr,
|
||||
CSSPseudoElementType::NotPseudo);
|
||||
|
||||
// TODO: Compare old and new styles to generate restyle change hints, and
|
||||
// process them.
|
||||
primaryFrame->SetStyleContext(context.get());
|
||||
|
||||
FlattenedChildIterator it(aContent);
|
||||
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
|
||||
RecreateStyleContexts(n, context.get(), aStyleSet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
{
|
||||
// XXXheycam Do nothing for now.
|
||||
ServoStyleSet* styleSet = StyleSet();
|
||||
|
||||
nsIDocument* doc = PresContext()->Document();
|
||||
Element* root = doc->GetRootElement();
|
||||
|
||||
if (root) {
|
||||
styleSet->RestyleSubtree(root, /* aForce = */ false);
|
||||
RecreateStyleContexts(root, nullptr, styleSet);
|
||||
}
|
||||
|
||||
IncrementRestyleGeneration();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,12 @@ namespace mozilla {
|
|||
*/
|
||||
class ServoRestyleManager : public RestyleManagerBase
|
||||
{
|
||||
friend class ServoStyleSet;
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(ServoRestyleManager)
|
||||
|
||||
explicit ServoRestyleManager(nsPresContext* aPresContext);
|
||||
|
||||
void Disconnect();
|
||||
void PostRestyleEvent(dom::Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint);
|
||||
|
@ -72,6 +72,24 @@ protected:
|
|||
~ServoRestyleManager() {}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Traverses a tree of content that Servo has just restyled, recreating style
|
||||
* contexts for their frames with the new style data.
|
||||
*
|
||||
* This is just static so ServoStyleSet can mark this class as friend, so we
|
||||
* can access to the GetContext method without making it available to everyone
|
||||
* else.
|
||||
*/
|
||||
static void RecreateStyleContexts(nsIContent* aContent,
|
||||
nsStyleContext* aParentContext,
|
||||
ServoStyleSet* aStyleSet);
|
||||
|
||||
/**
|
||||
* Propagates the IS_DIRTY flag down to the tree, setting
|
||||
* HAS_DIRTY_DESCENDANTS appropriately.
|
||||
*/
|
||||
static void DirtyTree(nsIContent* aContent);
|
||||
|
||||
inline ServoStyleSet* StyleSet() const {
|
||||
MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
|
||||
"ServoRestyleManager should only be used with a Servo-flavored "
|
||||
|
|
|
@ -4262,7 +4262,7 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
|
|||
if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) {
|
||||
// Eagerly compute styles for the anonymous content tree.
|
||||
for (auto& info : aContent) {
|
||||
styleSet->RestyleSubtree(info.mContent);
|
||||
styleSet->RestyleSubtree(info.mContent, /* aForce = */ true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
*/
|
||||
bool AddStyleFlushObserver(nsIPresShell* aShell) {
|
||||
NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
|
||||
"Double-adding style flush observer");
|
||||
"Double-adding style flush observer");
|
||||
// We only get the cause for the first observer each frame because capturing
|
||||
// a stack is expensive. This is still useful if (1) you're trying to remove
|
||||
// all flushes for a particial frame or (2) the costly flush is triggered
|
||||
|
@ -173,7 +173,7 @@ public:
|
|||
}
|
||||
bool AddLayoutFlushObserver(nsIPresShell* aShell) {
|
||||
NS_ASSERTION(!IsLayoutFlushObserver(aShell),
|
||||
"Double-adding layout flush observer");
|
||||
"Double-adding layout flush observer");
|
||||
// We only get the cause for the first observer each frame because capturing
|
||||
// a stack is expensive. This is still useful if (1) you're trying to remove
|
||||
// all flushes for a particial frame or (2) the costly flush is triggered
|
||||
|
@ -193,7 +193,7 @@ public:
|
|||
}
|
||||
bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
|
||||
NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
|
||||
"Double-adding style flush observer");
|
||||
"Double-adding style flush observer");
|
||||
bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
|
||||
EnsureTimerStarted();
|
||||
return appended;
|
||||
|
@ -288,7 +288,7 @@ public:
|
|||
* Check whether the given observer is an observer for the given flush type
|
||||
*/
|
||||
bool IsRefreshObserver(nsARefreshObserver *aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsIDocumentInlines.h"
|
||||
|
@ -379,7 +380,12 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
|||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::RestyleSubtree(nsINode* aNode)
|
||||
ServoStyleSet::RestyleSubtree(nsINode* aNode, bool aForce)
|
||||
{
|
||||
if (aForce) {
|
||||
MOZ_ASSERT(aNode->IsContent());
|
||||
ServoRestyleManager::DirtyTree(aNode->AsContent());
|
||||
}
|
||||
|
||||
Servo_RestyleSubtree(aNode, mRawSet.get());
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace dom {
|
|||
class Element;
|
||||
} // namespace dom
|
||||
class CSSStyleSheet;
|
||||
class ServoRestyleManager;
|
||||
class ServoStyleSheet;
|
||||
} // namespace mozilla
|
||||
class nsIDocument;
|
||||
|
@ -39,6 +40,7 @@ namespace mozilla {
|
|||
*/
|
||||
class ServoStyleSet
|
||||
{
|
||||
friend class ServoRestyleManager;
|
||||
public:
|
||||
ServoStyleSet();
|
||||
|
||||
|
@ -116,7 +118,13 @@ public:
|
|||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask);
|
||||
|
||||
void RestyleSubtree(nsINode* aNode);
|
||||
/**
|
||||
* Restyles a whole subtree of nodes.
|
||||
*
|
||||
* The aForce parameter propagates the dirty bits down the subtree, and when
|
||||
* used aNode needs to be nsIContent.
|
||||
*/
|
||||
void RestyleSubtree(nsINode* aNode, bool aForce);
|
||||
|
||||
private:
|
||||
already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
|
||||
|
|
Загрузка…
Ссылка в новой задаче