Bug 1292618: Support basic pseudo-element restyling. r=heycam

:before and :after only, for now.

MozReview-Commit-ID: 9hLFvVhqIrN
Signed-off-by: Emilio Cobos Álvarez <ecoal95@gmail.com>
This commit is contained in:
Emilio Cobos Álvarez 2016-08-11 19:01:52 -07:00
parent c043a5d5c5
commit 6ca7e9e4f1
5 changed files with 98 additions and 10 deletions

View File

@ -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 |

View File

@ -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() {}

View File

@ -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)
{
@ -819,7 +831,7 @@ Servo_DropNodeData(ServoNodeData* data)
RawServoStyleSheetStrong
Servo_StylesheetFromUTF8Bytes(const uint8_t* bytes, uint32_t length,
mozilla::css::SheetParsingMode mode,
css::SheetParsingMode mode,
const uint8_t* base_bytes, uint32_t base_length,
ThreadSafeURIHolder* base,
ThreadSafeURIHolder* referrer,

View File

@ -215,7 +215,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);
@ -231,6 +232,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,

View File

@ -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>