gecko-dev/dom/base/ShadowRoot.h
Emilio Cobos Álvarez 3b61137a4b Bug 1484478 - Use a node bit for connectedness. r=smaug
While trying to repro bug 1484293 I noticed that this assertion failed:

https://searchfox.org/mozilla-central/rev/ef8b3886cb173d5534b954b6fb7eb2d94a9473d0/dom/base/ShadowRoot.cpp#160

(during unlink, while unbinding the kids)

We rely on GetComposedDoc returning the right thing during unbind to cleanup
some stuff (see bug 1473637 for example), so it should probably be correct all
the time, regardless of whether something is unlinked or not.

Also this makes GetComposedDoc() much faster, which is nice too, since we call
it somewhat often.

I removed NodeHasRelevantHoverRules, since it's unused (was used by the old
style system).

I moved the SetIsConnected(false) call for the shadow root to before unbinding
the kids for consistency with what Element does with the uncomposed doc flag,
now that the children's connectedness doesn't depend on the shadow root's.

Differential Revision: https://phabricator.services.mozilla.com/D3715

--HG--
extra : moz-landing-system : lando
2018-08-20 11:56:27 +00:00

235 lines
6.8 KiB
C++

/* -*- 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_dom_shadowroot_h__
#define mozilla_dom_shadowroot_h__
#include "mozilla/dom/DocumentBinding.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DocumentOrShadowRoot.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "mozilla/dom/ShadowRootBinding.h"
#include "mozilla/ServoBindings.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIdentifierMapEntry.h"
#include "nsStubMutationObserver.h"
#include "nsTHashtable.h"
class nsAtom;
class nsIContent;
class nsXBLPrototypeBinding;
namespace mozilla {
class EventChainPreVisitor;
class ServoStyleRuleMap;
namespace css {
class Rule;
}
namespace dom {
class Element;
class ShadowRoot final : public DocumentFragment,
public DocumentOrShadowRoot,
public nsStubMutationObserver
{
public:
NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot());
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
DocumentFragment)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
ShadowRoot(Element* aElement, ShadowRootMode aMode,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
// Shadow DOM v1
Element* Host() const
{
MOZ_ASSERT(GetHost(), "ShadowRoot always has a host, how did we create "
"this ShadowRoot?");
return GetHost();
}
ShadowRootMode Mode() const
{
return mMode;
}
bool IsClosed() const
{
return mMode == ShadowRootMode::Closed;
}
void RemoveSheet(StyleSheet* aSheet);
void RuleAdded(StyleSheet&, css::Rule&);
void RuleRemoved(StyleSheet&, css::Rule&);
void RuleChanged(StyleSheet&, css::Rule*);
void StyleSheetApplicableStateChanged(StyleSheet&, bool aApplicable);
StyleSheetList* StyleSheets()
{
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
}
/**
* Clones internal state, for example stylesheets, of aOther to 'this'.
*/
void CloneInternalDataFrom(ShadowRoot* aOther);
void InsertSheetAt(size_t aIndex, StyleSheet&);
// Calls UnbindFromTree for each of our kids, and also flags us as no longer
// being connected.
void Unbind();
// Calls BindToTree on each of our kids, and also maybe flags us as being
// connected.
nsresult Bind();
private:
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&);
void AppendStyleSheet(StyleSheet& aSheet)
{
InsertSheetAt(SheetCount(), aSheet);
}
/**
* Try to reassign an element to a slot and returns whether the assignment
* changed.
*/
void MaybeReassignElement(Element* aElement);
/**
* Represents the insertion point in a slot for a given node.
*/
struct SlotAssignment
{
HTMLSlotElement* mSlot = nullptr;
Maybe<uint32_t> mIndex;
SlotAssignment() = default;
SlotAssignment(HTMLSlotElement* aSlot, const Maybe<uint32_t>& aIndex)
: mSlot(aSlot)
, mIndex(aIndex)
{ }
};
/**
* Return the assignment corresponding to the content node at this particular
* point in time.
*
* It's the caller's responsibility to actually call InsertAssignedNode /
* AppendAssignedNode in the slot as needed.
*/
SlotAssignment SlotAssignmentFor(nsIContent* aContent);
/**
* Explicitly invalidates the style and layout of the flattened-tree subtree
* rooted at the element.
*
* You need to use this whenever the flat tree is going to be shuffled in a
* way that layout doesn't understand via the usual ContentInserted /
* ContentAppended / ContentRemoved notifications. For example, if removing an
* element will cause a change in the flat tree such that other element will
* start showing up (like fallback content), this method needs to be called on
* an ancestor of that element.
*
* It is important that this runs _before_ actually shuffling the flat tree
* around, so that layout knows the actual tree that it needs to invalidate.
*/
void InvalidateStyleAndLayoutOnSubtree(Element*);
public:
void AddSlot(HTMLSlotElement* aSlot);
void RemoveSlot(HTMLSlotElement* aSlot);
bool HasSlots() const { return !mSlotMap.IsEmpty(); };
const RawServoAuthorStyles* ServoStyles() const
{
return mServoStyles.get();
}
RawServoAuthorStyles* ServoStyles()
{
return mServoStyles.get();
}
mozilla::ServoStyleRuleMap& ServoStyleRuleMap();
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void AddToIdTable(Element* aElement, nsAtom* aId);
void RemoveFromIdTable(Element* aElement, nsAtom* aId);
// WebIDL methods.
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
Element* GetActiveElement();
void GetInnerHTML(nsAString& aInnerHTML);
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
/**
* These methods allow UA Widget to insert DOM elements into the Shadow ROM
* without putting their DOM reflectors to content scope first.
* The inserted DOM will have their reflectors in the UA Widget scope.
*/
nsINode* ImportNodeAndAppendChildAt(nsINode& aParentNode,
nsINode& aNode,
bool aDeep, mozilla::ErrorResult& rv);
nsINode* CreateElementAndAppendChildAt(nsINode& aParentNode,
const nsAString& aTagName,
mozilla::ErrorResult& rv);
bool IsUAWidget() const
{
return mIsUAWidget;
}
void SetIsUAWidget()
{
mIsUAWidget = true;
}
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
protected:
// FIXME(emilio): This will need to become more fine-grained.
void ApplicableRulesChanged();
virtual ~ShadowRoot();
const ShadowRootMode mMode;
// The computed data from the style sheets.
UniquePtr<RawServoAuthorStyles> mServoStyles;
UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
using SlotArray = AutoTArray<HTMLSlotElement*, 1>;
// Map from name of slot to an array of all slots in the shadow DOM with with
// the given name. The slots are stored as a weak pointer because the elements
// are in the shadow tree and should be kept alive by its parent.
nsClassHashtable<nsStringHashKey, SlotArray> mSlotMap;
bool mIsUAWidget;
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_shadowroot_h__