зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1292618: Support basic pseudo-element restyling. r=heycam
:before and :after only, for now. MozReview-Commit-ID: 9hLFvVhqIrN
This commit is contained in:
Родитель
00ab304ee2
Коммит
e7bc43ddc7
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/dom/ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
@ -79,10 +82,10 @@ ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
|
|||
Servo_GetComputedValues(aContent).Consume();
|
||||
MOZ_ASSERT(computedValues);
|
||||
|
||||
nsChangeHint changeHint = nsChangeHint(0);
|
||||
// NB: Change hint processing only applies to elements, at least until we
|
||||
// support display: contents.
|
||||
if (aContent->IsElement()) {
|
||||
nsChangeHint changeHint = nsChangeHint(0);
|
||||
Element* element = aContent->AsElement();
|
||||
|
||||
// Add an explicit change hint if appropriate.
|
||||
|
@ -140,6 +143,36 @@ ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
|
|||
f->SetStyleContext(newContext);
|
||||
}
|
||||
|
||||
// Update pseudo-elements state if appropriate.
|
||||
if (aContent->IsElement()) {
|
||||
Element* aElement = aContent->AsElement();
|
||||
const static CSSPseudoElementType pseudosToRestyle[] = {
|
||||
CSSPseudoElementType::before, CSSPseudoElementType::after,
|
||||
};
|
||||
|
||||
for (CSSPseudoElementType pseudoType : pseudosToRestyle) {
|
||||
nsIAtom* pseudoTag =
|
||||
nsCSSPseudoElements::GetPseudoAtom(pseudoType);
|
||||
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(aElement, pseudoType,
|
||||
newContext);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: There are other continuations we still haven't restyled, mostly
|
||||
// pseudo-elements. We have to deal with those, and with anonymous boxes.
|
||||
aContent->UnsetFlags(NODE_IS_DIRTY_FOR_SERVO);
|
||||
|
@ -187,7 +220,37 @@ MarkChildrenAsDirtyForServo(nsIContent* aContent)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
/* static */ nsIFrame*
|
||||
ServoRestyleManager::FrameForPseudoElement(nsIContent* aContent,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
|
||||
nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
|
||||
|
||||
if (!aPseudoTagOrNull) {
|
||||
return primaryFrame;
|
||||
}
|
||||
|
||||
if (!primaryFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NOTE: we probably need to special-case display: contents here. Gecko's
|
||||
// RestyleManager passes the primary frame of the parent instead.
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
|
||||
return nsLayoutUtils::GetBeforeFrameForContent(primaryFrame, aContent);
|
||||
}
|
||||
|
||||
if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
|
||||
return nsLayoutUtils::GetAfterFrameForContent(primaryFrame, aContent);
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unkown pseudo-element given to "
|
||||
"ServoRestyleManager::FrameForPseudoElement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
|
||||
{
|
||||
const nsRestyleHint HANDLED_RESTYLE_HINTS = eRestyle_Self |
|
||||
|
|
|
@ -77,6 +77,15 @@ public:
|
|||
|
||||
bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); }
|
||||
|
||||
/**
|
||||
* Gets the appropriate frame given a content and a pseudo-element tag.
|
||||
*
|
||||
* Right now only supports a null tag, before or after. If the pseudo-element
|
||||
* is not null, the content needs to be an element.
|
||||
*/
|
||||
static nsIFrame* FrameForPseudoElement(nsIContent* aContent,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
|
||||
protected:
|
||||
~ServoRestyleManager() {}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsDOMTokenList.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
|
@ -24,8 +25,11 @@
|
|||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define IMPL_STRONG_REF_TYPE(name, T) \
|
||||
already_AddRefed<T> name::Consume() { \
|
||||
RefPtr<T> result = dont_AddRef(mPtr); \
|
||||
|
@ -196,15 +200,17 @@ Gecko_UnsetNodeFlags(RawGeckoNode* aNode, uint32_t aFlags)
|
|||
}
|
||||
|
||||
nsStyleContext*
|
||||
Gecko_GetStyleContext(RawGeckoNode* aNode)
|
||||
Gecko_GetStyleContext(RawGeckoNode* aNode, nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
MOZ_ASSERT(aNode->IsContent());
|
||||
nsIFrame* primaryFrame = aNode->AsContent()->GetPrimaryFrame();
|
||||
if (!primaryFrame) {
|
||||
nsIFrame* relevantFrame =
|
||||
ServoRestyleManager::FrameForPseudoElement(aNode->AsContent(),
|
||||
aPseudoTagOrNull);
|
||||
if (!relevantFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return primaryFrame->StyleContext();
|
||||
return relevantFrame->StyleContext();
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
|
@ -727,6 +733,12 @@ Gecko_ClearPODTArray(void* aArray, size_t aElementSize, size_t aElementAlign)
|
|||
aElementSize, aElementAlign);
|
||||
}
|
||||
|
||||
void
|
||||
Gecko_ClearStyleContents(nsStyleContent* aContent)
|
||||
{
|
||||
aContent->AllocateContents(0);
|
||||
}
|
||||
|
||||
void
|
||||
Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen)
|
||||
{
|
||||
|
|
|
@ -214,7 +214,8 @@ void Gecko_UnsetNodeFlags(RawGeckoNode* node, uint32_t flags);
|
|||
//
|
||||
// Also, we might want a ComputedValues to ComputedValues API for animations?
|
||||
// Not if we do them in Gecko...
|
||||
nsStyleContext* Gecko_GetStyleContext(RawGeckoNode* node);
|
||||
nsStyleContext* Gecko_GetStyleContext(RawGeckoNode* node,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
|
||||
ServoComputedValuesBorrowed newstyle);
|
||||
void Gecko_StoreStyleDifference(RawGeckoNode* node, nsChangeHint change);
|
||||
|
@ -230,6 +231,10 @@ void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
|
|||
// otherwise. This is ensured with rust traits for the relevant structs.
|
||||
void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
|
||||
|
||||
// Clear the mContents field in nsStyleContent. This is needed to run the
|
||||
// destructors, otherwise we'd leak the images (though we still don't support
|
||||
// those), strings, and whatnot.
|
||||
void Gecko_ClearStyleContents(nsStyleContent* content);
|
||||
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len);
|
||||
|
||||
void Gecko_InitializeImageLayer(nsStyleImageLayers::Layer* layer,
|
||||
|
|
|
@ -114,8 +114,7 @@ ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
|
|||
bool skipFixup = false;
|
||||
|
||||
return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
|
||||
aPseudoType,
|
||||
Move(aComputedValues), skipFixup);
|
||||
aPseudoType, Move(aComputedValues), skipFixup);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
|
|
Загрузка…
Ссылка в новой задаче