blob: eaa59e9c89c951f5c0280378d7db0ba9f0ac888d [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ShadowRoot_h
#define ShadowRoot_h
#include "core/CoreExport.h"
#include "core/dom/ContainerNode.h"
#include "core/dom/DocumentFragment.h"
#include "core/dom/Element.h"
#include "core/dom/TreeScope.h"
namespace blink {
class Document;
class ElementShadow;
class ExceptionState;
class HTMLShadowElement;
class HTMLSlotElement;
class InsertionPoint;
class ShadowRootRareDataV0;
class SlotAssignment;
class StyleSheetList;
enum class ShadowRootType {
UserAgent,
V0,
Open,
Closed
};
class CORE_EXPORT ShadowRoot final : public DocumentFragment, public TreeScope {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(ShadowRoot);
public:
// FIXME: Current implementation does not work well if a shadow root is dynamically created.
// So multiple shadow subtrees in several elements are prohibited.
// See https://github.com/w3c/webcomponents/issues/102 and http://crbug.com/234020
static ShadowRoot* create(Document& document, ShadowRootType type)
{
return new ShadowRoot(document, type);
}
// Disambiguate between Node and TreeScope hierarchies; TreeScope's implementation is simpler.
using TreeScope::document;
using TreeScope::getElementById;
// Make protected methods from base class public here.
using TreeScope::setDocument;
using TreeScope::setParentTreeScope;
Element& host() const { DCHECK(parentOrShadowHostNode()); return *toElement(parentOrShadowHostNode()); }
ElementShadow* owner() const { return host().shadow(); }
ShadowRootType type() const { return static_cast<ShadowRootType>(m_type); }
String mode() const { return (type() == ShadowRootType::V0 || type() == ShadowRootType::Open) ? "open" : "closed"; };
bool isOpenOrV0() const { return type() == ShadowRootType::V0 || type() == ShadowRootType::Open; }
bool isV1() const { return type() == ShadowRootType::Open || type() == ShadowRootType::Closed; }
void attach(const AttachContext& = AttachContext()) override;
InsertionNotificationRequest insertedInto(ContainerNode*) override;
void removedFrom(ContainerNode*) override;
// For V0
ShadowRoot* youngerShadowRoot() const;
ShadowRoot* olderShadowRoot() const;
ShadowRoot* olderShadowRootForBindings() const;
void setYoungerShadowRoot(ShadowRoot&);
void setOlderShadowRoot(ShadowRoot&);
bool isYoungest() const { return !youngerShadowRoot(); }
bool isOldest() const { return !olderShadowRoot(); }
bool containsShadowElements() const;
bool containsContentElements() const;
bool containsInsertionPoints() const { return containsShadowElements() || containsContentElements(); }
unsigned descendantShadowElementCount() const;
HTMLShadowElement* shadowInsertionPointOfYoungerShadowRoot() const;
void setShadowInsertionPointOfYoungerShadowRoot(HTMLShadowElement*);
void didAddInsertionPoint(InsertionPoint*);
void didRemoveInsertionPoint(InsertionPoint*);
const HeapVector<Member<InsertionPoint>>& descendantInsertionPoints();
// For Internals, don't use this.
unsigned childShadowRootCount() const { return m_childShadowRootCount; }
unsigned numberOfStyles() const { return m_numberOfStyles; }
void recalcStyle(StyleRecalcChange);
void registerScopedHTMLStyleChild();
void unregisterScopedHTMLStyleChild();
SlotAssignment& ensureSlotAssignment();
void didAddSlot();
void didRemoveSlot();
const HeapVector<Member<HTMLSlotElement>>& descendantSlots();
void assignV1();
void distributeV1();
HTMLSlotElement* assignedSlotFor(const Node&) const;
Element* activeElement() const;
String innerHTML() const;
void setInnerHTML(const String&, ExceptionState&);
Node* cloneNode(bool, ExceptionState&);
void setDelegatesFocus(bool flag) { m_delegatesFocus = flag; }
bool delegatesFocus() const { return m_delegatesFocus; }
bool containsShadowRoots() const { return m_childShadowRootCount; }
StyleSheetList& styleSheets();
void setStyleSheets(StyleSheetList* styleSheetList) { m_styleSheetList = styleSheetList; }
DECLARE_VIRTUAL_TRACE();
DECLARE_VIRTUAL_TRACE_WRAPPERS();
private:
ShadowRoot(Document&, ShadowRootType);
~ShadowRoot() override;
void childrenChanged(const ChildrenChange&) override;
ShadowRootRareDataV0& ensureShadowRootRareDataV0();
void addChildShadowRoot() { ++m_childShadowRootCount; }
void removeChildShadowRoot() { DCHECK_GT(m_childShadowRootCount, 0u); --m_childShadowRootCount; }
void invalidateDescendantInsertionPoints();
// ShadowRoots should never be cloned.
Node* cloneNode(bool) override { return nullptr; }
void invalidateDescendantSlots();
unsigned descendantSlotCount() const;
Member<ShadowRootRareDataV0> m_shadowRootRareDataV0;
Member<StyleSheetList> m_styleSheetList;
Member<SlotAssignment> m_slotAssignment;
unsigned m_numberOfStyles : 13;
unsigned m_childShadowRootCount : 13;
unsigned m_type : 2;
unsigned m_registeredWithParentShadowRoot : 1;
unsigned m_descendantInsertionPointsIsValid : 1;
unsigned m_delegatesFocus : 1;
unsigned m_descendantSlotsIsValid : 1;
};
inline Element* ShadowRoot::activeElement() const
{
return adjustedFocusedElement();
}
inline ShadowRoot* Element::shadowRootIfV1() const
{
ShadowRoot* root = this->shadowRoot();
if (root && root->isV1())
return root;
return nullptr;
}
DEFINE_NODE_TYPE_CASTS(ShadowRoot, isShadowRoot());
DEFINE_TYPE_CASTS(ShadowRoot, TreeScope, treeScope, treeScope->rootNode().isShadowRoot(), treeScope.rootNode().isShadowRoot());
DEFINE_TYPE_CASTS(TreeScope, ShadowRoot, shadowRoot, true, true);
CORE_EXPORT std::ostream& operator<<(std::ostream&, const ShadowRootType&);
} // namespace blink
#endif // ShadowRoot_h