Files
palemoon27/dom/html/HTMLContentElement.cpp
T
roytam1 9ca494cce7 import changes from rmottola/Arctic-Fox:
- Bug 940273 - Part 1 - Fetch changes from maple twig to support Service Worker Cache. (5f8e82dd7)
- Bug 940273 - Part 1b - Expose nsFileProtocolHandler.h in mozilla/net. (71a3ebcf4)
- Bug 940273 - Part 2 - Add a pref to enable Service Worker Cache. (2e7b478d3)
- patch header include (3b90a9b8d)
- override -> MOZ_OVERRIDE (8f51321bc)
- override -> MOZ_OVERRIDE (5f4ab5143)
- Bug 1136563 - ARIA 1.1: Support role 'switch' (2484c9c27)
- Bug 1121518 - ARIA 1.1: Add support for role 'searchbox' (8d3ee1204)
- override -> MOZ_OVERRIDE (3db7a0cb4)
- Bug 1137714 - Make roleDescription nicer/correct/faster (da6beb861)
- Bug 1134280 - Get rid of Tag() - patch 1 - Is{HTML,XUL,MathML,SVG}Element and IsAnyOf{HTML,XUL,MathML,SVG}Elements (133801ca1)
- Bug 1134280 - Get rid of Tag() - patch 2.1 - /accessible - Fix all the occurrences (fbef71d88)
- Bug 1134280 - Get rid of Tag() - patch 2.2 - /editor - Fix all the occurrences (e54a21dcc)
- Bug 1134280 - Get rid of Tag() - patch 2.3 - dom/base and docshell - Fix all the occurrences (8bf192106)
- Bug 1134280 - Get rid of Tag() - patch 2.4 - layout/mathml - Fix all the occurrences (7914f351d)
- Bug 1134280 - Get rid of Tag() - patch 2.5 - dom/xul - Fix all the occurrences (6611b95ef)
- Bug 1134280 - Get rid of Tag() - patch 2.6 - layout/base and layout/form - Fix all the occurrences (61e06ff31)
- Bug 1134280 - Get rid of Tag() - patch 2.7 - layout/generic - Fix all the occurrences (bbe5865c2)
- Bug 1134280 - Get rid of Tag() - patch 2.8 - dom/html - Fix all the occurrences (7af471da5)
- Bug 1134280 - Get rid of Tag() - patch 2.9 - dom/svg, dom/xml, dom/xslt and dom/xbl - Fix all the occurrences (ab9769748)
- Bug 1134280 - Get rid of Tag() - patch 2.10 - dom/events, dom/mathml, dom/plugins, dom/smil - Fix all the occurrences (421ba62f4)
- Bug 1134280 - Get rid of Tag() - patch 2.11 - layout/xul - Fix all the occurrences (e19e64b2c)
- Bug 1134280 - Get rid of Tag() - patch 2.12 - layout/style, layout/svg - Fix all the occurrences (7ec90f520)
- Bug 1134280 - Get rid of Tag() - patch 2.13 - Fix all the occurrences (a887a4341)
- Bug 1134280 - Get rid of Tag() - patch 3 - nsContentUtils::IsHTMLBlock should work with nsIContent inste nsIAtom (28fa04521)
- Bug 1134280 - Get rid of Tag() - patch 4 - Get rid of nsDocumentEncoder::IsTag (ed4bf4d48)
- Bug 1134280 - Get rid of Tag() - patch 5 - nsGenericHTMLElement::IsHTMLElement (70a2822c7)
- Bug 1134280 - Get rid of Tag() - patch 6 - Remove nsINode::Tag() (85885131f)
- Bug 1134280 - Get rid of Tag() - patch 7 - Followup to fix bustage. (actuall, backport, it was missing) (cfcfa3e74)
- Bug 1134280 - Get rid of Tag() - patch 8 - Fixed a debug-only compilation issue (502319995)
- Bug 1356843 - Fix -Wcomma warnings in dom/base/ and dom/xml/. clang's -Wcomma warning warns about suspicious use of the comma operator such as between two statements or to call a function for side effects within an expression. (0f1ad0554)
2019-02-23 00:13:11 +08:00

