зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1287951: stylo: Add support for computing style hints from Servo. r=heycam
MozReview-Commit-ID: ALuJxcfAMuL
This commit is contained in:
Родитель
0f56cc072c
Коммит
253dfd8aad
|
@ -12,6 +12,8 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
#define NS_EVENT_STATE_HIGHEST_SERVO_BIT 6
|
||||
|
||||
/**
|
||||
* EventStates is the class used to represent the event states of nsIContent
|
||||
* instances. These states are calculated by IntrinsicState() and
|
||||
|
@ -23,6 +25,7 @@ class EventStates
|
|||
{
|
||||
public:
|
||||
typedef uint64_t InternalType;
|
||||
typedef uint8_t ServoType;
|
||||
|
||||
constexpr EventStates()
|
||||
: mStates(0)
|
||||
|
@ -155,6 +158,14 @@ public:
|
|||
return mStates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to get the appropriate state representation for Servo.
|
||||
*/
|
||||
ServoType ServoValue() const
|
||||
{
|
||||
return mStates & ((1 << (NS_EVENT_STATE_HIGHEST_SERVO_BIT + 1)) - 1);
|
||||
}
|
||||
|
||||
private:
|
||||
InternalType mStates;
|
||||
};
|
||||
|
@ -200,10 +211,11 @@ private:
|
|||
// Content is in the indeterminate state.
|
||||
#define NS_EVENT_STATE_INDETERMINATE NS_DEFINE_EVENT_STATE_MACRO(6)
|
||||
|
||||
#define NS_EVENT_STATE_HIGHEST_SERVO_BIT 6
|
||||
|
||||
/*
|
||||
* Bits below here do not have Servo-related ordering constraints.
|
||||
*
|
||||
* Remember to change NS_EVENT_STATE_HIGHEST_SERVO_BIT at the top of the file if
|
||||
* this changes!
|
||||
*/
|
||||
|
||||
// Drag is hovering over content.
|
||||
|
|
|
@ -17,20 +17,25 @@ ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
ServoRestyleManager::DirtyTree(nsIContent* aContent)
|
||||
ServoRestyleManager::DirtyTree(nsIContent* aContent, bool aIncludingRoot)
|
||||
{
|
||||
if (aContent->IsDirtyForServo()) {
|
||||
return;
|
||||
}
|
||||
if (aIncludingRoot) {
|
||||
// XXX: This can in theory leave nodes not dirty, but in practice this is not
|
||||
// a problem, at least for now, since right now element dirty implies
|
||||
// descendants dirty. Remove this early return if this ever changes.
|
||||
if (aContent->IsDirtyForServo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
aContent->SetIsDirtyForServo();
|
||||
aContent->SetIsDirtyForServo();
|
||||
}
|
||||
|
||||
FlattenedChildIterator it(aContent);
|
||||
|
||||
nsIContent* n = it.GetNextChild();
|
||||
bool hadChildren = bool(n);
|
||||
for ( ; n; n = it.GetNextChild()) {
|
||||
DirtyTree(n);
|
||||
for (; n; n = it.GetNextChild()) {
|
||||
DirtyTree(n, true);
|
||||
}
|
||||
|
||||
if (hadChildren) {
|
||||
|
@ -48,26 +53,22 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
if (aRestyleHint == 0 && !aMinChangeHint) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) {
|
||||
return; // Nothing to do.
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
nsIPresShell* presShell = PresContext()->PresShell();
|
||||
if (!ObservingRefreshDriver()) {
|
||||
SetObservingRefreshDriver(PresContext()->RefreshDriver()->
|
||||
AddStyleFlushObserver(presShell));
|
||||
}
|
||||
|
||||
// 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())
|
||||
break;
|
||||
cur->SetHasDirtyDescendantsForServo();
|
||||
SetObservingRefreshDriver(
|
||||
PresContext()->RefreshDriver()->AddStyleFlushObserver(presShell));
|
||||
}
|
||||
|
||||
presShell->GetDocument()->SetNeedStyleFlush();
|
||||
|
@ -137,6 +138,50 @@ ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
MarkParentsAsHavingDirtyDescendants(Element* aElement)
|
||||
{
|
||||
nsINode* cur = aElement;
|
||||
while ((cur = cur->GetParentNode())) {
|
||||
if (cur->HasDirtyDescendantsForServo()) {
|
||||
break;
|
||||
}
|
||||
|
||||
cur->SetHasDirtyDescendantsForServo();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
|
||||
{
|
||||
if (aHint & eRestyle_Self) {
|
||||
aElement->SetIsDirtyForServo();
|
||||
MarkParentsAsHavingDirtyDescendants(aElement);
|
||||
// NB: Using Servo's style system marking the subtree as dirty is necessary
|
||||
// so we inherit correctly the style structs.
|
||||
aHint |= eRestyle_Subtree;
|
||||
}
|
||||
|
||||
if (aHint & eRestyle_Subtree) {
|
||||
DirtyTree(aElement, /* aIncludingRoot = */ false);
|
||||
MarkParentsAsHavingDirtyDescendants(aElement);
|
||||
}
|
||||
|
||||
if (aHint & eRestyle_LaterSiblings) {
|
||||
for (nsINode* cur = aElement->GetNextSibling(); cur;
|
||||
cur = cur->GetNextSibling()) {
|
||||
if (cur->IsContent()) {
|
||||
DirtyTree(cur->AsContent(), /* aIncludingRoot = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle all other nsRestyleHint values.
|
||||
if (aHint & ~(eRestyle_Self | eRestyle_Subtree | eRestyle_LaterSiblings)) {
|
||||
NS_ERROR("stylo: Unhandled restyle hint");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
{
|
||||
|
@ -149,10 +194,26 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
|
||||
Element* root = doc->GetRootElement();
|
||||
if (root) {
|
||||
for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) {
|
||||
ServoElementSnapshot* snapshot = iter.UserData();
|
||||
Element* element = iter.Key();
|
||||
|
||||
// TODO: avoid the ComputeRestyleHint call if we already have the highest
|
||||
// explicit restyle hint?
|
||||
nsRestyleHint hint = styleSet->ComputeRestyleHint(element, snapshot);
|
||||
hint |= snapshot->ExplicitRestyleHint();
|
||||
|
||||
if (hint) {
|
||||
NoteRestyleHint(element, hint);
|
||||
}
|
||||
}
|
||||
|
||||
styleSet->RestyleSubtree(root, /* aForce = */ false);
|
||||
RecreateStyleContexts(root, nullptr, styleSet);
|
||||
}
|
||||
|
||||
mModifiedElements.Clear();
|
||||
|
||||
// NB: we restyle from the root element, but the document also gets the
|
||||
// HAS_DIRTY_DESCENDANTS flag as part of the loop on PostRestyleEvent, and we
|
||||
// use that to check we have pending restyles.
|
||||
|
@ -188,7 +249,7 @@ ServoRestyleManager::RestyleForRemove(Element* aContainer,
|
|||
|
||||
nsresult
|
||||
ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
|
||||
EventStates aStateMask)
|
||||
EventStates aChangedBits)
|
||||
{
|
||||
if (!aContent->IsElement()) {
|
||||
return NS_OK;
|
||||
|
@ -197,7 +258,32 @@ ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
|
|||
Element* aElement = aContent->AsElement();
|
||||
nsChangeHint changeHint;
|
||||
nsRestyleHint restyleHint;
|
||||
ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
|
||||
|
||||
// NOTE: restyleHint here is effectively always 0, since that's what
|
||||
// ServoStyleSet::HasStateDependentStyle returns. Servo computes on
|
||||
// ProcessPendingRestyles using the ElementSnapshot, but in theory could
|
||||
// compute it sequentially easily.
|
||||
//
|
||||
// Determine what's the best way to do it, and how much work do we save
|
||||
// processing the restyle hint early (i.e., computing the style hint here
|
||||
// sequentially, potentially saving the snapshot), vs lazily (snapshot
|
||||
// approach).
|
||||
//
|
||||
// If we take the sequential approach we need to specialize Servo's restyle
|
||||
// hints system a bit more, and mesure whether we save something storing the
|
||||
// restyle hint in the table and deferring the dirtiness setting until
|
||||
// ProcessPendingRestyles (that's a requirement if we store snapshots though),
|
||||
// vs processing the restyle hint in-place, dirtying the nodes on
|
||||
// PostRestyleEvent.
|
||||
//
|
||||
// If we definitely take the snapshot approach, we should take rid of
|
||||
// HasStateDependentStyle, etc (though right now they're no-ops).
|
||||
ContentStateChangedInternal(aElement, aChangedBits, &changeHint,
|
||||
&restyleHint);
|
||||
|
||||
EventStates previousState = aElement->StyleState() ^ aChangedBits;
|
||||
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
|
||||
snapshot->AddState(previousState);
|
||||
|
||||
PostRestyleEvent(aElement, restyleHint, changeHint);
|
||||
return NS_OK;
|
||||
|
@ -206,18 +292,15 @@ ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
|
|||
void
|
||||
ServoRestyleManager::AttributeWillChange(Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::AttributeWillChange not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::AttributeChanged(Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ERROR("stylo: ServoRestyleManager::AttributeChanged not implemented");
|
||||
|
@ -229,4 +312,16 @@ ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
|||
MOZ_CRASH("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
|
||||
}
|
||||
|
||||
ServoElementSnapshot*
|
||||
ServoRestyleManager::SnapshotForElement(Element* aElement)
|
||||
{
|
||||
ServoElementSnapshot* snapshot = mModifiedElements.LookupOrAdd(aElement);
|
||||
if (!snapshot->HasAny(
|
||||
ServoElementSnapshot::Flags::HTMLElementInHTMLDocument)) {
|
||||
snapshot->SetIsHTMLElementInHTMLDocument(
|
||||
aElement->IsHTMLElement() && aElement->OwnerDoc()->IsHTMLDocument());
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/RestyleManagerBase.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsINode.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -60,25 +62,25 @@ public:
|
|||
nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue);
|
||||
void AttributeChanged(dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType,
|
||||
void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aOldValue);
|
||||
nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
bool HasPendingRestyles() {
|
||||
if (MOZ_UNLIKELY(IsDisconnected())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PresContext()->PresShell()->GetDocument()->HasDirtyDescendantsForServo();
|
||||
}
|
||||
bool HasPendingRestyles() { return mModifiedElements.Count() != 0; }
|
||||
|
||||
protected:
|
||||
~ServoRestyleManager() {}
|
||||
|
||||
private:
|
||||
ServoElementSnapshot* SnapshotForElement(Element* aElement);
|
||||
|
||||
/**
|
||||
* The element-to-element snapshot table to compute restyle hints.
|
||||
*/
|
||||
nsClassHashtable<nsRefPtrHashKey<Element>, ServoElementSnapshot>
|
||||
mModifiedElements;
|
||||
|
||||
/**
|
||||
* Traverses a tree of content that Servo has just restyled, recreating style
|
||||
* contexts for their frames with the new style data.
|
||||
|
@ -95,9 +97,15 @@ private:
|
|||
* Propagates the IS_DIRTY flag down to the tree, setting
|
||||
* HAS_DIRTY_DESCENDANTS appropriately.
|
||||
*/
|
||||
static void DirtyTree(nsIContent* aContent);
|
||||
static void DirtyTree(nsIContent* aContent, bool aIncludingRoot = true);
|
||||
|
||||
inline ServoStyleSet* StyleSet() const {
|
||||
/**
|
||||
* Marks the tree with the appropriate dirty flags for the given restyle hint.
|
||||
*/
|
||||
static void NoteRestyleHint(Element* aElement, nsRestyleHint aRestyleHint);
|
||||
|
||||
inline ServoStyleSet* StyleSet() const
|
||||
{
|
||||
MOZ_ASSERT(PresContext()->StyleSet()->IsServo(),
|
||||
"ServoRestyleManager should only be used with a Servo-flavored "
|
||||
"style backend");
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "mozilla/ServoBindings.h"
|
||||
|
||||
#include "StyleStructContext.h"
|
||||
#include "gfxFontFamilyList.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
|
@ -18,11 +19,11 @@
|
|||
#include "nsNameSpaceManager.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "StyleStructContext.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
uint32_t
|
||||
|
@ -102,11 +103,10 @@ Gecko_GetDocumentElement(RawGeckoDocument* aDoc)
|
|||
return aDoc->GetDocumentElement();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EventStates::ServoType
|
||||
Gecko_ElementState(RawGeckoElement* aElement)
|
||||
{
|
||||
return aElement->StyleState().GetInternalValue() &
|
||||
((1 << (NS_EVENT_STATE_HIGHEST_SERVO_BIT + 1)) - 1);
|
||||
return aElement->StyleState().ServoValue();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -184,9 +184,27 @@ Gecko_UnsetNodeFlags(RawGeckoNode* aNode, uint32_t aFlags)
|
|||
aNode->UnsetFlags(aFlags);
|
||||
}
|
||||
|
||||
template<class MatchFn>
|
||||
bool
|
||||
DoMatch(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName, MatchFn aMatch)
|
||||
ServoDeclarationBlock*
|
||||
Gecko_GetServoDeclarationBlock(RawGeckoElement* aElement)
|
||||
{
|
||||
const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::style);
|
||||
if (!attr || attr->Type() != nsAttrValue::eServoCSSDeclaration) {
|
||||
return nullptr;
|
||||
}
|
||||
return attr->GetServoCSSDeclarationValue();
|
||||
}
|
||||
|
||||
template <typename Implementor>
|
||||
static nsIAtom*
|
||||
AtomAttrValue(Implementor* aElement, nsIAtom* aName)
|
||||
{
|
||||
const nsAttrValue* attr = aElement->GetParsedAttr(aName);
|
||||
return attr ? attr->GetAtomValue() : nullptr;
|
||||
}
|
||||
|
||||
template <typename Implementor, typename MatchFn>
|
||||
static bool
|
||||
DoMatch(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName, MatchFn aMatch)
|
||||
{
|
||||
if (aNS) {
|
||||
int32_t ns = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNS);
|
||||
|
@ -218,16 +236,18 @@ struct FakeRef {
|
|||
T* mPtr;
|
||||
};
|
||||
|
||||
bool
|
||||
Gecko_HasAttr(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
HasAttr(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName)
|
||||
{
|
||||
auto match = [](const nsAttrValue* aValue) { return true; };
|
||||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrEquals(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_, bool aIgnoreCase)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrEquals(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName, nsIAtom* aStr_,
|
||||
bool aIgnoreCase)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr, aIgnoreCase](const nsAttrValue* aValue) {
|
||||
|
@ -236,9 +256,10 @@ Gecko_AttrEquals(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrDashEquals(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrDashEquals(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr](const nsAttrValue* aValue) {
|
||||
|
@ -250,9 +271,10 @@ Gecko_AttrDashEquals(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrIncludes(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrIncludes(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr](const nsAttrValue* aValue) {
|
||||
|
@ -264,9 +286,10 @@ Gecko_AttrIncludes(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrHasSubstring(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrHasSubstring(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr](const nsAttrValue* aValue) {
|
||||
|
@ -277,9 +300,10 @@ Gecko_AttrHasSubstring(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrHasPrefix(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrHasPrefix(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr](const nsAttrValue* aValue) {
|
||||
|
@ -290,9 +314,10 @@ Gecko_AttrHasPrefix(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_AttrHasSuffix(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
template <typename Implementor>
|
||||
static bool
|
||||
AttrHasSuffix(Implementor* aElement, nsIAtom* aNS, nsIAtom* aName,
|
||||
nsIAtom* aStr_)
|
||||
{
|
||||
FakeRef<nsIAtom> aStr(aStr_);
|
||||
auto match = [aStr](const nsAttrValue* aValue) {
|
||||
|
@ -303,9 +328,22 @@ Gecko_AttrHasSuffix(RawGeckoElement* aElement, nsIAtom* aNS, nsIAtom* aName,
|
|||
return DoMatch(aElement, aNS, aName, match);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Gecko_ClassOrClassList(RawGeckoElement* aElement,
|
||||
nsIAtom** aClass, nsIAtom*** aClassList)
|
||||
/**
|
||||
* Gets the class or class list (if any) of the implementor. The calling
|
||||
* convention here is rather hairy, and is optimized for getting Servo the
|
||||
* information it needs for hot calls.
|
||||
*
|
||||
* The return value indicates the number of classes. If zero, neither outparam
|
||||
* is valid. If one, the class_ outparam is filled with the atom of the class.
|
||||
* If two or more, the classList outparam is set to point to an array of atoms
|
||||
* representing the class list.
|
||||
*
|
||||
* The array is borrowed and the atoms are not addrefed. These values can be
|
||||
* invalidated by any DOM mutation. Use them in a tight scope.
|
||||
*/
|
||||
template <typename Implementor>
|
||||
static uint32_t
|
||||
ClassOrClassList(Implementor* aElement, nsIAtom** aClass, nsIAtom*** aClassList)
|
||||
{
|
||||
const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::_class);
|
||||
if (!attr) {
|
||||
|
@ -357,15 +395,55 @@ Gecko_ClassOrClassList(RawGeckoElement* aElement,
|
|||
return atomArray->Length();
|
||||
}
|
||||
|
||||
ServoDeclarationBlock*
|
||||
Gecko_GetServoDeclarationBlock(RawGeckoElement* aElement)
|
||||
{
|
||||
const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::style);
|
||||
if (!attr || attr->Type() != nsAttrValue::eServoCSSDeclaration) {
|
||||
return nullptr;
|
||||
#define SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
|
||||
nsIAtom* prefix_##AtomAttrValue(implementor_* aElement, nsIAtom* aName) \
|
||||
{ \
|
||||
return AtomAttrValue(aElement, aName); \
|
||||
} \
|
||||
bool prefix_##HasAttr(implementor_* aElement, nsIAtom* aNS, nsIAtom* aName) \
|
||||
{ \
|
||||
return HasAttr(aElement, aNS, aName); \
|
||||
} \
|
||||
bool prefix_##AttrEquals(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr, bool aIgnoreCase) \
|
||||
{ \
|
||||
return AttrEquals(aElement, aNS, aName, aStr, aIgnoreCase); \
|
||||
} \
|
||||
bool prefix_##AttrDashEquals(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr) \
|
||||
{ \
|
||||
return AttrDashEquals(aElement, aNS, aName, aStr); \
|
||||
} \
|
||||
bool prefix_##AttrIncludes(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr) \
|
||||
{ \
|
||||
return AttrIncludes(aElement, aNS, aName, aStr); \
|
||||
} \
|
||||
bool prefix_##AttrHasSubstring(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr) \
|
||||
{ \
|
||||
return AttrHasSubstring(aElement, aNS, aName, aStr); \
|
||||
} \
|
||||
bool prefix_##AttrHasPrefix(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr) \
|
||||
{ \
|
||||
return AttrHasPrefix(aElement, aNS, aName, aStr); \
|
||||
} \
|
||||
bool prefix_##AttrHasSuffix(implementor_* aElement, nsIAtom* aNS, \
|
||||
nsIAtom* aName, nsIAtom* aStr) \
|
||||
{ \
|
||||
return AttrHasSuffix(aElement, aNS, aName, aStr); \
|
||||
} \
|
||||
uint32_t prefix_##ClassOrClassList(implementor_* aElement, nsIAtom** aClass, \
|
||||
nsIAtom*** aClassList) \
|
||||
{ \
|
||||
return ClassOrClassList(aElement, aClass, aClassList); \
|
||||
}
|
||||
return attr->GetServoCSSDeclarationValue();
|
||||
}
|
||||
|
||||
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElement)
|
||||
SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, ServoElementSnapshot)
|
||||
|
||||
#undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
|
||||
|
||||
ServoNodeData*
|
||||
Gecko_GetNodeData(RawGeckoNode* aNode)
|
||||
|
@ -809,6 +887,15 @@ Servo_Initialize()
|
|||
"non-MOZ_STYLO build");
|
||||
}
|
||||
|
||||
// Restyle hints.
|
||||
nsRestyleHint
|
||||
Servo_ComputeRestyleHint(RawGeckoElement* element,
|
||||
ServoElementSnapshot* snapshot, RawServoStyleSet* set)
|
||||
{
|
||||
MOZ_CRASH("stylo: shouldn't be calling Servo_ComputeRestyleHint in a "
|
||||
"non-MOZ_STYLO build");
|
||||
}
|
||||
|
||||
void
|
||||
Servo_RestyleDocument(RawGeckoDocument* doc, RawServoStyleSet* set)
|
||||
{
|
||||
|
|
|
@ -7,12 +7,14 @@
|
|||
#ifndef mozilla_ServoBindings_h
|
||||
#define mozilla_ServoBindings_h
|
||||
|
||||
#include "stdint.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/css/SheetParsingMode.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "stdint.h"
|
||||
|
||||
/*
|
||||
* API for Servo to access Gecko data structures. This file must compile as valid
|
||||
|
@ -36,6 +38,7 @@ namespace mozilla {
|
|||
using mozilla::FontFamilyList;
|
||||
using mozilla::FontFamilyType;
|
||||
using mozilla::dom::Element;
|
||||
using mozilla::ServoElementSnapshot;
|
||||
typedef mozilla::dom::Element RawGeckoElement;
|
||||
class nsIDocument;
|
||||
typedef nsIDocument RawGeckoDocument;
|
||||
|
@ -104,29 +107,29 @@ nsIAtom* Gecko_Namespace(RawGeckoElement* element);
|
|||
nsIAtom* Gecko_GetElementId(RawGeckoElement* element);
|
||||
|
||||
// Attributes.
|
||||
bool Gecko_HasAttr(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name);
|
||||
bool Gecko_AttrEquals(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str, bool ignoreCase);
|
||||
bool Gecko_AttrDashEquals(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str);
|
||||
bool Gecko_AttrIncludes(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str);
|
||||
bool Gecko_AttrHasSubstring(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str);
|
||||
bool Gecko_AttrHasPrefix(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str);
|
||||
bool Gecko_AttrHasSuffix(RawGeckoElement* element, nsIAtom* ns, nsIAtom* name, nsIAtom* str);
|
||||
#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
|
||||
nsIAtom* prefix_##AtomAttrValue(implementor_* element, nsIAtom* attribute); \
|
||||
bool prefix_##HasAttr(implementor_* element, nsIAtom* ns, nsIAtom* name); \
|
||||
bool prefix_##AttrEquals(implementor_* element, nsIAtom* ns, nsIAtom* name, \
|
||||
nsIAtom* str, bool ignoreCase); \
|
||||
bool prefix_##AttrDashEquals(implementor_* element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrIncludes(implementor_* element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasSubstring(implementor_* element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasPrefix(implementor_* element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasSuffix(implementor_* element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
uint32_t prefix_##ClassOrClassList(implementor_* element, nsIAtom** class_, \
|
||||
nsIAtom*** classList);
|
||||
|
||||
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElement)
|
||||
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
|
||||
ServoElementSnapshot)
|
||||
|
||||
// Gets the class or class list (if any) of the Element.
|
||||
//
|
||||
// The calling convention here is rather hairy, and is optimized for getting
|
||||
// Servo the information it needs for hot calls.
|
||||
//
|
||||
// The return value indicates the number of classes. If zero, neither outparam
|
||||
// is valid. If one, the class_ outparam is filled with the atom of the class.
|
||||
// If two or more, the classList outparam is set to point to an array of atoms
|
||||
// representing the class list.
|
||||
//
|
||||
// The array is borrowed and the atoms are not addrefed. These values can be
|
||||
// invalidated by any DOM mutation. Use them in a tight scope.
|
||||
uint32_t Gecko_ClassOrClassList(RawGeckoElement* element,
|
||||
nsIAtom** class_, nsIAtom*** classList);
|
||||
#undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
|
||||
|
||||
// Style attributes.
|
||||
ServoDeclarationBlock* Gecko_GetServoDeclarationBlock(RawGeckoElement* element);
|
||||
|
@ -259,13 +262,20 @@ void Servo_Initialize();
|
|||
void Servo_RestyleDocument(RawGeckoDocument* doc, RawServoStyleSet* set);
|
||||
void Servo_RestyleSubtree(RawGeckoNode* node, RawServoStyleSet* set);
|
||||
|
||||
// Restyle hints.
|
||||
nsRestyleHint Servo_ComputeRestyleHint(RawGeckoElement* element,
|
||||
ServoElementSnapshot* snapshot,
|
||||
RawServoStyleSet* set);
|
||||
|
||||
// Style-struct management.
|
||||
#define STYLE_STRUCT(name, checkdata_cb) \
|
||||
struct nsStyle##name; \
|
||||
void Gecko_Construct_nsStyle##name(nsStyle##name* ptr); \
|
||||
void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, const nsStyle##name* other); \
|
||||
void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr); \
|
||||
const nsStyle##name* Servo_GetStyle##name(ServoComputedValues* computedValues);
|
||||
#define STYLE_STRUCT(name, checkdata_cb) \
|
||||
struct nsStyle##name; \
|
||||
void Gecko_Construct_nsStyle##name(nsStyle##name* ptr); \
|
||||
void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, \
|
||||
const nsStyle##name* other); \
|
||||
void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr); \
|
||||
const nsStyle##name* Servo_GetStyle##name( \
|
||||
ServoComputedValues* computedValues);
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
ServoElementSnapshot::AddAttrs(Element* aElement)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
|
||||
if (!HasAny(Flags::Attributes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t attrCount = aElement->GetAttrCount();
|
||||
const nsAttrName* attrName;
|
||||
for (uint32_t i = 0; i < attrCount; ++i) {
|
||||
attrName = aElement->GetAttrNameAt(i);
|
||||
const nsAttrValue* attrValue =
|
||||
aElement->GetParsedAttr(attrName->LocalName(), attrName->NamespaceID());
|
||||
mAttrs.AppendElement(ServoAttrSnapshot(*attrName, *attrValue));
|
||||
}
|
||||
mContains |= Flags::Attributes;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,180 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ServoElementSnapshot_h
|
||||
#define mozilla_ServoElementSnapshot_h
|
||||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
* A structure representing a single attribute name and value.
|
||||
*
|
||||
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
|
||||
*/
|
||||
struct ServoAttrSnapshot
|
||||
{
|
||||
nsAttrName mName;
|
||||
nsAttrValue mValue;
|
||||
|
||||
ServoAttrSnapshot(const nsAttrName& aName, const nsAttrValue& aValue)
|
||||
: mName(aName)
|
||||
, mValue(aValue)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitflags enum class used to determine what data does a ServoElementSnapshot
|
||||
* contains.
|
||||
*/
|
||||
enum class ServoElementSnapshotFlags : uint8_t
|
||||
{
|
||||
State = 1 << 0,
|
||||
Attributes = 1 << 1,
|
||||
HTMLElementInHTMLDocument = 1 << 2,
|
||||
All = State | Attributes | HTMLElementInHTMLDocument
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoElementSnapshotFlags)
|
||||
|
||||
/**
|
||||
* This class holds all non-tree-structural state of an element that might be
|
||||
* used for selector matching eventually.
|
||||
*
|
||||
* This means the attributes, and the element state, such as :hover, :active,
|
||||
* etc...
|
||||
*/
|
||||
class ServoElementSnapshot
|
||||
{
|
||||
typedef dom::Element Element;
|
||||
typedef EventStates::ServoType ServoStateType;
|
||||
|
||||
public:
|
||||
typedef ServoElementSnapshotFlags Flags;
|
||||
|
||||
/**
|
||||
* Empty snapshot, with no data at all.
|
||||
*/
|
||||
ServoElementSnapshot()
|
||||
: mContains(Flags(0))
|
||||
, mState(0)
|
||||
, mExplicitRestyleHint(nsRestyleHint(0))
|
||||
, mExplicitChangeHint(nsChangeHint(0))
|
||||
, mIsHTMLElementInHTMLDocument(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool HasAttrs() { return HasAny(Flags::Attributes); }
|
||||
|
||||
bool HasState() { return HasAny(Flags::State); }
|
||||
|
||||
/**
|
||||
* Captures the given state (if not previously captured).
|
||||
*/
|
||||
void AddState(EventStates aState)
|
||||
{
|
||||
if (!HasAny(Flags::State)) {
|
||||
mState = aState.ServoValue();
|
||||
mContains |= Flags::State;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the given element attributes (if not previously captured).
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
const nsAttrName* GetAttrNameAt(uint32_t aIndex) const
|
||||
{
|
||||
if (aIndex >= mAttrs.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &mAttrs[aIndex].mName;
|
||||
}
|
||||
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aLocalName) const
|
||||
{
|
||||
return GetParsedAttr(aLocalName, kNameSpaceID_None);
|
||||
}
|
||||
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aLocalName,
|
||||
int32_t aNamespaceID) const
|
||||
{
|
||||
uint32_t i, len = mAttrs.Length();
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
// This should be the common case so lets make an optimized loop
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mAttrs[i].mName.Equals(aLocalName)) {
|
||||
return &mAttrs[i].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mAttrs[i].mName.Equals(aLocalName, aNamespaceID)) {
|
||||
return &mAttrs[i].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetIsHTMLElementInHTMLDocument(bool aIs)
|
||||
{
|
||||
MOZ_ASSERT(!HasAny(Flags::HTMLElementInHTMLDocument),
|
||||
"Only expected to be set once!");
|
||||
mContains |= Flags::HTMLElementInHTMLDocument;
|
||||
mIsHTMLElementInHTMLDocument = aIs;
|
||||
}
|
||||
|
||||
bool HasAny(Flags aFlags) { return bool(mContains & aFlags); }
|
||||
|
||||
private:
|
||||
// TODO: Profile, a 1 or 2 element AutoTArray could be worth it, given we know
|
||||
// we're dealing with attribute changes when we take snapshots of attributes,
|
||||
// though it can be wasted space if we deal with a lot of state-only
|
||||
// snapshots.
|
||||
Flags mContains;
|
||||
nsTArray<ServoAttrSnapshot> mAttrs;
|
||||
ServoStateType mState;
|
||||
nsRestyleHint mExplicitRestyleHint;
|
||||
nsChangeHint mExplicitChangeHint;
|
||||
bool mIsHTMLElementInHTMLDocument;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -381,6 +381,13 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
|||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
ServoStyleSet::ComputeRestyleHint(dom::Element* aElement,
|
||||
ServoElementSnapshot* aSnapshot)
|
||||
{
|
||||
return Servo_ComputeRestyleHint(aElement, aSnapshot, mRawSet.get());
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::RestyleSubtree(nsINode* aNode, bool aForce)
|
||||
{
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ServoBindingHelpers.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/ServoStyleSheet.h"
|
||||
#include "mozilla/SheetType.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
@ -113,10 +114,15 @@ public:
|
|||
// Test if style is dependent on content state
|
||||
nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask);
|
||||
nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
|
||||
mozilla::CSSPseudoElementType aPseudoType,
|
||||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask);
|
||||
nsRestyleHint HasStateDependentStyle(
|
||||
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);
|
||||
|
||||
/**
|
||||
* Restyles a whole subtree of nodes.
|
||||
|
|
|
@ -93,6 +93,7 @@ EXPORTS.mozilla += [
|
|||
'RuleProcessorCache.h',
|
||||
'ServoBindingHelpers.h',
|
||||
'ServoBindings.h',
|
||||
'ServoElementSnapshot.h',
|
||||
'ServoStyleSet.h',
|
||||
'ServoStyleSheet.h',
|
||||
'SheetType.h',
|
||||
|
@ -190,6 +191,7 @@ UNIFIED_SOURCES += [
|
|||
'RuleNodeCacheConditions.cpp',
|
||||
'RuleProcessorCache.cpp',
|
||||
'ServoBindings.cpp',
|
||||
'ServoElementSnapshot.cpp',
|
||||
'ServoStyleSet.cpp',
|
||||
'ServoStyleSheet.cpp',
|
||||
'StyleAnimationValue.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче