/* -*- 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 nsIContentInlines_h #define nsIContentInlines_h #include "nsIContent.h" #include "mozilla/dom/Document.h" #include "nsContentUtils.h" #include "nsAtom.h" #include "nsIFrame.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/ShadowRoot.h" inline bool nsIContent::IsInHTMLDocument() const { return OwnerDoc()->IsHTMLDocument(); } inline bool nsIContent::IsInChromeDocument() const { return nsContentUtils::IsChromeDoc(OwnerDoc()); } inline void nsIContent::SetPrimaryFrame(nsIFrame* aFrame) { MOZ_ASSERT(IsInUncomposedDoc() || IsInShadowTree(), "This will end badly!"); // is known to trigger this, see bug 749326 and bug 135040. MOZ_ASSERT(IsHTMLElement(nsGkAtoms::area) || !aFrame || !mPrimaryFrame || aFrame == mPrimaryFrame, "Losing track of existing primary frame"); if (aFrame) { MOZ_ASSERT(!aFrame->IsPlaceholderFrame()); if (MOZ_LIKELY(!IsHTMLElement(nsGkAtoms::area)) || aFrame->GetContent() == this) { aFrame->SetIsPrimaryFrame(true); } } else if (nsIFrame* currentPrimaryFrame = GetPrimaryFrame()) { if (MOZ_LIKELY(!IsHTMLElement(nsGkAtoms::area)) || currentPrimaryFrame->GetContent() == this) { currentPrimaryFrame->SetIsPrimaryFrame(false); } } mPrimaryFrame = aFrame; } inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const { if (!IsElement()) { return nullptr; } return AsElement()->GetShadowRoot(); } template static inline nsINode* GetFlattenedTreeParentNode(const nsINode* aNode) { if (!aNode->IsContent()) { return nullptr; } nsINode* parent = aNode->GetParentNode(); if (!parent || !parent->IsContent()) { return parent; } const nsIContent* content = aNode->AsContent(); nsIContent* parentAsContent = parent->AsContent(); if (aType == nsINode::eForStyle && content->IsRootOfNativeAnonymousSubtree() && parentAsContent == content->OwnerDoc()->GetRootElement()) { const bool docLevel = content->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent); return docLevel ? content->OwnerDocAsNode() : parent; } if (content->IsRootOfNativeAnonymousSubtree()) { return parent; } if (parentAsContent->GetShadowRoot()) { // If it's not assigned to any slot it's not part of the flat tree, and thus // we return null. return content->GetAssignedSlot(); } if (parentAsContent->IsInShadowTree()) { if (auto* slot = mozilla::dom::HTMLSlotElement::FromNode(parentAsContent)) { // If the assigned nodes list is empty, we're fallback content which is // active, otherwise we are not part of the flat tree. return slot->AssignedNodes().IsEmpty() ? parent : nullptr; } if (auto* shadowRoot = mozilla::dom::ShadowRoot::FromNode(parentAsContent)) { return shadowRoot->GetHost(); } } // Common case. return parent; } inline nsINode* nsINode::GetFlattenedTreeParentNode() const { return ::GetFlattenedTreeParentNode(this); } inline nsIContent* nsIContent::GetFlattenedTreeParent() const { nsINode* parent = GetFlattenedTreeParentNode(); return (parent && parent->IsContent()) ? parent->AsContent() : nullptr; } inline bool nsIContent::IsEventAttributeName(nsAtom* aName) { const char16_t* name = aName->GetUTF16String(); if (name[0] != 'o' || name[1] != 'n') { return false; } return IsEventAttributeNameInternal(aName); } inline nsINode* nsINode::GetFlattenedTreeParentNodeForStyle() const { return ::GetFlattenedTreeParentNode(this); } inline bool nsINode::NodeOrAncestorHasDirAuto() const { return AncestorHasDirAuto() || (IsElement() && AsElement()->HasDirAuto()); } inline bool nsINode::IsEditable() const { if (HasFlag(NODE_IS_EDITABLE)) { // The node is in an editable contentEditable subtree. return true; } // All editable anonymous content should be made explicitly editable via the // NODE_IS_EDITABLE flag. if (IsInNativeAnonymousSubtree()) { return false; } // Check if the node is in a document and the document is in designMode. return IsInDesignMode(); } inline bool nsINode::IsInDesignMode() const { if (!OwnerDoc()->HasFlag(NODE_IS_EDITABLE)) { return false; } if (IsDocument()) { return HasFlag(NODE_IS_EDITABLE); } // NOTE(emilio): If you change this to be the composed doc you also need to // change NotifyEditableStateChange() in Document.cpp. // NOTE(masayuki): Perhaps, we should keep this behavior because of // web-compat. if (IsInUncomposedDoc() && GetUncomposedDoc()->HasFlag(NODE_IS_EDITABLE)) { return true; } // FYI: In design mode, form controls don't work as usual. For example, // isn't focusable but can be deleted and replaced // with typed text.