370 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLContentElementBinding.h"
#include "mozilla/dom/NodeListBinding.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/css/StyleRule.h"
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
#include "nsIAtom.h"
#include "nsCSSRuleProcessor.h"
#include "nsRuleData.h"
#include "nsRuleProcessorData.h"
#include "nsRuleWalker.h"
#include "nsCSSParser.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(Content)
using namespace mozilla::dom;
HTMLContentElement::HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo), mValidSelector(true), mIsInsertionPoint(false)
{
}
HTMLContentElement::~HTMLContentElement()
{
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLContentElement,
nsGenericHTMLElement,
mMatchedNodes)
NS_IMPL_ADDREF_INHERITED(HTMLContentElement, Element)
NS_IMPL_RELEASE_INHERITED(HTMLContentElement, Element)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLContentElement)
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLContentElement)
JSObject*
HTMLContentElement::WrapNode(JSContext *aCx)
{
return HTMLContentElementBinding::Wrap(aCx, this);
}
nsresult
HTMLContentElement::BindToTree(nsIDocument* aDocument,
nsIContent* aParent,
nsIContent* aBindingParent,
bool aCompileEventHandlers)
{
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
aBindingParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
ShadowRoot* containingShadow = GetContainingShadow();
if (containingShadow && !oldContainingShadow) {
nsINode* parentNode = nsINode::GetParentNode();
while (parentNode && parentNode != containingShadow) {
if (parentNode->IsHTMLElement(nsGkAtoms::content)) {
// Content element in fallback content is not an insertion point.
return NS_OK;
}
parentNode = parentNode->GetParentNode();
}
// If the content element is being inserted into a ShadowRoot,
// add this element to the list of insertion points.
mIsInsertionPoint = true;
containingShadow->AddInsertionPoint(this);
containingShadow->SetInsertionPointChanged();
}
return NS_OK;
}
void
HTMLContentElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
oldContainingShadow->RemoveInsertionPoint(this);
// Remove all the matched nodes now that the
// insertion point is no longer an insertion point.
ClearMatchedNodes();
oldContainingShadow->SetInsertionPointChanged();
mIsInsertionPoint = false;
}
}
void
HTMLContentElement::AppendMatchedNode(nsIContent* aContent)
{
mMatchedNodes.AppendElement(aContent);
nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
destInsertionPoint.AppendElement(this);
if (mMatchedNodes.Length() == 1) {
// Fallback content gets dropped so we need to updated fallback
// content distribution.
UpdateFallbackDistribution();
}
}
void
HTMLContentElement::UpdateFallbackDistribution()
{
for (nsIContent* child = nsINode::GetFirstChild();
child;
child = child->GetNextSibling()) {
nsTArray<nsIContent*>& destInsertionPoint = child->DestInsertionPoints();
destInsertionPoint.Clear();
if (mMatchedNodes.IsEmpty()) {
destInsertionPoint.AppendElement(this);
}
}
}
void
HTMLContentElement::RemoveMatchedNode(nsIContent* aContent)
{
mMatchedNodes.RemoveElement(aContent);
ShadowRoot::RemoveDestInsertionPoint(this, aContent->DestInsertionPoints());
if (mMatchedNodes.IsEmpty()) {
// Fallback content is activated so we need to update fallback
// content distribution.
UpdateFallbackDistribution();
}
}
void
HTMLContentElement::InsertMatchedNode(uint32_t aIndex, nsIContent* aContent)
{
mMatchedNodes.InsertElementAt(aIndex, aContent);
nsTArray<nsIContent*>& destInsertionPoint = aContent->DestInsertionPoints();
destInsertionPoint.AppendElement(this);
if (mMatchedNodes.Length() == 1) {
// Fallback content gets dropped so we need to updated fallback
// content distribution.
UpdateFallbackDistribution();
}
}
void
HTMLContentElement::ClearMatchedNodes()
{
for (uint32_t i = 0; i < mMatchedNodes.Length(); i++) {
ShadowRoot::RemoveDestInsertionPoint(this, mMatchedNodes[i]->DestInsertionPoints());
}
mMatchedNodes.Clear();
UpdateFallbackDistribution();
}
static bool
IsValidContentSelectors(nsCSSSelector* aSelector)
{
nsCSSSelector* currentSelector = aSelector;
while (currentSelector) {
// Blacklist invalid selector fragments.
if (currentSelector->IsPseudoElement() ||
currentSelector->mPseudoClassList ||
currentSelector->mNegations ||
currentSelector->mOperator) {
return false;
}
currentSelector = currentSelector->mNext;
}
return true;
}
nsresult
HTMLContentElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
bool aNotify)
{
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
aValue, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::select) {
// Select attribute was updated, the insertion point may match different
// elements.
nsIDocument* doc = OwnerDoc();
nsCSSParser parser(doc->CSSLoader());
mValidSelector = true;
mSelectorList = nullptr;
nsresult rv = parser.ParseSelectorString(aValue,
doc->GetDocumentURI(),
// Bug 11240
0, // XXX get the line number!
getter_Transfers(mSelectorList));
// We don't want to return an exception if parsing failed because
// the spec does not define it as an exception case.
if (NS_SUCCEEDED(rv)) {
// Ensure that all the selectors are valid
nsCSSSelectorList* selectors = mSelectorList;
while (selectors) {
if (!IsValidContentSelectors(selectors->mSelectors)) {
// If we have an invalid selector, we can not match anything.
mValidSelector = false;
mSelectorList = nullptr;
break;
}
selectors = selectors->mNext;
}
}
ShadowRoot* containingShadow = GetContainingShadow();
if (containingShadow) {
containingShadow->DistributeAllNodes();
}
}
return NS_OK;
}
nsresult
HTMLContentElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
bool aNotify)
{
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID,
aAttribute, aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::select) {
// The select attribute was removed. This insertion point becomes
// a universal selector.
mValidSelector = true;
mSelectorList = nullptr;
ShadowRoot* containingShadow = GetContainingShadow();
if (containingShadow) {
containingShadow->DistributeAllNodes();
}
}
return NS_OK;
}
bool
HTMLContentElement::Match(nsIContent* aContent)
{
if (!mValidSelector) {
return false;
}
if (mSelectorList) {
nsIDocument* doc = OwnerDoc();
ShadowRoot* containingShadow = GetContainingShadow();
nsIContent* host = containingShadow->GetHost();
TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
doc, TreeMatchContext::eNeverMatchVisited);
doc->FlushPendingLinkUpdates();
matchingContext.SetHasSpecifiedScope();
matchingContext.AddScopeElement(host->AsElement());
if (!aContent->IsElement()) {
return false;
}
return nsCSSRuleProcessor::SelectorListMatches(aContent->AsElement(),
matchingContext,
mSelectorList);
}
return true;
}
already_AddRefed<DistributedContentList>
HTMLContentElement::GetDistributedNodes()
{
nsRefPtr<DistributedContentList> list = new DistributedContentList(this);
return list.forget();
}
NS_IMPL_CYCLE_COLLECTION(DistributedContentList, mParent, mDistributedNodes)
NS_INTERFACE_TABLE_HEAD(DistributedContentList)
NS_INTERFACE_TABLE(DistributedContentList, nsINodeList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DistributedContentList)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DistributedContentList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DistributedContentList)
DistributedContentList::DistributedContentList(HTMLContentElement* aHostElement)
: mParent(aHostElement)
{
MOZ_COUNT_CTOR(DistributedContentList);
if (aHostElement->IsInsertionPoint()) {
if (aHostElement->MatchedNodes().IsEmpty()) {
// Fallback content.
nsINode* contentNode = aHostElement;
for (nsIContent* content = contentNode->GetFirstChild();
content;
content = content->GetNextSibling()) {
mDistributedNodes.AppendElement(content);
}
} else {
mDistributedNodes.AppendElements(aHostElement->MatchedNodes());
}
}
}
DistributedContentList::~DistributedContentList()
{
MOZ_COUNT_DTOR(DistributedContentList);
}
nsIContent*
DistributedContentList::Item(uint32_t aIndex)
{
return mDistributedNodes.SafeElementAt(aIndex);
}
NS_IMETHODIMP
DistributedContentList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
{
nsIContent* item = Item(aIndex);
if (!item) {
return NS_ERROR_FAILURE;
}
return CallQueryInterface(item, aReturn);
}
NS_IMETHODIMP
DistributedContentList::GetLength(uint32_t* aLength)
{
*aLength = mDistributedNodes.Length();
return NS_OK;
}
int32_t
DistributedContentList::IndexOf(nsIContent* aContent)
{
return mDistributedNodes.IndexOf(aContent);
}
JSObject*
DistributedContentList::WrapObject(JSContext* aCx)
{
return NodeListBinding::Wrap(aCx, this);
}