2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2013-12-02 14:26:11 +04:00
|
|
|
/* 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__
|
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
#include "mozilla/dom/DocumentBinding.h"
|
2013-12-02 14:26:11 +04:00
|
|
|
#include "mozilla/dom/DocumentFragment.h"
|
2017-12-21 01:29:21 +03:00
|
|
|
#include "mozilla/dom/DocumentOrShadowRoot.h"
|
2018-05-11 13:57:38 +03:00
|
|
|
#include "mozilla/dom/NameSpaceConstants.h"
|
2018-04-13 21:04:47 +03:00
|
|
|
#include "mozilla/dom/ShadowRootBinding.h"
|
|
|
|
#include "mozilla/ServoBindings.h"
|
2013-12-02 14:26:11 +04:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsCycleCollectionParticipant.h"
|
2018-09-21 03:39:47 +03:00
|
|
|
#include "nsIRadioGroupContainer.h"
|
2018-04-13 21:04:47 +03:00
|
|
|
#include "nsStubMutationObserver.h"
|
2013-12-02 14:26:11 +04:00
|
|
|
#include "nsTHashtable.h"
|
|
|
|
|
2017-10-03 01:05:19 +03:00
|
|
|
class nsAtom;
|
2013-12-02 14:26:11 +04:00
|
|
|
class nsIContent;
|
|
|
|
class nsXBLPrototypeBinding;
|
|
|
|
|
|
|
|
namespace mozilla {
|
2017-12-04 11:06:40 +03:00
|
|
|
|
|
|
|
class EventChainPreVisitor;
|
2018-05-09 04:02:21 +03:00
|
|
|
class ServoStyleRuleMap;
|
2017-12-04 11:06:40 +03:00
|
|
|
|
2018-03-17 00:56:05 +03:00
|
|
|
namespace css {
|
|
|
|
class Rule;
|
|
|
|
}
|
|
|
|
|
2013-12-02 14:26:11 +04:00
|
|
|
namespace dom {
|
|
|
|
|
|
|
|
class Element;
|
2018-09-21 03:39:47 +03:00
|
|
|
class HTMLInputElement;
|
2013-12-02 14:26:11 +04:00
|
|
|
|
2015-03-21 21:35:18 +03:00
|
|
|
class ShadowRoot final : public DocumentFragment,
|
2017-12-21 01:29:21 +03:00
|
|
|
public DocumentOrShadowRoot,
|
2018-09-21 03:39:47 +03:00
|
|
|
public nsStubMutationObserver,
|
|
|
|
public nsIRadioGroupContainer {
|
2013-12-02 14:26:11 +04:00
|
|
|
public:
|
2018-05-11 13:57:38 +03:00
|
|
|
NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot());
|
2017-12-31 22:57:32 +03:00
|
|
|
|
2013-12-02 14:26:11 +04:00
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot, DocumentFragment)
|
|
|
|
NS_DECL_ISUPPORTS_INHERITED
|
|
|
|
|
2013-12-02 14:26:12 +04:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
|
|
|
|
2018-02-25 20:01:42 +03:00
|
|
|
ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
|
|
|
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
2013-12-02 14:26:11 +04:00
|
|
|
|
2018-08-30 01:19:42 +03:00
|
|
|
void AddSizeOfExcludingThis(nsWindowSizes&, size_t* aNodeSize) const final;
|
|
|
|
|
2017-10-19 09:44:35 +03:00
|
|
|
// Shadow DOM v1
|
2018-02-18 16:33:14 +03:00
|
|
|
Element* Host() const {
|
|
|
|
MOZ_ASSERT(GetHost(),
|
|
|
|
"ShadowRoot always has a host, how did we create "
|
|
|
|
"this ShadowRoot?");
|
|
|
|
return GetHost();
|
|
|
|
}
|
|
|
|
|
2017-12-18 00:29:10 +03:00
|
|
|
ShadowRootMode Mode() const { return mMode; }
|
2017-11-02 11:53:44 +03:00
|
|
|
bool IsClosed() const { return mMode == ShadowRootMode::Closed; }
|
2017-10-19 09:44:35 +03:00
|
|
|
|
2016-09-26 15:03:25 +03:00
|
|
|
void RemoveSheet(StyleSheet* aSheet);
|
2018-03-17 00:56:05 +03:00
|
|
|
void RuleAdded(StyleSheet&, css::Rule&);
|
|
|
|
void RuleRemoved(StyleSheet&, css::Rule&);
|
|
|
|
void RuleChanged(StyleSheet&, css::Rule*);
|
|
|
|
void StyleSheetApplicableStateChanged(StyleSheet&, bool aApplicable);
|
|
|
|
|
2017-12-18 00:29:10 +03:00
|
|
|
StyleSheetList* StyleSheets() {
|
2017-12-21 01:29:21 +03:00
|
|
|
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
|
2017-12-18 00:29:10 +03:00
|
|
|
}
|
2013-12-21 10:43:58 +04:00
|
|
|
|
2018-03-04 13:41:13 +03:00
|
|
|
/**
|
|
|
|
* Clones internal state, for example stylesheets, of aOther to 'this'.
|
|
|
|
*/
|
|
|
|
void CloneInternalDataFrom(ShadowRoot* aOther);
|
2018-06-22 13:53:18 +03:00
|
|
|
void InsertSheetAt(size_t aIndex, StyleSheet&);
|
|
|
|
|
2018-08-20 14:56:27 +03:00
|
|
|
// Calls UnbindFromTree for each of our kids, and also flags us as no longer
|
|
|
|
// being connected.
|
|
|
|
void Unbind();
|
|
|
|
|
2018-11-21 16:02:24 +03:00
|
|
|
// Only intended for UA widgets / special shadow roots, or for handling
|
|
|
|
// failure cases when adopting (see BlastSubtreeToPieces).
|
|
|
|
//
|
2018-11-09 01:44:59 +03:00
|
|
|
// Forgets our shadow host and unbinds all our kids.
|
2018-11-08 23:55:22 +03:00
|
|
|
void Unattach();
|
|
|
|
|
2018-08-20 14:56:27 +03:00
|
|
|
// Calls BindToTree on each of our kids, and also maybe flags us as being
|
|
|
|
// connected.
|
|
|
|
nsresult Bind();
|
|
|
|
|
2017-10-17 19:28:42 +03:00
|
|
|
private:
|
2018-03-17 00:56:05 +03:00
|
|
|
void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&);
|
|
|
|
|
2018-06-22 13:53:18 +03:00
|
|
|
void AppendStyleSheet(StyleSheet& aSheet) {
|
|
|
|
InsertSheetAt(SheetCount(), aSheet);
|
|
|
|
}
|
2013-12-02 14:26:12 +04:00
|
|
|
|
2017-10-18 16:24:53 +03:00
|
|
|
/**
|
2017-12-04 11:06:34 +03:00
|
|
|
* Try to reassign an element to a slot and returns whether the assignment
|
2017-10-18 17:03:41 +03:00
|
|
|
* changed.
|
|
|
|
*/
|
2018-03-13 17:27:50 +03:00
|
|
|
void MaybeReassignElement(Element* aElement);
|
2017-12-04 11:06:34 +03:00
|
|
|
|
|
|
|
/**
|
2018-03-13 17:27:50 +03:00
|
|
|
* Represents the insertion point in a slot for a given node.
|
2017-12-04 11:06:34 +03:00
|
|
|
*/
|
2018-03-13 17:27:50 +03:00
|
|
|
struct SlotAssignment {
|
|
|
|
HTMLSlotElement* mSlot = nullptr;
|
|
|
|
Maybe<uint32_t> mIndex;
|
2018-03-14 13:34:01 +03:00
|
|
|
|
2018-03-14 13:39:38 +03:00
|
|
|
SlotAssignment() = default;
|
2018-03-14 13:57:17 +03:00
|
|
|
SlotAssignment(HTMLSlotElement* aSlot, const Maybe<uint32_t>& aIndex)
|
2018-03-14 13:34:01 +03:00
|
|
|
: mSlot(aSlot), mIndex(aIndex) {}
|
2018-03-13 17:27:50 +03:00
|
|
|
};
|
2017-12-04 11:06:34 +03:00
|
|
|
|
|
|
|
/**
|
2018-03-13 17:27:50 +03:00
|
|
|
* Return the assignment corresponding to the content node at this particular
|
|
|
|
* point in time.
|
2017-12-04 11:06:34 +03:00
|
|
|
*
|
2018-03-13 17:27:50 +03:00
|
|
|
* It's the caller's responsibility to actually call InsertAssignedNode /
|
|
|
|
* AppendAssignedNode in the slot as needed.
|
2017-12-04 11:06:34 +03:00
|
|
|
*/
|
2018-03-13 17:27:50 +03:00
|
|
|
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*);
|
2017-10-18 17:03:41 +03:00
|
|
|
|
2017-10-17 19:28:42 +03:00
|
|
|
public:
|
2017-12-04 11:06:34 +03:00
|
|
|
void AddSlot(HTMLSlotElement* aSlot);
|
|
|
|
void RemoveSlot(HTMLSlotElement* aSlot);
|
2018-06-01 12:45:11 +03:00
|
|
|
bool HasSlots() const { return !mSlotMap.IsEmpty(); };
|
2017-12-04 11:06:34 +03:00
|
|
|
|
2018-08-30 15:00:00 +03:00
|
|
|
const RawServoAuthorStyles* GetServoStyles() const {
|
2018-02-25 20:01:42 +03:00
|
|
|
return mServoStyles.get();
|
|
|
|
}
|
|
|
|
|
2018-08-30 15:00:00 +03:00
|
|
|
RawServoAuthorStyles* GetServoStyles() { return mServoStyles.get(); }
|
2018-02-25 20:01:42 +03:00
|
|
|
|
|
|
|
mozilla::ServoStyleRuleMap& ServoStyleRuleMap();
|
2013-12-02 14:26:12 +04:00
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
JSObject* WrapObject(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) override;
|
2013-12-02 14:26:11 +04:00
|
|
|
|
2017-12-20 08:46:01 +03:00
|
|
|
void AddToIdTable(Element* aElement, nsAtom* aId);
|
|
|
|
void RemoveFromIdTable(Element* aElement, nsAtom* aId);
|
|
|
|
|
2013-12-02 14:26:11 +04:00
|
|
|
// WebIDL methods.
|
2017-12-21 01:29:21 +03:00
|
|
|
using mozilla::dom::DocumentOrShadowRoot::GetElementById;
|
2018-01-15 09:42:47 +03:00
|
|
|
|
|
|
|
Element* GetActiveElement();
|
2013-12-02 14:26:12 +04:00
|
|
|
void GetInnerHTML(nsAString& aInnerHTML);
|
|
|
|
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
|
2015-02-09 21:01:23 +03:00
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
/**
|
|
|
|
* 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; }
|
|
|
|
|
2018-08-19 00:32:38 +03:00
|
|
|
void SetIsUAWidget() {
|
2018-11-26 23:09:51 +03:00
|
|
|
MOZ_ASSERT(!HasChildren());
|
2019-02-21 21:39:28 +03:00
|
|
|
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
2018-08-19 00:32:38 +03:00
|
|
|
mIsUAWidget = true;
|
|
|
|
}
|
2018-06-29 23:39:46 +03:00
|
|
|
|
2018-04-05 20:42:41 +03:00
|
|
|
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
2017-12-04 11:06:40 +03:00
|
|
|
|
2018-09-21 03:39:47 +03:00
|
|
|
// nsIRadioGroupContainer
|
|
|
|
NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor,
|
|
|
|
bool aFlushContent) override {
|
|
|
|
return DocumentOrShadowRoot::WalkRadioGroup(aName, aVisitor, aFlushContent);
|
|
|
|
}
|
|
|
|
virtual void SetCurrentRadioButton(const nsAString& aName,
|
|
|
|
HTMLInputElement* aRadio) override {
|
|
|
|
DocumentOrShadowRoot::SetCurrentRadioButton(aName, aRadio);
|
|
|
|
}
|
|
|
|
virtual HTMLInputElement* GetCurrentRadioButton(
|
|
|
|
const nsAString& aName) override {
|
|
|
|
return DocumentOrShadowRoot::GetCurrentRadioButton(aName);
|
|
|
|
}
|
|
|
|
NS_IMETHOD
|
|
|
|
GetNextRadioButton(const nsAString& aName, const bool aPrevious,
|
|
|
|
HTMLInputElement* aFocusedRadio,
|
|
|
|
HTMLInputElement** aRadioOut) override {
|
|
|
|
return DocumentOrShadowRoot::GetNextRadioButton(aName, aPrevious,
|
|
|
|
aFocusedRadio, aRadioOut);
|
|
|
|
}
|
|
|
|
virtual void AddToRadioGroup(const nsAString& aName,
|
|
|
|
HTMLInputElement* aRadio) override {
|
|
|
|
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
|
|
|
|
}
|
|
|
|
virtual void RemoveFromRadioGroup(const nsAString& aName,
|
|
|
|
HTMLInputElement* aRadio) override {
|
|
|
|
DocumentOrShadowRoot::RemoveFromRadioGroup(aName, aRadio);
|
|
|
|
}
|
|
|
|
virtual uint32_t GetRequiredRadioCount(
|
|
|
|
const nsAString& aName) const override {
|
|
|
|
return DocumentOrShadowRoot::GetRequiredRadioCount(aName);
|
|
|
|
}
|
|
|
|
virtual void RadioRequiredWillChange(const nsAString& aName,
|
|
|
|
bool aRequiredAdded) override {
|
|
|
|
DocumentOrShadowRoot::RadioRequiredWillChange(aName, aRequiredAdded);
|
|
|
|
}
|
|
|
|
virtual bool GetValueMissingState(const nsAString& aName) const override {
|
|
|
|
return DocumentOrShadowRoot::GetValueMissingState(aName);
|
|
|
|
}
|
|
|
|
virtual void SetValueMissingState(const nsAString& aName,
|
|
|
|
bool aValue) override {
|
|
|
|
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
|
|
|
|
}
|
|
|
|
|
2013-12-02 14:26:11 +04:00
|
|
|
protected:
|
2018-03-17 00:56:05 +03:00
|
|
|
// FIXME(emilio): This will need to become more fine-grained.
|
|
|
|
void ApplicableRulesChanged();
|
|
|
|
|
2014-07-09 01:23:16 +04:00
|
|
|
virtual ~ShadowRoot();
|
2013-12-02 14:26:12 +04:00
|
|
|
|
2018-02-25 20:01:42 +03:00
|
|
|
const ShadowRootMode mMode;
|
|
|
|
|
|
|
|
// The computed data from the style sheets.
|
|
|
|
UniquePtr<RawServoAuthorStyles> mServoStyles;
|
|
|
|
UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
|
2017-10-19 09:44:35 +03:00
|
|
|
|
2018-02-25 19:33:28 +03:00
|
|
|
using SlotArray = AutoTArray<HTMLSlotElement*, 1>;
|
2017-12-04 11:06:34 +03:00
|
|
|
// 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.
|
2018-02-25 19:33:28 +03:00
|
|
|
nsClassHashtable<nsStringHashKey, SlotArray> mSlotMap;
|
2013-12-02 14:26:12 +04:00
|
|
|
|
2018-06-29 23:39:46 +03:00
|
|
|
bool mIsUAWidget;
|
|
|
|
|
2018-08-09 02:58:44 +03:00
|
|
|
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
2013-12-02 14:26:11 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
|
|
|
|
|
|
|
#endif // mozilla_dom_shadowroot_h__
|