Update Shadow DOM to v1 spec.
parent
9d6286a2fe
commit
8819de769f
|
@ -436,23 +436,22 @@ nsresult nsChromeRegistry::RefreshWindow(nsPIDOMWindowOuter* aWindow)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
int32_t count = document->GetNumberOfStyleSheets();
|
||||
size_t count = document->SheetCount();
|
||||
|
||||
// Build an array of style sheets we need to reload.
|
||||
nsTArray<RefPtr<StyleSheet>> oldSheets(count);
|
||||
nsTArray<RefPtr<StyleSheet>> newSheets(count);
|
||||
|
||||
// Iterate over the style sheets.
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
// Get the style sheet
|
||||
StyleSheet* styleSheet = document->GetStyleSheetAt(i);
|
||||
oldSheets.AppendElement(styleSheet);
|
||||
oldSheets.AppendElement(document->SheetAt(i));
|
||||
}
|
||||
|
||||
// Iterate over our old sheets and kick off a sync load of the new
|
||||
// sheet if and only if it's a non-inline sheet with a chrome URL.
|
||||
for (StyleSheet* sheet : oldSheets) {
|
||||
MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
|
||||
MOZ_ASSERT(sheet, "SheetAt shouldn't return nullptr for "
|
||||
"in-range sheet indexes");
|
||||
nsIURI* uri = sheet->GetSheetURI();
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ function* testTopLeft(inspector, view) {
|
|||
let afterElement = children.nodes[children.nodes.length - 1];
|
||||
yield selectNode(afterElement, inspector);
|
||||
top = getComputedViewPropertyValue(view, "top");
|
||||
is(top, "50%", "The computed view shows the correct top");
|
||||
is(top, "96px", "The computed view shows the correct top");
|
||||
left = getComputedViewPropertyValue(view, "left");
|
||||
is(left, "50%", "The computed view shows the correct left");
|
||||
is(left, "96px", "The computed view shows the correct left");
|
||||
}
|
||||
|
|
|
@ -356,24 +356,16 @@ EffectCompositor::GetElementToRestyle(dom::Element* aElement,
|
|||
return aElement;
|
||||
}
|
||||
|
||||
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
|
||||
if (!primaryFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIFrame* pseudoFrame;
|
||||
if (aPseudoType == CSSPseudoElementType::before) {
|
||||
pseudoFrame = nsLayoutUtils::GetBeforeFrame(primaryFrame);
|
||||
} else if (aPseudoType == CSSPseudoElementType::after) {
|
||||
pseudoFrame = nsLayoutUtils::GetAfterFrame(primaryFrame);
|
||||
} else {
|
||||
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
|
||||
"other that :before or :after");
|
||||
return nullptr;
|
||||
return nsLayoutUtils::GetBeforePseudo(aElement);
|
||||
}
|
||||
if (!pseudoFrame) {
|
||||
return nullptr;
|
||||
if (aPseudoType == CSSPseudoElementType::after) {
|
||||
return nsLayoutUtils::GetAfterPseudo(aElement);
|
||||
}
|
||||
return pseudoFrame->GetContent()->AsElement();
|
||||
|
||||
NS_NOTREACHED("Should not try to get the element to restyle for a pseudo "
|
||||
"other that :before or :after");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1107,19 +1107,17 @@ KeyframeEffectReadOnly::GetAnimationFrame() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* frame;
|
||||
if (mTarget->mPseudoType == CSSPseudoElementType::before) {
|
||||
frame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
frame = nsLayoutUtils::GetBeforeFrame(mTarget->mElement);
|
||||
} else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
|
||||
frame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
frame = nsLayoutUtils::GetAfterFrame(mTarget->mElement);
|
||||
} else {
|
||||
frame = mTarget->mElement->GetPrimaryFrame();
|
||||
MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
|
||||
"unknown mTarget->mPseudoType");
|
||||
}
|
||||
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -71,10 +71,10 @@ ArchiveRequest::~ArchiveRequest()
|
|||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
ArchiveRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
ArchiveReader* aReader);
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(
|
||||
EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
public:
|
||||
// This is called by the DOMArchiveRequestEvent
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "AnonymousContent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/AnonymousContentBinding.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMHTMLCollection.h"
|
||||
|
@ -208,5 +209,31 @@ AnonymousContent::WrapObject(JSContext* aCx,
|
|||
return AnonymousContentBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
}
|
||||
|
||||
void
|
||||
AnonymousContent::GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||
const nsAString& aPropertyName,
|
||||
DOMString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Element* element = GetElementById(aElementId);
|
||||
if (!element) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = element->OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsComputedDOMStyle> cs =
|
||||
new nsComputedDOMStyle(element,
|
||||
NS_LITERAL_STRING(""),
|
||||
element->OwnerDoc(),
|
||||
nsComputedDOMStyle::eAll);
|
||||
aRv = cs->GetPropertyValue(aPropertyName, aResult);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -68,6 +68,11 @@ public:
|
|||
const Sequence<OwningNonNull<DOMRect>>& aRects,
|
||||
ErrorResult& aError);
|
||||
|
||||
void GetComputedStylePropertyValue(const nsAString& aElementId,
|
||||
const nsAString& aPropertyName,
|
||||
DOMString& aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~AnonymousContent();
|
||||
nsCOMPtr<Element> mContentNode;
|
||||
|
|
|
@ -344,7 +344,7 @@ Attr::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
|||
}
|
||||
|
||||
nsresult
|
||||
Attr::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
Attr::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
return NS_OK;
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
// nsIDOMAttr interface
|
||||
NS_DECL_NSIDOMATTR
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
// nsIAttribute interface
|
||||
void SetMap(nsDOMAttributeMap *aMap) override;
|
||||
|
|
|
@ -6,61 +6,27 @@
|
|||
|
||||
#include "ChildIterator.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/XBLChildrenElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MatchedNodes {
|
||||
public:
|
||||
explicit MatchedNodes(HTMLContentElement* aInsertionPoint)
|
||||
: mIsContentElement(true), mContentElement(aInsertionPoint) {}
|
||||
|
||||
explicit MatchedNodes(XBLChildrenElement* aInsertionPoint)
|
||||
: mIsContentElement(false), mChildrenElement(aInsertionPoint) {}
|
||||
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes().Length()
|
||||
: mChildrenElement->InsertedChildrenLength();
|
||||
}
|
||||
|
||||
nsIContent* operator[](int32_t aIndex) const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes()[aIndex]
|
||||
: mChildrenElement->InsertedChild(aIndex);
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return mIsContentElement ? mContentElement->MatchedNodes().IsEmpty()
|
||||
: !mChildrenElement->HasInsertedChildren();
|
||||
}
|
||||
protected:
|
||||
bool mIsContentElement;
|
||||
union {
|
||||
HTMLContentElement* mContentElement;
|
||||
XBLChildrenElement* mChildrenElement;
|
||||
};
|
||||
};
|
||||
|
||||
static inline MatchedNodes
|
||||
GetMatchedNodesForPoint(nsIContent* aContent)
|
||||
ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIsFirst(aStartAtBeginning),
|
||||
mIndexInInserted(0)
|
||||
{
|
||||
if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
|
||||
// XBL case
|
||||
return MatchedNodes(static_cast<XBLChildrenElement*>(aContent));
|
||||
}
|
||||
|
||||
// Web components case
|
||||
MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::content));
|
||||
return MatchedNodes(HTMLContentElement::FromContent(aContent));
|
||||
mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
|
||||
HTMLSlotElement::FromContent(mParent) : nullptr;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
|
@ -69,30 +35,29 @@ ExplicitChildIterator::GetNextChild()
|
|||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
|
||||
MOZ_ASSERT(!mDefaultChild);
|
||||
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (mIndexInInserted < assignedChildren.Length()) {
|
||||
return assignedChildren[mIndexInInserted++];
|
||||
}
|
||||
mIndexInInserted = 0;
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mShadowIterator) {
|
||||
// If we're inside of a <shadow> element, look through the
|
||||
// explicit children of the projected ShadowRoot via
|
||||
// the mShadowIterator.
|
||||
nsIContent* nextChild = mShadowIterator->GetNextChild();
|
||||
if (nextChild) {
|
||||
return nextChild;
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (mIndexInInserted < assignedNodes.Length()) ?
|
||||
assignedNodes[mIndexInInserted++]->AsContent() : nullptr;
|
||||
return mChild;
|
||||
}
|
||||
|
||||
mShadowIterator = nullptr;
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement =
|
||||
static_cast<XBLChildrenElement*>(mChild);
|
||||
if (mIndexInInserted < childrenElement->InsertedChildrenLength()) {
|
||||
return childrenElement->InsertedChild(mIndexInInserted++);
|
||||
}
|
||||
mIndexInInserted = 0;
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
MOZ_ASSERT(mChild);
|
||||
MOZ_ASSERT(nsContentUtils::IsContentInsertionPoint(mChild));
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
|
||||
mDefaultChild = mDefaultChild->GetNextSibling();
|
||||
if (mDefaultChild) {
|
||||
|
@ -101,6 +66,19 @@ ExplicitChildIterator::GetNextChild()
|
|||
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (mIsFirst) { // at the beginning of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = 1;
|
||||
mChild = assignedNodes[0]->AsContent();
|
||||
mIsFirst = false;
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetFirstChild();
|
||||
mIsFirst = false;
|
||||
} else if (mChild) { // in the middle of the child list
|
||||
|
@ -110,31 +88,16 @@ ExplicitChildIterator::GetNextChild()
|
|||
// Iterate until we find a non-insertion point, or an insertion point with
|
||||
// content.
|
||||
while (mChild) {
|
||||
// If the current child being iterated is a shadow insertion point then
|
||||
// the iterator needs to go into the projected ShadowRoot.
|
||||
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
|
||||
// Look for the next child in the projected ShadowRoot for the <shadow>
|
||||
// element.
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
|
||||
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
mShadowIterator = new ExplicitChildIterator(projectedShadow);
|
||||
nsIContent* nextChild = mShadowIterator->GetNextChild();
|
||||
if (nextChild) {
|
||||
return nextChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
}
|
||||
mChild = mChild->GetNextSibling();
|
||||
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
|
||||
if (mChild->IsActiveChildrenElement()) {
|
||||
// If the current child being iterated is a content insertion point
|
||||
// then the iterator needs to return the nodes distributed into
|
||||
// the content insertion point.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (!assignedChildren.IsEmpty()) {
|
||||
auto* childrenElement =
|
||||
static_cast<XBLChildrenElement*>(mChild);
|
||||
if (childrenElement->HasInsertedChildren()) {
|
||||
// Iterate through elements projected on insertion point.
|
||||
mIndexInInserted = 1;
|
||||
return assignedChildren[0];
|
||||
return childrenElement->InsertedChild(0);
|
||||
}
|
||||
|
||||
// Insertion points inside fallback/default content
|
||||
|
@ -192,19 +155,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
|
|||
}
|
||||
|
||||
bool
|
||||
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
|
||||
ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
|
||||
{
|
||||
if (aChildToFind->GetParent() == mParent &&
|
||||
!aChildToFind->IsRootOfAnonymousSubtree()) {
|
||||
// Fast path: just point ourselves to aChildToFind, which is a
|
||||
// normal DOM child of ours.
|
||||
MOZ_ASSERT(!ShadowRoot::IsShadowInsertionPoint(aChildToFind));
|
||||
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
|
||||
mChild = aChildToFind;
|
||||
mChild = const_cast<nsIContent*>(aChildToFind);
|
||||
mIndexInInserted = 0;
|
||||
mShadowIterator = nullptr;
|
||||
mDefaultChild = nullptr;
|
||||
mIsFirst = false;
|
||||
MOZ_ASSERT(!mChild->IsActiveChildrenElement());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -220,12 +181,18 @@ ExplicitChildIterator::Get() const
|
|||
{
|
||||
MOZ_ASSERT(!mIsFirst);
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
} else if (mShadowIterator) {
|
||||
return mShadowIterator->Get();
|
||||
// When mParentAsSlot is set, mChild is always set to the current child. It
|
||||
// does not matter whether mChild is an assigned node or a fallback content.
|
||||
if (mParentAsSlot) {
|
||||
return mChild;
|
||||
}
|
||||
|
||||
if (mIndexInInserted) {
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
|
||||
return mDefaultChild ? mDefaultChild : mChild;
|
||||
}
|
||||
|
||||
|
@ -234,20 +201,28 @@ ExplicitChildIterator::GetPreviousChild()
|
|||
{
|
||||
// If we're already in the inserted-children array, look there first
|
||||
if (mIndexInInserted) {
|
||||
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
|
||||
mChild = (--mIndexInInserted) ?
|
||||
assignedNodes[mIndexInInserted - 1]->AsContent() : nullptr;
|
||||
|
||||
if (!mChild) {
|
||||
mIsFirst = true;
|
||||
}
|
||||
return mChild;
|
||||
}
|
||||
|
||||
// NB: mIndexInInserted points one past the last returned child so we need
|
||||
// to look *two* indices back in order to return the previous child.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
MOZ_ASSERT(mChild->IsActiveChildrenElement());
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
if (--mIndexInInserted) {
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (mShadowIterator) {
|
||||
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
|
||||
if (previousChild) {
|
||||
return previousChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (mDefaultChild) {
|
||||
// If we're already in default content, check if there are more nodes there
|
||||
mDefaultChild = mDefaultChild->GetPreviousSibling();
|
||||
|
@ -261,35 +236,32 @@ ExplicitChildIterator::GetPreviousChild()
|
|||
} else if (mChild) { // in the middle of the child list
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else { // at the end of the child list
|
||||
// For slot parent, iterate over assigned nodes if not empty, otherwise
|
||||
// fall through and iterate over direct children (fallback content).
|
||||
if (mParentAsSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes =
|
||||
mParentAsSlot->AssignedNodes();
|
||||
if (!assignedNodes.IsEmpty()) {
|
||||
mIndexInInserted = assignedNodes.Length();
|
||||
mChild = assignedNodes[mIndexInInserted - 1]->AsContent();
|
||||
return mChild;
|
||||
}
|
||||
}
|
||||
|
||||
mChild = mParent->GetLastChild();
|
||||
}
|
||||
|
||||
// Iterate until we find a non-insertion point, or an insertion point with
|
||||
// content.
|
||||
while (mChild) {
|
||||
if (ShadowRoot::IsShadowInsertionPoint(mChild)) {
|
||||
// If the current child being iterated is a shadow insertion point then
|
||||
// the iterator needs to go into the projected ShadowRoot.
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(mChild);
|
||||
ShadowRoot* projectedShadow = shadowElem->GetOlderShadowRoot();
|
||||
if (projectedShadow) {
|
||||
// Create a ExplicitChildIterator that begins iterating from the end.
|
||||
mShadowIterator = new ExplicitChildIterator(projectedShadow, false);
|
||||
nsIContent* previousChild = mShadowIterator->GetPreviousChild();
|
||||
if (previousChild) {
|
||||
return previousChild;
|
||||
}
|
||||
mShadowIterator = nullptr;
|
||||
}
|
||||
mChild = mChild->GetPreviousSibling();
|
||||
} else if (nsContentUtils::IsContentInsertionPoint(mChild)) {
|
||||
if (mChild->IsActiveChildrenElement()) {
|
||||
// If the current child being iterated is a content insertion point
|
||||
// then the iterator needs to return the nodes distributed into
|
||||
// the content insertion point.
|
||||
MatchedNodes assignedChildren = GetMatchedNodesForPoint(mChild);
|
||||
if (!assignedChildren.IsEmpty()) {
|
||||
mIndexInInserted = assignedChildren.Length();
|
||||
return assignedChildren[mIndexInInserted - 1];
|
||||
auto* childrenElement = static_cast<XBLChildrenElement*>(mChild);
|
||||
if (childrenElement->HasInsertedChildren()) {
|
||||
mIndexInInserted = childrenElement->InsertedChildrenLength();
|
||||
return childrenElement->InsertedChild(mIndexInInserted - 1);
|
||||
}
|
||||
|
||||
mDefaultChild = mChild->GetLastChild();
|
||||
|
@ -317,11 +289,9 @@ AllChildrenIterator::Get() const
|
|||
{
|
||||
switch (mPhase) {
|
||||
case eAtBeforeKid: {
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
MOZ_ASSERT(frame, "No frame at eAtBeforeKid phase");
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
MOZ_ASSERT(beforeFrame, "No content before frame at eAtBeforeKid phase");
|
||||
return beforeFrame->GetContent();
|
||||
Element* before = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
MOZ_ASSERT(before, "No content before frame at eAtBeforeKid phase");
|
||||
return before;
|
||||
}
|
||||
|
||||
case eAtExplicitKids:
|
||||
|
@ -331,11 +301,9 @@ AllChildrenIterator::Get() const
|
|||
return mAnonKids[mAnonKidsIdx];
|
||||
|
||||
case eAtAfterKid: {
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
MOZ_ASSERT(frame, "No frame at eAtAfterKid phase");
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
MOZ_ASSERT(afterFrame, "No content before frame at eAtBeforeKid phase");
|
||||
return afterFrame->GetContent();
|
||||
Element* after = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
MOZ_ASSERT(after, "No content after frame at eAtAfterKid phase");
|
||||
return after;
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -345,19 +313,14 @@ AllChildrenIterator::Get() const
|
|||
|
||||
|
||||
bool
|
||||
AllChildrenIterator::Seek(nsIContent* aChildToFind)
|
||||
AllChildrenIterator::Seek(const nsIContent* aChildToFind)
|
||||
{
|
||||
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
|
||||
mPhase = eAtExplicitKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
if (beforeFrame->GetContent() == aChildToFind) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Element* beforePseudo = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforePseudo && beforePseudo == aChildToFind) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,12 +346,10 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
|
|||
|
||||
// The root scroll frame is not the primary frame of the root element.
|
||||
// Detect and handle this case.
|
||||
if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
|
||||
nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
|
||||
nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
|
||||
if (scrollFrame) {
|
||||
AppendNativeAnonymousChildrenFromFrame(scrollFrame);
|
||||
}
|
||||
if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
|
||||
mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
|
||||
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
mOriginalContent->OwnerDoc(), mAnonKids);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,13 +367,10 @@ AllChildrenIterator::GetNextChild()
|
|||
{
|
||||
if (mPhase == eAtBegin) {
|
||||
mPhase = eAtExplicitKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeFrame->GetContent();
|
||||
}
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,13 +406,10 @@ AllChildrenIterator::GetNextChild()
|
|||
return mAnonKids[mAnonKidsIdx];
|
||||
}
|
||||
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
if (afterFrame) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterFrame->GetContent();
|
||||
}
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,13 +423,10 @@ AllChildrenIterator::GetPreviousChild()
|
|||
if (mPhase == eAtEnd) {
|
||||
MOZ_ASSERT(mAnonKidsIdx == mAnonKids.Length());
|
||||
mPhase = eAtAnonKids;
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* afterFrame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
if (afterFrame) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterFrame->GetContent();
|
||||
}
|
||||
Element* afterContent = nsLayoutUtils::GetAfterPseudo(mOriginalContent);
|
||||
if (afterContent) {
|
||||
mPhase = eAtAfterKid;
|
||||
return afterContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -503,13 +455,10 @@ AllChildrenIterator::GetPreviousChild()
|
|||
return kid;
|
||||
}
|
||||
|
||||
nsIFrame* frame = mOriginalContent->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
nsIFrame* beforeFrame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
if (beforeFrame) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeFrame->GetContent();
|
||||
}
|
||||
Element* beforeContent = nsLayoutUtils::GetBeforePseudo(mOriginalContent);
|
||||
if (beforeContent) {
|
||||
mPhase = eAtBeforeKid;
|
||||
return beforeContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -585,12 +534,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
|
|||
return true;
|
||||
}
|
||||
|
||||
// The root element has a scroll frame that is not the primary frame, so we
|
||||
// need to do special checking for that case.
|
||||
if (aElement == aElement->OwnerDoc()->GetRootElement()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,27 +36,20 @@ class ExplicitChildIterator
|
|||
{
|
||||
public:
|
||||
explicit ExplicitChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: mParent(aParent),
|
||||
mChild(nullptr),
|
||||
mDefaultChild(nullptr),
|
||||
mIndexInInserted(0),
|
||||
mIsFirst(aStartAtBeginning)
|
||||
{
|
||||
}
|
||||
bool aStartAtBeginning = true);
|
||||
|
||||
ExplicitChildIterator(const ExplicitChildIterator& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mShadowIterator(aOther.mShadowIterator ?
|
||||
new ExplicitChildIterator(*aOther.mShadowIterator) :
|
||||
nullptr),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
ExplicitChildIterator(ExplicitChildIterator&& aOther)
|
||||
: mParent(aOther.mParent), mChild(aOther.mChild),
|
||||
: mParent(aOther.mParent),
|
||||
mParentAsSlot(aOther.mParentAsSlot),
|
||||
mChild(aOther.mChild),
|
||||
mDefaultChild(aOther.mDefaultChild),
|
||||
mShadowIterator(Move(aOther.mShadowIterator)),
|
||||
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
|
||||
|
||||
nsIContent* GetNextChild();
|
||||
|
@ -65,13 +58,13 @@ public:
|
|||
// found. This version can take shortcuts that the two-argument version
|
||||
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
|
||||
// cases).
|
||||
bool Seek(nsIContent* aChildToFind);
|
||||
bool Seek(const nsIContent* aChildToFind);
|
||||
|
||||
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
|
||||
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
|
||||
// whether aChildToFind was found as an explicit child prior to encountering
|
||||
// aBound.
|
||||
bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
|
||||
bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
|
||||
{
|
||||
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
||||
// we might not find aChildToFind when called from ContentInserted
|
||||
|
@ -102,6 +95,10 @@ protected:
|
|||
// the <xbl:content> element for the binding.
|
||||
const nsIContent* mParent;
|
||||
|
||||
// If parent is a slot element, this points to the parent as HTMLSlotElement,
|
||||
// otherwise, it's null.
|
||||
const HTMLSlotElement* mParentAsSlot;
|
||||
|
||||
// The current child. When we encounter an insertion point,
|
||||
// mChild remains as the insertion point whose content we're iterating (and
|
||||
// our state is controled by mDefaultChild or mIndexInInserted depending on
|
||||
|
@ -114,11 +111,6 @@ protected:
|
|||
// to null, we continue iterating at mChild's next sibling.
|
||||
nsIContent* mDefaultChild;
|
||||
|
||||
// If non-null, this points to an iterator of the explicit children of
|
||||
// the ShadowRoot projected by the current shadow element that we're
|
||||
// iterating.
|
||||
nsAutoPtr<ExplicitChildIterator> mShadowIterator;
|
||||
|
||||
// If not zero, we're iterating inserted children for an insertion point. This
|
||||
// is an index into mChild's inserted children array (mChild must be an
|
||||
// nsXBLChildrenElement). The index is one past the "current" child (as
|
||||
|
@ -139,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
|
|||
public:
|
||||
explicit FlattenedChildIterator(const nsIContent* aParent,
|
||||
bool aStartAtBeginning = true)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||
, mXBLInvolved(false)
|
||||
, mOriginalContent(aParent)
|
||||
{
|
||||
Init(false);
|
||||
}
|
||||
|
||||
FlattenedChildIterator(FlattenedChildIterator&& aOther)
|
||||
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
|
||||
: ExplicitChildIterator(Move(aOther))
|
||||
, mXBLInvolved(aOther.mXBLInvolved)
|
||||
, mOriginalContent(aOther.mOriginalContent)
|
||||
{}
|
||||
|
||||
FlattenedChildIterator(const FlattenedChildIterator& aOther)
|
||||
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
|
||||
: ExplicitChildIterator(aOther)
|
||||
, mXBLInvolved(aOther.mXBLInvolved)
|
||||
, mOriginalContent(aOther.mOriginalContent)
|
||||
{}
|
||||
|
||||
bool XBLInvolved() { return mXBLInvolved; }
|
||||
|
||||
const nsIContent* Parent() const { return mOriginalContent; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This constructor is a hack to help AllChildrenIterator which sometimes
|
||||
|
@ -159,7 +161,9 @@ protected:
|
|||
*/
|
||||
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
|
||||
bool aStartAtBeginning = true)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
||||
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||
, mXBLInvolved(false)
|
||||
, mOriginalContent(aParent)
|
||||
{
|
||||
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
|
||||
Init(ignoreXBL);
|
||||
|
@ -170,6 +174,8 @@ protected:
|
|||
// For certain optimizations, nsCSSFrameConstructor needs to know if the
|
||||
// child list of the element that we're iterating matches its .childNodes.
|
||||
bool mXBLInvolved;
|
||||
|
||||
const nsIContent* mOriginalContent;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -187,12 +193,11 @@ public:
|
|||
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
|
||||
bool aStartAtBeginning = true) :
|
||||
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
|
||||
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
||||
mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
||||
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
|
||||
|
||||
AllChildrenIterator(AllChildrenIterator&& aOther)
|
||||
: FlattenedChildIterator(Move(aOther)),
|
||||
mOriginalContent(aOther.mOriginalContent),
|
||||
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
|
||||
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
|
||||
#ifdef DEBUG
|
||||
|
@ -211,11 +216,10 @@ public:
|
|||
// Seeks the given node in children of a parent element, starting from
|
||||
// the current iterator's position, and sets the iterator at the given child
|
||||
// node if it was found.
|
||||
bool Seek(nsIContent* aChildToFind);
|
||||
bool Seek(const nsIContent* aChildToFind);
|
||||
|
||||
nsIContent* GetNextChild();
|
||||
nsIContent* GetPreviousChild();
|
||||
const nsIContent* Parent() const { return mOriginalContent; }
|
||||
|
||||
enum IteratorPhase
|
||||
{
|
||||
|
@ -233,8 +237,6 @@ private:
|
|||
void AppendNativeAnonymousChildren();
|
||||
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
|
||||
|
||||
const nsIContent* mOriginalContent;
|
||||
|
||||
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
||||
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
|
||||
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
|
||||
|
@ -256,10 +258,11 @@ private:
|
|||
/**
|
||||
* StyleChildrenIterator traverses the children of the element from the
|
||||
* perspective of the style system, particularly the children we need to traverse
|
||||
* during restyle. This is identical to AllChildrenIterator with eAllChildren,
|
||||
* _except_ that we detect and skip any native anonymous children that are used
|
||||
* to implement pseudo-elements (since the style system needs to cascade those
|
||||
* using different algorithms).
|
||||
* during restyle. This is identical to AllChildrenIterator with
|
||||
* (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
|
||||
* detect and skip any native anonymous children that are used to implement
|
||||
* pseudo-elements (since the style system needs to cascade those using
|
||||
* different algorithms).
|
||||
*
|
||||
* Note: it assumes that no mutation of the DOM or frame tree takes place during
|
||||
* iteration, and will break horribly if that is not true.
|
||||
|
@ -267,7 +270,9 @@ private:
|
|||
class StyleChildrenIterator : private AllChildrenIterator {
|
||||
public:
|
||||
explicit StyleChildrenIterator(const nsIContent* aContent)
|
||||
: AllChildrenIterator(aContent, nsIContent::eAllChildren)
|
||||
: AllChildrenIterator(aContent,
|
||||
nsIContent::eAllChildren |
|
||||
nsIContent::eSkipDocumentLevelNativeAnonymousContent)
|
||||
{
|
||||
MOZ_COUNT_CTOR(StyleChildrenIterator);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -294,7 +294,6 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy
|
|||
nsTArray<nsWeakPtr>* unresolved = mCandidatesMap.LookupOrAdd(typeName);
|
||||
nsWeakPtr* elem = unresolved->AppendElement();
|
||||
*elem = do_GetWeakReference(aElement);
|
||||
aElement->AddStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -417,19 +416,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype)
|
||||
{
|
||||
mozilla::dom::CustomElementDefinition* definition =
|
||||
mCustomDefinitions.GetWeak(aAtom);
|
||||
if (definition) {
|
||||
aPrototype.set(definition->mPrototype);
|
||||
} else {
|
||||
aPrototype.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::UpgradeCandidates(nsIAtom* aKey,
|
||||
CustomElementDefinition* aDefinition,
|
||||
|
@ -469,6 +455,12 @@ nsISupports* CustomElementRegistry::GetParentObject() const
|
|||
return mWindow;
|
||||
}
|
||||
|
||||
DocGroup*
|
||||
CustomElementRegistry::GetDocGroup() const
|
||||
{
|
||||
return mWindow ? mWindow->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
||||
static const char* kLifeCycleCallbackNames[] = {
|
||||
"connectedCallback",
|
||||
"disconnectedCallback",
|
||||
|
@ -591,14 +583,8 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
return;
|
||||
}
|
||||
|
||||
nsIParserService* ps = nsContentUtils::GetParserService();
|
||||
if (!ps) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// bgsound and multicol are unknown html element.
|
||||
int32_t tag = ps->HTMLCaseSensitiveAtomTagToId(extendsAtom);
|
||||
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
|
||||
if (tag == eHTMLTag_userdefined ||
|
||||
tag == eHTMLTag_bgsound ||
|
||||
tag == eHTMLTag_multicol) {
|
||||
|
@ -633,9 +619,9 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
*/
|
||||
JSAutoCompartment ac(cx, constructor);
|
||||
JS::Rooted<JS::Value> prototypev(cx);
|
||||
// The .prototype on the constructor passed from document.registerElement
|
||||
// is the "expando" of a wrapper. So we should get it from wrapper instead
|
||||
// instead of underlying object.
|
||||
// The .prototype on the constructor passed could be an "expando" of a
|
||||
// wrapper. So we should get it from wrapper instead of the underlying
|
||||
// object.
|
||||
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
|
@ -881,8 +867,6 @@ CustomElementRegistry::Upgrade(Element* aElement,
|
|||
CustomElementDefinition* aDefinition,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
RefPtr<CustomElementData> data = aElement->GetCustomElementData();
|
||||
MOZ_ASSERT(data, "CustomElementData should exist");
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ struct CustomElementData;
|
|||
struct ElementDefinitionOptions;
|
||||
class CallbackFunction;
|
||||
class CustomElementReaction;
|
||||
class DocGroup;
|
||||
class Function;
|
||||
class Promise;
|
||||
|
||||
|
@ -423,9 +424,6 @@ public:
|
|||
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||
CustomElementDefinition* aDefinition);
|
||||
|
||||
void GetCustomPrototype(nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype);
|
||||
|
||||
/**
|
||||
* Upgrade an element.
|
||||
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
|
||||
|
@ -434,8 +432,7 @@ public:
|
|||
|
||||
/**
|
||||
* Registers an unresolved custom element that is a candidate for
|
||||
* upgrade when the definition is registered via registerElement.
|
||||
* |aTypeName| is the name of the custom element type, if it is not
|
||||
* upgrade. |aTypeName| is the name of the custom element type, if it is not
|
||||
* provided, then element name is used. |aTypeName| should be provided
|
||||
* when registering a custom element that extends an existing
|
||||
* element. e.g. <button is="x-button">.
|
||||
|
@ -472,8 +469,8 @@ private:
|
|||
js::SystemAllocPolicy> ConstructorMap;
|
||||
|
||||
// Hashtable for custom element definitions in web components.
|
||||
// Custom prototypes are stored in the compartment where
|
||||
// registerElement was called.
|
||||
// Custom prototypes are stored in the compartment where definition was
|
||||
// defined.
|
||||
DefinitionMap mCustomDefinitions;
|
||||
|
||||
// Hashtable for looking up definitions by using constructor as key.
|
||||
|
@ -517,6 +514,8 @@ private:
|
|||
public:
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void Define(const nsAString& aName, Function& aFunctionConstructor,
|
||||
|
|
|
@ -728,7 +728,7 @@ WalkDescendantsResetAutoDirection(Element* aElement)
|
|||
{
|
||||
nsIContent* child = aElement->GetFirstChild();
|
||||
while (child) {
|
||||
if (child->HasDirAuto()) {
|
||||
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
|
||||
child = child->GetNextNonChildNode(aElement);
|
||||
continue;
|
||||
}
|
||||
|
@ -791,7 +791,7 @@ WalkDescendantsClearAncestorDirAuto(Element* aElement)
|
|||
{
|
||||
nsIContent* child = aElement->GetFirstChild();
|
||||
while (child) {
|
||||
if (child->HasDirAuto()) {
|
||||
if (child->IsElement() && child->AsElement()->HasDirAuto()) {
|
||||
child = child->GetNextNonChildNode(aElement);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/* 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/DocGroup.h"
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
@ -7,10 +11,13 @@
|
|||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
|
||||
|
||||
/* static */ void
|
||||
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
|
||||
{
|
||||
|
@ -55,5 +62,23 @@ DocGroup::~DocGroup()
|
|||
|
||||
NS_IMPL_ISUPPORTS(DocGroup, nsISupports)
|
||||
|
||||
void
|
||||
DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
|
||||
{
|
||||
if (mSignalSlotList.Contains(aSlot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
|
||||
|
||||
if (!sPendingDocGroups) {
|
||||
// Queue a mutation observer compound microtask.
|
||||
nsDOMMutationObserver::QueueMutationObserverMicroTask();
|
||||
sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
|
||||
}
|
||||
|
||||
sPendingDocGroups->AppendElement(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -74,6 +75,23 @@ public:
|
|||
return mDocuments.end();
|
||||
}
|
||||
|
||||
// Append aSlot to the list of signal slot list, if it's not in it already
|
||||
// list, and queue a mutation observer microtask.
|
||||
void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
|
||||
|
||||
const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
|
||||
{
|
||||
return mSignalSlotList;
|
||||
}
|
||||
|
||||
void ClearSignalSlotList()
|
||||
{
|
||||
mSignalSlotList.Clear();
|
||||
}
|
||||
|
||||
// List of DocGroups that has non-empty signal slot list.
|
||||
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
|
||||
|
||||
private:
|
||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||
~DocGroup();
|
||||
|
@ -82,6 +100,7 @@ private:
|
|||
RefPtr<TabGroup> mTabGroup;
|
||||
nsTArray<nsIDocument*> mDocuments;
|
||||
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
||||
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -125,6 +125,8 @@ DocumentFragment::Constructor(const GlobalObject& aGlobal,
|
|||
return window->GetDoc()->CreateDocumentFragment();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(DocumentFragment, FragmentOrElement, mHost)
|
||||
|
||||
// QueryInterface implementation for DocumentFragment
|
||||
NS_INTERFACE_MAP_BEGIN(DocumentFragment)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocumentFragment, FragmentOrElement)
|
||||
|
||||
// interface nsIDOMNode
|
||||
NS_FORWARD_NSIDOMNODE_TO_NSINODE
|
||||
|
@ -121,15 +122,9 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* GetHost() const
|
||||
{
|
||||
return mHost;
|
||||
}
|
||||
Element* GetHost() const { return mHost; }
|
||||
|
||||
void SetHost(nsIContent* aHost)
|
||||
{
|
||||
mHost = aHost;
|
||||
}
|
||||
void SetHost(Element* aHost) { mHost = aHost; }
|
||||
|
||||
static already_AddRefed<DocumentFragment>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
@ -145,7 +140,7 @@ protected:
|
|||
}
|
||||
|
||||
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
nsIContent* mHost; // Weak
|
||||
nsCOMPtr<Element> mHost;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -166,8 +166,7 @@ nsIContent::DoGetID() const
|
|||
const nsAttrValue*
|
||||
Element::DoGetClasses() const
|
||||
{
|
||||
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
|
||||
|
||||
MOZ_ASSERT(MayHaveClass(), "Unexpected call");
|
||||
if (IsSVGElement()) {
|
||||
const nsAttrValue* animClass =
|
||||
static_cast<const nsSVGElement*>(this)->GetAnimatedClassName();
|
||||
|
@ -470,50 +469,11 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
|
|||
JSObject*
|
||||
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
|
||||
JS::Rooted<JSObject*> customProto(aCx);
|
||||
|
||||
if (!givenProto) {
|
||||
// Custom element prototype swizzling.
|
||||
CustomElementData* data = GetCustomElementData();
|
||||
if (data) {
|
||||
// If this is a registered custom element then fix the prototype.
|
||||
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
||||
data->GetCustomElementType(), &customProto);
|
||||
if (customProto &&
|
||||
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
|
||||
// The custom element prototype could be in different compartment.
|
||||
if (!JS_WrapObject(aCx, &customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
// Just go ahead and create with the right proto up front. Set
|
||||
// customProto to null to flag that we don't need to do any post-facto
|
||||
// proto fixups here.
|
||||
givenProto = customProto;
|
||||
customProto = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (customProto) {
|
||||
// We want to set the custom prototype in the compartment where it was
|
||||
// registered. In the case that |obj| and |prototype| are in different
|
||||
// compartments, this will set the prototype on the |obj|'s wrapper and
|
||||
// thus only visible in the wrapper's compartment, since we know obj's
|
||||
// principal does not subsume customProto's in this case.
|
||||
JSAutoCompartment ac(aCx, customProto);
|
||||
JS::Rooted<JSObject*> wrappedObj(aCx, obj);
|
||||
if (!JS_WrapObject(aCx, &wrappedObj) ||
|
||||
!JS_SetPrototype(aCx, wrappedObj, customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* doc;
|
||||
if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
doc = OwnerDoc();
|
||||
|
@ -1093,9 +1053,102 @@ Element::RemoveFromIdTable()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Element::SetSlot(const nsAString& aName, ErrorResult& aError)
|
||||
{
|
||||
aError = SetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName, true);
|
||||
}
|
||||
|
||||
void
|
||||
Element::GetSlot(nsAString& aName)
|
||||
{
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::slot, aName);
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-element-shadowroot
|
||||
ShadowRoot*
|
||||
Element::GetShadowRootByMode() const
|
||||
{
|
||||
/**
|
||||
* 1. Let shadow be context object’s shadow root.
|
||||
* 2. If shadow is null or its mode is "closed", then return null.
|
||||
*/
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
if (!shadowRoot || shadowRoot->IsClosed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. Return shadow.
|
||||
*/
|
||||
return shadowRoot;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-element-attachshadow
|
||||
already_AddRefed<ShadowRoot>
|
||||
Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError)
|
||||
{
|
||||
/**
|
||||
* 1. If context object’s namespace is not the HTML namespace,
|
||||
* then throw a "NotSupportedError" DOMException.
|
||||
*/
|
||||
if (!IsHTMLElement()) {
|
||||
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. If context object’s local name is not
|
||||
* a valid custom element name, "article", "aside", "blockquote",
|
||||
* "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
|
||||
* "header", "main" "nav", "p", "section", or "span",
|
||||
* then throw a "NotSupportedError" DOMException.
|
||||
*/
|
||||
nsIAtom* nameAtom = NodeInfo()->NameAtom();
|
||||
if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
|
||||
nameAtom == nsGkAtoms::article ||
|
||||
nameAtom == nsGkAtoms::aside ||
|
||||
nameAtom == nsGkAtoms::blockquote ||
|
||||
nameAtom == nsGkAtoms::body ||
|
||||
nameAtom == nsGkAtoms::div ||
|
||||
nameAtom == nsGkAtoms::footer ||
|
||||
nameAtom == nsGkAtoms::h1 ||
|
||||
nameAtom == nsGkAtoms::h2 ||
|
||||
nameAtom == nsGkAtoms::h3 ||
|
||||
nameAtom == nsGkAtoms::h4 ||
|
||||
nameAtom == nsGkAtoms::h5 ||
|
||||
nameAtom == nsGkAtoms::h6 ||
|
||||
nameAtom == nsGkAtoms::header ||
|
||||
nameAtom == nsGkAtoms::main ||
|
||||
nameAtom == nsGkAtoms::nav ||
|
||||
nameAtom == nsGkAtoms::p ||
|
||||
nameAtom == nsGkAtoms::section ||
|
||||
nameAtom == nsGkAtoms::span)) {
|
||||
aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return AttachShadowInternal(aInit.mMode == ShadowRootMode::Closed, aError);
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowRoot>
|
||||
Element::CreateShadowRoot(ErrorResult& aError)
|
||||
{
|
||||
return AttachShadowInternal(false, aError);
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowRoot>
|
||||
Element::AttachShadowInternal(bool aClosed, ErrorResult& aError)
|
||||
{
|
||||
/**
|
||||
* 3. If context object is a shadow host, then throw
|
||||
* an "InvalidStateError" DOMException.
|
||||
*/
|
||||
if (GetShadowRoot()) {
|
||||
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
|
||||
|
@ -1113,12 +1166,9 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIDocument* doc = GetComposedDoc();
|
||||
nsIContent* destroyedFramesFor = nullptr;
|
||||
if (doc) {
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (shell) {
|
||||
shell->DestroyFramesFor(this, &destroyedFramesFor);
|
||||
if (nsIDocument* doc = GetComposedDoc()) {
|
||||
if (nsIPresShell* shell = doc->GetShell()) {
|
||||
shell->DestroyFramesForAndRestyle(this);
|
||||
MOZ_ASSERT(!shell->FrameManager()->GetDisplayContentsStyleFor(this));
|
||||
}
|
||||
}
|
||||
|
@ -1130,29 +1180,20 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
|||
// Calling SetPrototypeBinding takes ownership of protoBinding.
|
||||
docInfo->SetPrototypeBinding(NS_LITERAL_CSTRING("shadowroot"), protoBinding);
|
||||
|
||||
RefPtr<ShadowRoot> shadowRoot = new ShadowRoot(this, nodeInfo.forget(),
|
||||
protoBinding);
|
||||
/**
|
||||
* 4. Let shadow be a new shadow root whose node document is
|
||||
* context object’s node document, host is context object,
|
||||
* and mode is init’s mode.
|
||||
*/
|
||||
RefPtr<ShadowRoot> shadowRoot =
|
||||
new ShadowRoot(this, aClosed, nodeInfo.forget(), protoBinding);
|
||||
|
||||
shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
|
||||
|
||||
// Replace the old ShadowRoot with the new one and let the old
|
||||
// ShadowRoot know about the younger ShadowRoot because the old
|
||||
// ShadowRoot is projected into the younger ShadowRoot's shadow
|
||||
// insertion point (if it exists).
|
||||
ShadowRoot* olderShadow = GetShadowRoot();
|
||||
/**
|
||||
* 5. Set context object’s shadow root to shadow.
|
||||
*/
|
||||
SetShadowRoot(shadowRoot);
|
||||
if (olderShadow) {
|
||||
olderShadow->SetYoungerShadow(shadowRoot);
|
||||
|
||||
// Unbind children of older shadow root because they
|
||||
// are no longer in the composed tree.
|
||||
for (nsIContent* child = olderShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
olderShadow->SetIsComposedDocParticipant(false);
|
||||
}
|
||||
|
||||
// xblBinding takes ownership of docInfo.
|
||||
RefPtr<nsXBLBinding> xblBinding = new nsXBLBinding(shadowRoot, protoBinding);
|
||||
|
@ -1161,96 +1202,12 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
|||
|
||||
SetXBLBinding(xblBinding);
|
||||
|
||||
// Recreate the frame for the bound content because binding a ShadowRoot
|
||||
// changes how things are rendered.
|
||||
if (doc) {
|
||||
MOZ_ASSERT(doc == GetComposedDoc());
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (shell) {
|
||||
shell->CreateFramesFor(destroyedFramesFor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. Return shadow.
|
||||
*/
|
||||
return shadowRoot.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DestinationInsertionPointList, mParent,
|
||||
mDestinationPoints)
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(DestinationInsertionPointList)
|
||||
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
|
||||
NS_INTERFACE_TABLE(DestinationInsertionPointList, nsINodeList, nsIDOMNodeList)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DestinationInsertionPointList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DestinationInsertionPointList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DestinationInsertionPointList)
|
||||
|
||||
DestinationInsertionPointList::DestinationInsertionPointList(Element* aElement)
|
||||
: mParent(aElement)
|
||||
{
|
||||
nsTArray<nsIContent*>* destPoints = aElement->GetExistingDestInsertionPoints();
|
||||
if (destPoints) {
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
mDestinationPoints.AppendElement(destPoints->ElementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DestinationInsertionPointList::~DestinationInsertionPointList()
|
||||
{
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
DestinationInsertionPointList::Item(uint32_t aIndex)
|
||||
{
|
||||
return mDestinationPoints.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DestinationInsertionPointList::Item(uint32_t aIndex, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsIContent* item = Item(aIndex);
|
||||
if (!item) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return CallQueryInterface(item, aReturn);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DestinationInsertionPointList::Length() const
|
||||
{
|
||||
return mDestinationPoints.Length();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DestinationInsertionPointList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
*aLength = Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
DestinationInsertionPointList::IndexOf(nsIContent* aContent)
|
||||
{
|
||||
return mDestinationPoints.IndexOf(aContent);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DestinationInsertionPointList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return NodeListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<DestinationInsertionPointList>
|
||||
Element::GetDestinationInsertionPoints()
|
||||
{
|
||||
RefPtr<DestinationInsertionPointList> list =
|
||||
new DestinationInsertionPointList(this);
|
||||
return list.forget();
|
||||
}
|
||||
|
||||
void
|
||||
Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
|
||||
{
|
||||
|
@ -2383,7 +2340,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
|||
bool aNotify,
|
||||
nsAttrValue& aOldValue,
|
||||
uint8_t* aModType,
|
||||
bool* aHasListeners)
|
||||
bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
bool modification = false;
|
||||
*aHasListeners = aNotify &&
|
||||
|
@ -2391,6 +2349,8 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
|||
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
||||
this);
|
||||
|
||||
*aOldValueSet = false;
|
||||
|
||||
// If we have no listeners and aNotify is false, we are almost certainly
|
||||
// coming from the content sink and will almost certainly have no previous
|
||||
// value. Even if we do, setting the value is cheap when we have no
|
||||
|
@ -2414,6 +2374,7 @@ Element::MaybeCheckSameAttrVal(int32_t aNamespaceID,
|
|||
// We have to serialize the value anyway in order to create the
|
||||
// mutation event so there's no cost in doing it now.
|
||||
aOldValue.SetToSerialized(*info.mValue);
|
||||
*aOldValueSet = true;
|
||||
}
|
||||
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
|
||||
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
|
||||
|
@ -2433,10 +2394,12 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
|||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners)
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet)
|
||||
{
|
||||
if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
|
||||
aOldValue, aModType, aHasListeners)) {
|
||||
aOldValue, aModType, aHasListeners,
|
||||
aOldValueSet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2445,12 +2408,45 @@ Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
|||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetSingleClassFromParser(nsIAtom* aSingleClassName)
|
||||
{
|
||||
// Keep this in sync with SetAttr and SetParsedAttr below.
|
||||
|
||||
if (!mAttrsAndChildren.CanFitMoreAttrs()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAttrValue value(aSingleClassName);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, false);
|
||||
|
||||
// In principle, BeforeSetAttr should be called here if a node type
|
||||
// existed that wanted to do something special for class, but there
|
||||
// is no such node type, so calling SetMayHaveClass() directly.
|
||||
SetMayHaveClass();
|
||||
|
||||
return SetAttrAndNotify(kNameSpaceID_None,
|
||||
nsGkAtoms::_class,
|
||||
nullptr, // prefix
|
||||
nullptr, // old value
|
||||
value,
|
||||
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION),
|
||||
false, // hasListeners
|
||||
false, // notify
|
||||
kCallAfterSetAttr,
|
||||
document,
|
||||
updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetParsedAttr below
|
||||
// Keep this in sync with SetParsedAttr below and SetSingleClassFromParser
|
||||
// above.
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
|
@ -2462,17 +2458,27 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|||
|
||||
uint8_t modType;
|
||||
bool hasListeners;
|
||||
// We don't want to spend time preparsing class attributes if the value is not
|
||||
// changing, so just init our nsAttrValueOrString with aValue for the
|
||||
// OnlyNotifySameValueSet call.
|
||||
nsAttrValueOrString value(aValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
|
||||
nsAttrValue attrValue;
|
||||
nsAttrValue* preparsedAttrValue;
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::_class) {
|
||||
attrValue.ParseAtomArray(aValue);
|
||||
value.ResetToAttrValue(attrValue);
|
||||
preparsedAttrValue = &attrValue;
|
||||
} else {
|
||||
preparsedAttrValue = nullptr;
|
||||
}
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
|
@ -2481,21 +2487,23 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|||
|
||||
// Hold a script blocker while calling ParseAttribute since that can call
|
||||
// out to id-observers
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
nsAttrValue attrValue;
|
||||
if (preparsedAttrValue) {
|
||||
attrValue.SwapValueWith(*preparsedAttrValue);
|
||||
}
|
||||
// Even the value was pre-parsed in BeforeSetAttr, we still need to call
|
||||
// ParseAttribute because it can have side effects.
|
||||
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!preparsedAttrValue &&
|
||||
!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
||||
attrValue.SetTo(aValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
PreIdMaybeChange(aNamespaceID, aName, &value);
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
attrValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr);
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -2503,7 +2511,7 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|||
nsIAtom* aPrefix, nsAttrValue& aParsedValue,
|
||||
bool aNotify)
|
||||
{
|
||||
// Keep this in sync with SetAttr above
|
||||
// Keep this in sync with SetAttr and SetSingleClassFromParser above
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aName);
|
||||
NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
|
||||
|
@ -2518,41 +2526,46 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|||
bool hasListeners;
|
||||
nsAttrValueOrString value(aParsedValue);
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet;
|
||||
|
||||
if (OnlyNotifySameValueSet(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
oldValue, &modType, &hasListeners, &oldValueSet)) {
|
||||
return OnAttrSetButNotChanged(aNamespaceID, aName, value, aNotify);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
&aParsedValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PreIdMaybeChange(aNamespaceID, aName, &value);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix,
|
||||
oldValueSet ? &oldValue : nullptr,
|
||||
aParsedValue, modType, hasListeners, aNotify,
|
||||
kCallAfterSetAttr);
|
||||
kCallAfterSetAttr, document, updateBatch);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
bool aNotify,
|
||||
bool aCallAfterSetAttr)
|
||||
bool aCallAfterSetAttr,
|
||||
nsIDocument* aComposedDocument,
|
||||
const mozAutoDocUpdate&)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
nsMutationGuard::DidMutate();
|
||||
|
||||
// Copy aParsedValue for later use since it will be lost when we call
|
||||
|
@ -2564,6 +2577,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
|
||||
bool hadValidDir = false;
|
||||
bool hadDirAuto = false;
|
||||
bool oldValueSet;
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::dir) {
|
||||
|
@ -2574,8 +2588,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
// XXXbz Perhaps we should push up the attribute mapping function
|
||||
// stuff to Element?
|
||||
if (!IsAttributeMapped(aName) ||
|
||||
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
|
||||
!SetAndSwapMappedAttribute(aComposedDocument, aName, aParsedValue, &oldValueSet, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue, &oldValueSet);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2584,24 +2598,34 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
aNamespaceID,
|
||||
nsIDOMNode::ATTRIBUTE_NODE);
|
||||
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue, &oldValueSet);
|
||||
}
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
const nsAttrValue* oldValue =
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
PostIdMaybeChange(aNamespaceID, aName, &valueForAfterSetAttr);
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
// oldValue will be null if there was no previously set value
|
||||
const nsAttrValue* oldValue;
|
||||
if (aParsedValue.StoresOwnData()) {
|
||||
if (oldValueSet) {
|
||||
oldValue = &aParsedValue;
|
||||
} else {
|
||||
oldValue = nullptr;
|
||||
}
|
||||
} else {
|
||||
// No need to conditionally assign null here. If there was no previously
|
||||
// set value for the attribute, aOldValue will already be null.
|
||||
oldValue = aOldValue;
|
||||
}
|
||||
|
||||
if (aComposedDocument || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
RefPtr<nsXBLBinding> binding = GetXBLBinding();
|
||||
if (binding) {
|
||||
binding->AttributeChanged(aName, aNamespaceID, false, aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
|
@ -2611,7 +2635,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
MOZ_ASSERT(data->mState == CustomElementData::State::eCustom,
|
||||
"AttributeChanged callback should fire only if "
|
||||
"custom element state is custom");
|
||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> oldValueAtom;
|
||||
if (oldValue) {
|
||||
oldValueAtom = oldValue->GetAsAtom();
|
||||
} else {
|
||||
// If there is no old value, get the value of the uninitialized attribute
|
||||
// that was swapped with aParsedValue.
|
||||
oldValueAtom = aParsedValue.GetAsAtom();
|
||||
}
|
||||
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
nsAutoString ns;
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
|
||||
|
@ -2631,7 +2662,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
}
|
||||
|
||||
if (aCallAfterSetAttr) {
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, oldValue,
|
||||
aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
|
@ -2640,12 +2672,14 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (aNotify) {
|
||||
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
|
||||
// Callers only compute aOldValue under certain conditions which may not
|
||||
// be triggered by all nsIMutationObservers.
|
||||
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
|
||||
oldValue == &aParsedValue ? &aParsedValue : nullptr);
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : nullptr);
|
||||
}
|
||||
|
||||
if (aFireMutation) {
|
||||
|
@ -2663,7 +2697,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
if (!newValue.IsEmpty()) {
|
||||
mutation.mNewAttrValue = NS_Atomize(newValue);
|
||||
}
|
||||
if (!oldValue->IsEmptyString()) {
|
||||
if (oldValue && !oldValue->IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = oldValue->GetAsAtom();
|
||||
}
|
||||
mutation.mAttrChange = aModType;
|
||||
|
@ -2675,25 +2709,6 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::_class) {
|
||||
// aValue->GetAttrValue will only be non-null here when this is called
|
||||
// via Element::SetParsedAttr. This shouldn't happen for "class", but
|
||||
// this will handle it.
|
||||
if (aValue && !aValue->GetAttrValue()) {
|
||||
nsAttrValue attr;
|
||||
attr.ParseAtomArray(aValue->String());
|
||||
aValue->TakeParsedValue(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Element::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
|
@ -2701,22 +2716,16 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
|||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::_class) {
|
||||
SetFlags(NODE_MAY_HAVE_CLASS);
|
||||
// Result should have been preparsed above.
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(aAttribute != nsGkAtoms::_class,
|
||||
"The class attribute should be preparsed and therefore should "
|
||||
"never be passed to Element::ParseAttribute");
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
// Store id as an atom. id="" means that the element has no id,
|
||||
// not that it has an emptystring as the id.
|
||||
RemoveFromIdTable();
|
||||
if (aValue.IsEmpty()) {
|
||||
ClearHasID();
|
||||
return false;
|
||||
}
|
||||
aResult.ParseAtom(aValue);
|
||||
SetHasID();
|
||||
AddToIdTable(aResult.GetAtomValue());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2725,15 +2734,71 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
|||
}
|
||||
|
||||
bool
|
||||
Element::SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval)
|
||||
Element::SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval)
|
||||
{
|
||||
*aRetval = NS_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::_class) {
|
||||
if (aValue) {
|
||||
// Note: This flag is asymmetrical. It is never unset and isn't exact.
|
||||
// If it is ever made to be exact, we probably need to handle this
|
||||
// similarly to how ids are handled in PreIdMaybeChange and
|
||||
// PostIdMaybeChange.
|
||||
// Note that SetSingleClassFromParser inlines BeforeSetAttr and
|
||||
// calls SetMayHaveClass directly. Making a subclass take action
|
||||
// on the class attribute in a BeforeSetAttr override would
|
||||
// require revising SetSingleClassFromParser.
|
||||
SetMayHaveClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Element::PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue)
|
||||
{
|
||||
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
|
||||
return;
|
||||
}
|
||||
RemoveFromIdTable();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Element::PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue)
|
||||
{
|
||||
if (aNamespaceID != kNameSpaceID_None || aName != nsGkAtoms::id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// id="" means that the element has no id, not that it has an empty
|
||||
// string as the id.
|
||||
if (aValue && !aValue->IsEmptyString()) {
|
||||
SetHasID();
|
||||
AddToIdTable(aValue->GetAtomValue());
|
||||
} else {
|
||||
ClearHasID();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
EventListenerManager*
|
||||
Element::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
|
||||
bool* aDefer)
|
||||
|
@ -2810,9 +2875,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIDocument *document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
|
||||
|
@ -2822,11 +2884,16 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
nullptr);
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasMutationListeners = aNotify &&
|
||||
nsContentUtils::HasMutationListeners(this,
|
||||
NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
|
||||
this);
|
||||
|
||||
PreIdMaybeChange(aNameSpaceID, aName, nullptr);
|
||||
|
||||
// Grab the attr node if needed before we remove it from the attr map
|
||||
RefPtr<Attr> attrNode;
|
||||
if (hasMutationListeners) {
|
||||
|
@ -2845,12 +2912,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
// react to unexpected attribute changes.
|
||||
nsMutationGuard::DidMutate();
|
||||
|
||||
if (aName == nsGkAtoms::id && aNameSpaceID == kNameSpaceID_None) {
|
||||
// Have to do this before clearing flag. See RemoveFromIdTable
|
||||
RemoveFromIdTable();
|
||||
ClearHasID();
|
||||
}
|
||||
|
||||
bool hadValidDir = false;
|
||||
bool hadDirAuto = false;
|
||||
|
||||
|
@ -2863,6 +2924,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PostIdMaybeChange(aNameSpaceID, aName, nullptr);
|
||||
|
||||
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
RefPtr<nsXBLBinding> binding = GetXBLBinding();
|
||||
if (binding) {
|
||||
|
@ -2870,8 +2933,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
}
|
||||
}
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled()) {
|
||||
if (CustomElementData* data = GetCustomElementData()) {
|
||||
if (CustomElementDefinition* definition =
|
||||
|
@ -2898,6 +2959,11 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
}
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, &oldValue, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
UpdateState(aNotify);
|
||||
|
||||
if (aNotify) {
|
||||
// We can always pass oldValue here since there is no new value which could
|
||||
// have corrupted it.
|
||||
|
@ -2905,9 +2971,6 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
nsIDOMMutationEvent::REMOVAL, &oldValue);
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
OnSetDirAttr(this, nullptr, hadValidDir, hadDirAuto, aNotify);
|
||||
}
|
||||
|
@ -3129,7 +3192,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
|
|||
}
|
||||
|
||||
nsresult
|
||||
Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
||||
Element::GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// Optimisation: return early if this event doesn't interest us.
|
||||
// IMPORTANT: this switch and the switch below it must be kept in sync!
|
||||
|
@ -3151,8 +3214,9 @@ Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// We do the status bar updates in PreHandleEvent so that the status bar gets
|
||||
// updated even if the event is consumed before we have a chance to set it.
|
||||
// We do the status bar updates in GetEventTargetParent so that the status bar
|
||||
// gets updated even if the event is consumed before we have a chance to set
|
||||
// it.
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
// Set the status bar similarly for mouseover and focus
|
||||
case eMouseOver:
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "Units.h"
|
||||
#include "DOMIntersectionObserver.h"
|
||||
|
||||
class mozAutoDocUpdate;
|
||||
class nsIFrame;
|
||||
class nsIDOMMozNamedAttrMap;
|
||||
class nsIURI;
|
||||
|
@ -143,7 +144,6 @@ class CustomElementRegistry;
|
|||
class Link;
|
||||
class DOMRect;
|
||||
class DOMRectList;
|
||||
class DestinationInsertionPointList;
|
||||
class Grid;
|
||||
|
||||
// IID for the dom::Element interface
|
||||
|
@ -254,6 +254,23 @@ public:
|
|||
*/
|
||||
void ClearStyleStateLocks();
|
||||
|
||||
/**
|
||||
* Accessors for the state of our dir attribute.
|
||||
*/
|
||||
bool HasDirAuto() const
|
||||
{
|
||||
return State().HasState(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Elements with dir="rtl" or dir="ltr".
|
||||
*/
|
||||
bool HasFixedDir() const
|
||||
{
|
||||
return State().HasAtLeastOneOfStates(NS_EVENT_STATE_DIR_ATTR_LTR |
|
||||
NS_EVENT_STATE_DIR_ATTR_RTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the inline style declaration, if any, for this element.
|
||||
*/
|
||||
|
@ -379,17 +396,10 @@ public:
|
|||
|
||||
bool GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult);
|
||||
|
||||
// The bdi element defaults to dir=auto if it has no dir attribute set.
|
||||
// Other elements will only have dir=auto if they have an explicit dir=auto,
|
||||
// which will mean that HasValidDir() returns true but HasFixedDir() returns
|
||||
// false
|
||||
inline bool HasDirAuto() const {
|
||||
return (!HasFixedDir() &&
|
||||
(HasValidDir() || IsHTMLElement(nsGkAtoms::bdi)));
|
||||
}
|
||||
|
||||
Directionality GetComputedDirectionality() const;
|
||||
|
||||
inline Element* GetFlattenedTreeParentElementForStyle() const;
|
||||
|
||||
/**
|
||||
* Gets the custom element data used by web components custom element.
|
||||
* Custom element data is created at the first attempt to enqueue a callback.
|
||||
|
@ -460,6 +470,9 @@ protected:
|
|||
mState &= ~aStates;
|
||||
}
|
||||
|
||||
already_AddRefed<ShadowRoot> AttachShadowInternal(bool aClosed,
|
||||
ErrorResult& aError);
|
||||
|
||||
private:
|
||||
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
|
||||
// set our state
|
||||
|
@ -498,6 +511,16 @@ protected:
|
|||
RemoveStatesSilently(aStates);
|
||||
NotifyStateChange(aStates);
|
||||
}
|
||||
virtual void ToggleStates(EventStates aStates, bool aNotify)
|
||||
{
|
||||
NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
|
||||
"Should only be removing externally-managed states here");
|
||||
mState ^= aStates;
|
||||
if (aNotify) {
|
||||
NotifyStateChange(aStates);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void UpdateEditableState(bool aNotify) override;
|
||||
|
||||
|
@ -520,6 +543,7 @@ public:
|
|||
already_AddRefed<mozilla::dom::NodeInfo>
|
||||
GetExistingAttrNameFromQName(const nsAString& aStr) const;
|
||||
|
||||
MOZ_ALWAYS_INLINE // Avoid a crashy hook from Avast 10 Beta (Bug 1058131)
|
||||
nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAString& aValue, bool aNotify)
|
||||
{
|
||||
|
@ -534,25 +558,57 @@ public:
|
|||
* values will not actually be compared if we aren't notifying and we don't
|
||||
* have mutation listeners (in which case it's cheap to just return false
|
||||
* and let the caller go ahead and set the value).
|
||||
* @param aOldValue Set to the old value of the attribute, but only if there
|
||||
* are event listeners. If set, the type of aOldValue will be either
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners Set to true if there are mutation event listeners
|
||||
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Notifies mutation listeners if aNotify is true, there are mutation
|
||||
* listeners, and the attribute value is changing.
|
||||
*
|
||||
* @param aNamespaceID The namespace of the attribute
|
||||
* @param aName The local name of the attribute
|
||||
* @param aPrefix The prefix of the attribute
|
||||
* @param aValue The value that the attribute is being changed to
|
||||
* @param aNotify If true, mutation listeners will be notified if they exist
|
||||
* and the attribute value is changing
|
||||
* @param aOldValue [out] Set to the old value of the attribute, but only if
|
||||
* there are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType [out] Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners [out] Set to true if there are mutation event
|
||||
* listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
* @param aOldValueSet [out] Indicates whether an old attribute value has been
|
||||
* stored in aOldValue. The bool will be set to true if a value was stored.
|
||||
*/
|
||||
|
||||
bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
uint8_t* aModType, bool* aHasListeners);
|
||||
uint8_t* aModType, bool* aHasListeners,
|
||||
bool* aOldValueSet);
|
||||
|
||||
/**
|
||||
* Sets the class attribute to a value that contains no whitespace.
|
||||
* Assumes that we are not notifying and that the attribute hasn't been
|
||||
* set previously.
|
||||
*/
|
||||
nsresult SetSingleClassFromParser(nsIAtom* aSingleClassName);
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify) override;
|
||||
|
@ -589,7 +645,7 @@ public:
|
|||
* guaranteed (e.g. we could have class="").
|
||||
*/
|
||||
const nsAttrValue* GetClasses() const {
|
||||
if (HasFlag(NODE_MAY_HAVE_CLASS)) {
|
||||
if (MayHaveClass()) {
|
||||
return DoGetClasses();
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -761,6 +817,25 @@ public:
|
|||
already_AddRefed<nsIHTMLCollection>
|
||||
GetElementsByClassName(const nsAString& aClassNames);
|
||||
|
||||
CSSPseudoElementType GetPseudoElementType() const {
|
||||
if (!HasProperties()) {
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
nsresult rv = NS_OK;
|
||||
auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
|
||||
if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
|
||||
}
|
||||
|
||||
void SetPseudoElementType(CSSPseudoElementType aPseudo) {
|
||||
static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
|
||||
"Need to be able to store this in a void*");
|
||||
MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
|
||||
SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Implement the algorithm specified at
|
||||
|
@ -848,8 +923,15 @@ public:
|
|||
already_AddRefed<DOMRectList> GetClientRects();
|
||||
already_AddRefed<DOMRect> GetBoundingClientRect();
|
||||
|
||||
// Shadow DOM v1
|
||||
already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
|
||||
ErrorResult& aError);
|
||||
ShadowRoot* GetShadowRootByMode() const;
|
||||
void SetSlot(const nsAString& aName, ErrorResult& aError);
|
||||
void GetSlot(nsAString& aName);
|
||||
|
||||
// [deprecated] Shadow DOM v0
|
||||
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
|
||||
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
|
||||
|
||||
ShadowRoot *FastGetShadowRoot() const
|
||||
{
|
||||
|
@ -1239,7 +1321,10 @@ protected:
|
|||
* its current value) is !StoresOwnData() --- in which
|
||||
* case the current value is probably already useless.
|
||||
* If the current value is StoresOwnData() (or absent),
|
||||
* aOldValue will not be used.
|
||||
* aOldValue will not be used. aOldValue will only be set
|
||||
* in certain circumstances (there are mutation
|
||||
* listeners, element is a custom element, attribute was
|
||||
* not previously unset). Otherwise it will be null.
|
||||
* @param aParsedValue parsed new value of attribute. Replaced by the
|
||||
* old value of the attribute. This old value is only
|
||||
* useful if either it or the new value is StoresOwnData.
|
||||
|
@ -1248,16 +1333,19 @@ protected:
|
|||
* @param aFireMutation should mutation-events be fired?
|
||||
* @param aNotify should we notify document-observers?
|
||||
* @param aCallAfterSetAttr should we call AfterSetAttr?
|
||||
* @param aComposedDocument The current composed document of the element.
|
||||
*/
|
||||
nsresult SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValue& aOldValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
uint8_t aModType,
|
||||
bool aFireMutation,
|
||||
bool aNotify,
|
||||
bool aCallAfterSetAttr);
|
||||
bool aCallAfterSetAttr,
|
||||
nsIDocument* aComposedDocument,
|
||||
const mozAutoDocUpdate& aGuard);
|
||||
|
||||
/**
|
||||
* Scroll to a new position using behavior evaluated from CSS and
|
||||
|
@ -1295,14 +1383,21 @@ protected:
|
|||
*
|
||||
* @param aDocument the current document of this node (an optimization)
|
||||
* @param aName the name of the attribute
|
||||
* @param aValue the nsAttrValue to set
|
||||
* @param aValue the nsAttrValue to set. Will be swapped with the existing
|
||||
* value of the attribute if the attribute already exists.
|
||||
* @param [out] aValueWasSet If the attribute was not set previously,
|
||||
* aValue will be swapped with an empty attribute
|
||||
* and aValueWasSet will be set to false. Otherwise,
|
||||
* aValueWasSet will be set to true and aValue will
|
||||
* contain the previous value set.
|
||||
* @param [out] aRetval the nsresult status of the operation, if any.
|
||||
* @return true if the setting was attempted, false otherwise.
|
||||
*/
|
||||
virtual bool SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval);
|
||||
virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
|
@ -1315,33 +1410,92 @@ protected:
|
|||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue. Alternatively, if the attr is being removed it
|
||||
* will be null. BeforeSetAttr is allowed to modify aValue by parsing
|
||||
* the string to an nsAttrValue (to avoid having to reparse it in
|
||||
* ParseAttribute).
|
||||
* will be null.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
* deal with attribute sets. This will only be called after we have called
|
||||
* SetAndTakeAttr and AttributeChanged (that is, after we have actually set
|
||||
* the attr). It will always be called under a scriptblocker.
|
||||
* SetAndSwapAttr (that is, after we have actually set the attr). It will
|
||||
* always be called under a scriptblocker.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to. If null, the attr is being
|
||||
* removed.
|
||||
* @param aOldValue the value that the attribute had previously. If null,
|
||||
* the attr was not previously set. This argument may not have the
|
||||
* correct value for SVG elements, or other cases in which the
|
||||
* attribute value doesn't store its own data
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify)
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue, bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function shall be called just before the id attribute changes. It will
|
||||
* be called after BeforeSetAttr. If the attribute being changed is not the id
|
||||
* attribute, this function does nothing. Otherwise, it will remove the old id
|
||||
* from the document's id cache.
|
||||
*
|
||||
* This must happen after BeforeSetAttr (rather than during) because the
|
||||
* the subclasses' calls to BeforeSetAttr may notify on state changes. If they
|
||||
* incorrectly determine whether the element had an id, the element may not be
|
||||
* restyled properly.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the new id value. Will be null if the id is being unset.
|
||||
*/
|
||||
void PreIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue);
|
||||
|
||||
/**
|
||||
* This function shall be called just after the id attribute changes. It will
|
||||
* be called before AfterSetAttr. If the attribute being changed is not the id
|
||||
* attribute, this function does nothing. Otherwise, it will add the new id to
|
||||
* the document's id cache and properly set the ElementHasID flag.
|
||||
*
|
||||
* This must happen before AfterSetAttr (rather than during) because the
|
||||
* the subclasses' calls to AfterSetAttr may notify on state changes. If they
|
||||
* incorrectly determine whether the element now has an id, the element may
|
||||
* not be restyled properly.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the new id value. Will be null if the id is being unset.
|
||||
*/
|
||||
void PostIdMaybeChange(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue);
|
||||
|
||||
/**
|
||||
* Usually, setting an attribute to the value that it already has results in
|
||||
* no action. However, in some cases, setting an attribute to its current
|
||||
* value should have the effect of, for example, forcing a reload of
|
||||
* network data. To address that, this function will be called in this
|
||||
* situation to allow the handling of such a case.
|
||||
*
|
||||
* @param aNamespaceID the namespace of the attr being set
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue.
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1400,7 +1554,7 @@ protected:
|
|||
/**
|
||||
* Handle status bar updates before they can be cancelled.
|
||||
*/
|
||||
nsresult PreHandleEventForLinks(EventChainPreVisitor& aVisitor);
|
||||
nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* Handle default actions for link event if the event isn't consumed yet.
|
||||
|
@ -1460,30 +1614,6 @@ private:
|
|||
nsCOMPtr<nsIDocument> mDoc;
|
||||
};
|
||||
|
||||
class DestinationInsertionPointList : public nsINodeList
|
||||
{
|
||||
public:
|
||||
explicit DestinationInsertionPointList(Element* aElement);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DestinationInsertionPointList)
|
||||
|
||||
// nsIDOMNodeList
|
||||
NS_DECL_NSIDOMNODELIST
|
||||
|
||||
// nsINodeList
|
||||
virtual nsIContent* Item(uint32_t aIndex) override;
|
||||
virtual int32_t IndexOf(nsIContent* aContent) override;
|
||||
virtual nsINode* GetParentObject() override { return mParent; }
|
||||
virtual uint32_t Length() const;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
protected:
|
||||
virtual ~DestinationInsertionPointList();
|
||||
|
||||
RefPtr<Element> mParent;
|
||||
nsCOMArray<nsIContent> mDestinationPoints;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -25,6 +25,17 @@ Element::UnregisterActivityObserver()
|
|||
OwnerDoc()->UnregisterActivityObserver(this);
|
||||
}
|
||||
|
||||
inline Element*
|
||||
Element::GetFlattenedTreeParentElementForStyle() const
|
||||
{
|
||||
nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
|
||||
if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
|
||||
return parentNode->AsElement();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
#include "mozilla/CORSMode.h"
|
||||
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
|
||||
#include "nsStyledElement.h"
|
||||
|
@ -151,8 +152,56 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-slotable-assignedslot
|
||||
HTMLSlotElement*
|
||||
nsIContent::GetAssignedSlotByMode() const
|
||||
{
|
||||
/**
|
||||
* Get slotable's assigned slot for the result of
|
||||
* find a slot with open flag UNSET [1].
|
||||
*
|
||||
* [1] https://dom.spec.whatwg.org/#assign-a-slot
|
||||
*/
|
||||
HTMLSlotElement* slot = GetAssignedSlot();
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(GetParent());
|
||||
MOZ_ASSERT(GetParent()->GetShadowRoot());
|
||||
|
||||
/**
|
||||
* Additional check for open flag SET:
|
||||
* If slotable’s parent’s shadow root's mode is not "open",
|
||||
* then return null.
|
||||
*/
|
||||
if (GetParent()->GetShadowRoot()->IsClosed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentNodeInternal() const
|
||||
nsIContent::GetFlattenedTreeParentForMaybeAssignedNode() const
|
||||
{
|
||||
if (HTMLSlotElement* assignedSlot = GetAssignedSlot()) {
|
||||
return assignedSlot;
|
||||
}
|
||||
|
||||
HTMLSlotElement* parentSlot = HTMLSlotElement::FromContent(GetParent());
|
||||
if (!parentSlot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If this is not an unassigned node, then it must be a fallback content.
|
||||
MOZ_ASSERT(parentSlot->AssignedNodes().IsEmpty());
|
||||
|
||||
return parentSlot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
|
||||
{
|
||||
nsINode* parentNode = GetParentNode();
|
||||
if (!parentNode || !parentNode->IsContent()) {
|
||||
|
@ -161,18 +210,51 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const
|
|||
}
|
||||
nsIContent* parent = parentNode->AsContent();
|
||||
|
||||
if (aType == eForStyle &&
|
||||
IsRootOfNativeAnonymousSubtree() &&
|
||||
OwnerDoc()->GetRootElement() == parent) {
|
||||
// When getting the flattened tree parent for style, we return null
|
||||
// for any "document level" native anonymous content subtree root.
|
||||
// This is NAC generated by an ancestor frame of the document element's
|
||||
// primary frame, and includes scrollbar elements created by the root
|
||||
// scroll frame, and the "custom content container" and accessible caret
|
||||
// generated by the nsCanvasFrame. We distinguish document level NAC
|
||||
// from NAC generated by the root element's primary frame below.
|
||||
nsIFrame* parentFrame = parent->GetPrimaryFrame();
|
||||
if (!parentFrame) {
|
||||
// If the root element has no primary frame, it means it can't have
|
||||
// generated any NAC itself. Thus any NAC we have here must have
|
||||
// been generated by an ancestor frame.
|
||||
//
|
||||
// If we are in here, then either the root element is display:none, or
|
||||
// we are in the middle of constructing the root of the frame tree and
|
||||
// we are trying to eagerly restyle document level NAC in
|
||||
// nsCSSFrameConstructor::GetAnonymousContent before the root
|
||||
// element's frame has been constructed.
|
||||
return nullptr;
|
||||
}
|
||||
nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
|
||||
if (!creator) {
|
||||
// If the root element does have a frame, but does not implement
|
||||
// nsIAnonymousContentCreator, then this must be document level NAC.
|
||||
return nullptr;
|
||||
}
|
||||
AutoTArray<nsIContent*, 8> elements;
|
||||
creator->AppendAnonymousContentTo(elements, 0);
|
||||
if (!elements.Contains(this)) {
|
||||
// If the root element does have a frame, and also does implement
|
||||
// nsIAnonymousContentCreator, but didn't create this node, then
|
||||
// it must be document level NAC.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
|
||||
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
|
||||
// This node is distributed to insertion points, thus we
|
||||
// need to consult the destination insertion points list to
|
||||
// figure out where this node was inserted in the flattened tree.
|
||||
// It may be the case that |parent| distributes its children
|
||||
// but the child does not match any insertion points, thus
|
||||
// the flattened tree parent is nullptr.
|
||||
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
|
||||
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
|
||||
destInsertionPoints->LastElement()->GetParent() : nullptr;
|
||||
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
return GetFlattenedTreeParentForMaybeAssignedNode();
|
||||
}
|
||||
|
||||
if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
|
||||
nsIContent* insertionParent = GetXBLInsertionParent();
|
||||
if (insertionParent) {
|
||||
parent = insertionParent;
|
||||
|
@ -575,6 +657,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
|
|||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mContainingShadow");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mContainingShadow));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mAssignedSlot");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mExtendedSlots->mAssignedSlot.get()));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExtendedSlots->mXBLBinding");
|
||||
cb.NoteNativeChild(mExtendedSlots->mXBLBinding,
|
||||
NS_CYCLE_COLLECTION_PARTICIPANT(nsXBLBinding));
|
||||
|
@ -618,6 +703,7 @@ FragmentOrElement::nsDOMSlots::Unlink()
|
|||
mExtendedSlots->mLabelsList = nullptr;
|
||||
mExtendedSlots->mShadowRoot = nullptr;
|
||||
mExtendedSlots->mContainingShadow = nullptr;
|
||||
mExtendedSlots->mAssignedSlot = nullptr;
|
||||
MOZ_ASSERT(!(mExtendedSlots->mXBLBinding));
|
||||
mExtendedSlots->mXBLInsertionParent = nullptr;
|
||||
if (mExtendedSlots->mCustomElementData) {
|
||||
|
@ -718,7 +804,7 @@ FindChromeAccessOnlySubtreeOwner(nsIContent* aContent)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
//FIXME! Document how this event retargeting works, Bug 329124.
|
||||
aVisitor.mCanHandle = true;
|
||||
|
@ -727,6 +813,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
// Don't propagate mouseover and mouseout events when mouse is moving
|
||||
// inside chrome access only content.
|
||||
bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
|
||||
aVisitor.mRootOfClosedTree = isAnonForEvents;
|
||||
if ((aVisitor.mEvent->mMessage == eMouseOver ||
|
||||
aVisitor.mEvent->mMessage == eMouseOut ||
|
||||
aVisitor.mEvent->mMessage == ePointerOver ||
|
||||
|
@ -738,7 +825,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
((this == aVisitor.mEvent->mOriginalTarget &&
|
||||
!ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
|
||||
nsCOMPtr<nsIContent> relatedTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->relatedTarget);
|
||||
do_QueryInterface(aVisitor.mEvent->AsMouseEvent()->mRelatedTarget);
|
||||
if (relatedTarget &&
|
||||
relatedTarget->OwnerDoc() == OwnerDoc()) {
|
||||
|
||||
|
@ -748,7 +835,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
nsIContent* adjustedTarget =
|
||||
Event::GetShadowRelatedTarget(this, relatedTarget);
|
||||
if (this == adjustedTarget) {
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
aVisitor.mCanHandle = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -805,7 +892,7 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
originalTarget->FindFirstNonChromeOnlyAccessContent())
|
||||
? "" : "Wrong event propagation!?!\n");
|
||||
#endif
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
// Event should not propagate to non-anon content.
|
||||
aVisitor.mCanHandle = isAnonForEvents;
|
||||
return NS_OK;
|
||||
|
@ -816,58 +903,10 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
}
|
||||
}
|
||||
|
||||
nsIContent* parent = GetParent();
|
||||
|
||||
// Web components have a special event chain that need to account
|
||||
// for destination insertion points where nodes have been distributed.
|
||||
nsTArray<nsIContent*>* destPoints = GetExistingDestInsertionPoints();
|
||||
if (destPoints && !destPoints->IsEmpty()) {
|
||||
// Push destination insertion points to aVisitor.mDestInsertionPoints
|
||||
// excluding shadow insertion points.
|
||||
bool didPushNonShadowInsertionPoint = false;
|
||||
for (uint32_t i = 0; i < destPoints->Length(); i++) {
|
||||
nsIContent* point = destPoints->ElementAt(i);
|
||||
if (!ShadowRoot::IsShadowInsertionPoint(point)) {
|
||||
aVisitor.mDestInsertionPoints.AppendElement(point);
|
||||
didPushNonShadowInsertionPoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Next node in the event path is the final destination
|
||||
// (non-shadow) insertion point that was pushed.
|
||||
if (didPushNonShadowInsertionPoint) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
|
||||
if (thisShadowRoot) {
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
// If we do stop propagation, we still want to propagate
|
||||
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
|
||||
// The load event is special in that we don't ever propagate it
|
||||
// to chrome.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
aVisitor.mParentTarget = parentTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aVisitor.mDestInsertionPoints.IsEmpty()) {
|
||||
parent = aVisitor.mDestInsertionPoints.LastElement();
|
||||
aVisitor.mDestInsertionPoints.SetLength(
|
||||
aVisitor.mDestInsertionPoints.Length() - 1);
|
||||
} else {
|
||||
// The pool host for the youngest shadow root is shadow DOM host,
|
||||
// for older shadow roots, it is the shadow insertion point
|
||||
// where the shadow root is projected, nullptr if none exists.
|
||||
parent = thisShadowRoot->GetPoolHost();
|
||||
}
|
||||
}
|
||||
// Event parent is the assigned slot, if node is assigned, or node's parent
|
||||
// otherwise.
|
||||
HTMLSlotElement* slot = GetAssignedSlot();
|
||||
nsIContent* parent = slot ? slot : GetParent();
|
||||
|
||||
// Event may need to be retargeted if this is the root of a native
|
||||
// anonymous content subtree or event is dispatched somewhere inside XBL.
|
||||
|
@ -905,11 +944,17 @@ nsIContent::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
if (!aVisitor.mEvent->mFlags.mComposedInNativeAnonymousContent &&
|
||||
IsRootOfNativeAnonymousSubtree() && OwnerDoc() &&
|
||||
OwnerDoc()->GetWindow()) {
|
||||
aVisitor.mParentTarget = OwnerDoc()->GetWindow()->GetParentTarget();
|
||||
aVisitor.SetParentTarget(OwnerDoc()->GetWindow()->GetParentTarget(), true);
|
||||
} else if (parent) {
|
||||
aVisitor.mParentTarget = parent;
|
||||
aVisitor.SetParentTarget(parent, false);
|
||||
if (slot) {
|
||||
ShadowRoot* root = slot->GetContainingShadow();
|
||||
if (root && root->IsClosed()) {
|
||||
aVisitor.mParentIsSlotInClosedTree = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aVisitor.mParentTarget = GetComposedDoc();
|
||||
aVisitor.SetParentTarget(GetComposedDoc(), false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1086,21 +1131,18 @@ FragmentOrElement::SetShadowRoot(ShadowRoot* aShadowRoot)
|
|||
slots->mShadowRoot = aShadowRoot;
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>&
|
||||
FragmentOrElement::DestInsertionPoints()
|
||||
{
|
||||
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||
return slots->mDestInsertionPoints;
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>*
|
||||
FragmentOrElement::GetExistingDestInsertionPoints() const
|
||||
HTMLSlotElement*
|
||||
FragmentOrElement::GetAssignedSlot() const
|
||||
{
|
||||
nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
|
||||
if (slots) {
|
||||
return &slots->mDestInsertionPoints;
|
||||
}
|
||||
return nullptr;
|
||||
return slots ? slots->mAssignedSlot.get() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FragmentOrElement::SetAssignedSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
nsExtendedDOMSlots* slots = ExtendedDOMSlots();
|
||||
slots->mAssignedSlot = aSlot;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2368,9 +2410,8 @@ FragmentOrElement::SetIsElementInStyleScopeFlagOnShadowTree(bool aInStyleScope)
|
|||
NS_ASSERTION(IsElement(), "calling SetIsElementInStyleScopeFlagOnShadowTree "
|
||||
"on a non-Element is useless");
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
while (shadowRoot) {
|
||||
if (shadowRoot) {
|
||||
shadowRoot->SetIsElementInStyleScopeFlagOnSubtree(aInStyleScope);
|
||||
shadowRoot = shadowRoot->GetOlderShadowRoot();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
// nsIWeakReference
|
||||
NS_DECL_NSIWEAKREFERENCE
|
||||
virtual size_t SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
virtual bool IsAlive() const override { return mNode != nullptr; }
|
||||
|
||||
void NoticeNodeDestruction()
|
||||
{
|
||||
|
@ -154,9 +155,9 @@ public:
|
|||
virtual void SetXBLBinding(nsXBLBinding* aBinding,
|
||||
nsBindingManager* aOldBindingManager = nullptr) override;
|
||||
virtual ShadowRoot *GetContainingShadow() const override;
|
||||
virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
|
||||
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
|
||||
virtual void SetShadowRoot(ShadowRoot* aBinding) override;
|
||||
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
|
||||
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
|
||||
virtual nsIContent *GetXBLInsertionParent() const override;
|
||||
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
|
||||
virtual bool IsLink(nsIURI** aURI) const override;
|
||||
|
@ -294,10 +295,9 @@ public:
|
|||
RefPtr<ShadowRoot> mContainingShadow;
|
||||
|
||||
/**
|
||||
* An array of web component insertion points to which this element
|
||||
* is distributed.
|
||||
* The assigned slot associated with this element.
|
||||
*/
|
||||
nsTArray<nsIContent*> mDestInsertionPoints;
|
||||
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
|
||||
|
||||
/**
|
||||
* XBL binding installed on the element.
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
||||
|
@ -27,10 +27,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPoolHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOlderShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mYoungerShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
|
||||
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
|
@ -38,18 +35,14 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
|
|||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
if (tmp->mPoolHost) {
|
||||
tmp->mPoolHost->RemoveMutationObserver(tmp);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
|
||||
if (tmp->GetHost()) {
|
||||
tmp->GetHost()->RemoveMutationObserver(tmp);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPoolHost)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOlderShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mYoungerShadow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
|
||||
tmp->mIdentifierMap.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRoot)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
|
||||
|
@ -59,14 +52,16 @@ NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
|
|||
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
|
||||
|
||||
ShadowRoot::ShadowRoot(nsIContent* aContent,
|
||||
ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding)
|
||||
: DocumentFragment(aNodeInfo), mPoolHost(aContent),
|
||||
mProtoBinding(aProtoBinding), mShadowElement(nullptr),
|
||||
mInsertionPointChanged(false), mIsComposedDocParticipant(false)
|
||||
: DocumentFragment(aNodeInfo)
|
||||
, mProtoBinding(aProtoBinding)
|
||||
, mInsertionPointChanged(false)
|
||||
, mIsComposedDocParticipant(false)
|
||||
{
|
||||
SetHost(aContent);
|
||||
SetHost(aElement);
|
||||
mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
|
||||
|
||||
// Nodes in a shadow tree should never store a value
|
||||
// in the subtree root pointer, nodes in the shadow tree
|
||||
|
@ -75,29 +70,27 @@ ShadowRoot::ShadowRoot(nsIContent* aContent,
|
|||
|
||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
ExtendedDOMSlots()->mBindingParent = aContent;
|
||||
ExtendedDOMSlots()->mBindingParent = aElement;
|
||||
ExtendedDOMSlots()->mContainingShadow = this;
|
||||
|
||||
// Add the ShadowRoot as a mutation observer on the host to watch
|
||||
// for mutations because the insertion points in this ShadowRoot
|
||||
// may need to be updated when the host children are modified.
|
||||
mPoolHost->AddMutationObserver(this);
|
||||
GetHost()->AddMutationObserver(this);
|
||||
}
|
||||
|
||||
ShadowRoot::~ShadowRoot()
|
||||
{
|
||||
if (mPoolHost) {
|
||||
// mPoolHost may have been unlinked or a new ShadowRoot may have been
|
||||
// creating, making this one obsolete.
|
||||
mPoolHost->RemoveMutationObserver(this);
|
||||
if (auto* host = GetHost()) {
|
||||
// mHost may have been unlinked or a new ShadowRoot may have been
|
||||
// created, making this one obsolete.
|
||||
host->RemoveMutationObserver(this);
|
||||
}
|
||||
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// nsINode destructor expects mSubtreeRoot == this.
|
||||
SetSubtreeRootPointer(this);
|
||||
|
||||
SetHost(nullptr);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
@ -118,13 +111,116 @@ ShadowRoot::FromNode(nsINode* aNode)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
// Note that if name attribute missing, the slot is a default slot.
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.LookupOrAdd(name);
|
||||
MOZ_ASSERT(currentSlots);
|
||||
|
||||
HTMLSlotElement* oldSlot = currentSlots->IsEmpty() ?
|
||||
nullptr : currentSlots->ElementAt(0);
|
||||
|
||||
TreeOrderComparator comparator;
|
||||
currentSlots->InsertElementSorted(aSlot, comparator);
|
||||
|
||||
HTMLSlotElement* currentSlot = currentSlots->ElementAt(0);
|
||||
if (currentSlot != aSlot) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool doEnqueueSlotChange = false;
|
||||
if (oldSlot && oldSlot != currentSlot) {
|
||||
// Move assigned nodes from old slot to new slot.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
oldSlot->RemoveAssignedNode(assignedNode);
|
||||
currentSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
// Otherwise add appropriate nodes to this slot from the host.
|
||||
for (nsIContent* child = GetHost()->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsAutoString slotName;
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (child->IsSlotable() && slotName.Equals(name)) {
|
||||
currentSlot->AppendAssignedNode(child);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
MOZ_ASSERT(aSlot);
|
||||
|
||||
nsAutoString name;
|
||||
aSlot->GetName(name);
|
||||
|
||||
nsTArray<HTMLSlotElement*>* currentSlots = mSlotMap.Get(name);
|
||||
|
||||
if (currentSlots) {
|
||||
if (currentSlots->Length() == 1) {
|
||||
MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
|
||||
mSlotMap.Remove(name);
|
||||
|
||||
if (aSlot->AssignedNodes().Length() > 0) {
|
||||
aSlot->ClearAssignedNodes();
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
bool doEnqueueSlotChange = false;
|
||||
bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
|
||||
currentSlots->RemoveElement(aSlot);
|
||||
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
||||
|
||||
// Move assigned nodes from removed slot to the next slot in
|
||||
// tree order with the same name.
|
||||
if (doReplaceSlot) {
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = aSlot->AssignedNodes();
|
||||
while (assignedNodes.Length() > 0) {
|
||||
nsINode* assignedNode = assignedNodes[0];
|
||||
|
||||
aSlot->RemoveAssignedNode(assignedNode);
|
||||
replacementSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
replacementSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::StyleSheetChanged()
|
||||
{
|
||||
mProtoBinding->FlushSkinSheets();
|
||||
|
||||
nsIPresShell* shell = OwnerDoc()->GetShell();
|
||||
if (shell) {
|
||||
if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
|
||||
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
|
||||
shell->RecordShadowStyleChange(this);
|
||||
OwnerDoc()->EndUpdate(UPDATE_STYLE);
|
||||
|
@ -142,16 +238,30 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
|
|||
|
||||
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == StyleScope::SheetCount());
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
// FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
|
||||
// binding will disappear soon (tm).
|
||||
{
|
||||
size_t i = 0;
|
||||
for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Find the correct position to insert into the style sheet list (must
|
||||
// be in tree order).
|
||||
for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
|
||||
if (i == mProtoBinding->SheetCount()) {
|
||||
for (size_t i = 0; i <= SheetCount(); i++) {
|
||||
if (i == SheetCount()) {
|
||||
AppendStyleSheet(*aSheet);
|
||||
mProtoBinding->AppendStyleSheet(aSheet);
|
||||
break;
|
||||
}
|
||||
|
||||
nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
|
||||
nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
|
||||
if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
|
||||
InsertSheetAt(i, *aSheet);
|
||||
mProtoBinding->InsertStyleSheetAt(i, aSheet);
|
||||
break;
|
||||
}
|
||||
|
@ -166,6 +276,7 @@ void
|
|||
ShadowRoot::RemoveSheet(StyleSheet* aSheet)
|
||||
{
|
||||
mProtoBinding->RemoveStyleSheet(aSheet);
|
||||
StyleScope::RemoveSheet(*aSheet);
|
||||
|
||||
if (aSheet->IsApplicable()) {
|
||||
StyleSheetChanged();
|
||||
|
@ -232,238 +343,158 @@ ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
|
|||
return nsContentUtils::GetElementsByClassName(this, aClasses);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AddInsertionPoint(HTMLContentElement* aInsertionPoint)
|
||||
nsresult
|
||||
ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
TreeOrderComparator comparator;
|
||||
mInsertionPoints.InsertElementSorted(aInsertionPoint, comparator);
|
||||
}
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mRootOfClosedTree = IsClosed();
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveInsertionPoint(HTMLContentElement* aInsertionPoint)
|
||||
{
|
||||
mInsertionPoints.RemoveElement(aInsertionPoint);
|
||||
}
|
||||
// https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
|
||||
if (!aVisitor.mEvent->mFlags.mComposed) {
|
||||
nsCOMPtr<nsIContent> originalTarget =
|
||||
do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
|
||||
if (originalTarget->GetContainingShadow() == this) {
|
||||
// If we do stop propagation, we still want to propagate
|
||||
// the event to chrome (nsPIDOMWindow::GetParentTarget()).
|
||||
// The load event is special in that we don't ever propagate it
|
||||
// to chrome.
|
||||
nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
|
||||
EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
|
||||
? win->GetParentTarget() : nullptr;
|
||||
|
||||
void
|
||||
ShadowRoot::SetYoungerShadow(ShadowRoot* aYoungerShadow)
|
||||
{
|
||||
mYoungerShadow = aYoungerShadow;
|
||||
mYoungerShadow->mOlderShadow = this;
|
||||
|
||||
ChangePoolHost(mYoungerShadow->GetShadowElement());
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
|
||||
nsTArray<nsIContent*>& aDestInsertionPoints)
|
||||
{
|
||||
// Remove the insertion point from the destination insertion points.
|
||||
// Also remove all succeeding insertion points because it is no longer
|
||||
// possible for the content to be distributed into deeper node trees.
|
||||
int32_t index = aDestInsertionPoints.IndexOf(aInsertionPoint);
|
||||
|
||||
// It's possible that we already removed the insertion point while processing
|
||||
// other insertion point removals.
|
||||
if (index >= 0) {
|
||||
aDestInsertionPoints.SetLength(index);
|
||||
aVisitor.SetParentTarget(parentTarget, true);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* shadowHost = GetHost();
|
||||
aVisitor.SetParentTarget(shadowHost, false);
|
||||
|
||||
if (aVisitor.mOriginalTargetIsInAnon) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->mTarget));
|
||||
if (content && content->GetBindingParent() == shadowHost) {
|
||||
aVisitor.mEventTargetAtParent = shadowHost;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributeSingleNode(nsIContent* aContent)
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::AssignSlotFor(nsIContent* aContent)
|
||||
{
|
||||
// Find the insertion point to which the content belongs.
|
||||
HTMLContentElement* insertionPoint = nullptr;
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
if (mInsertionPoints[i]->Match(aContent)) {
|
||||
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
|
||||
// Node is already matched into the insertion point. We are done.
|
||||
return;
|
||||
nsAutoString slotName;
|
||||
// Note that if slot attribute is missing, assign it to the first default
|
||||
// slot, if exists.
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(slotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
// Find the appropriate position in the assigned node list for the
|
||||
// newly assigned content.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = slot->AssignedNodes();
|
||||
nsIContent* currentContent = GetHost()->GetFirstChild();
|
||||
bool indexFound = false;
|
||||
uint32_t insertionIndex;
|
||||
for (uint32_t i = 0; i < assignedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the
|
||||
// assigned content is found.
|
||||
while (currentContent && currentContent != assignedNodes[i]) {
|
||||
if (currentContent == aContent) {
|
||||
indexFound = true;
|
||||
insertionIndex = i;
|
||||
}
|
||||
|
||||
// Matching may cause the insertion point to drop fallback content.
|
||||
if (mInsertionPoints[i]->MatchedNodes().IsEmpty() &&
|
||||
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
|
||||
// This match will cause the insertion point to drop all fallback
|
||||
// content and used matched nodes instead. Give up on the optimization
|
||||
// and just distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
return;
|
||||
}
|
||||
insertionPoint = mInsertionPoints[i];
|
||||
currentContent = currentContent->GetNextSibling();
|
||||
}
|
||||
|
||||
if (indexFound) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the index into the insertion point.
|
||||
if (insertionPoint) {
|
||||
nsCOMArray<nsIContent>& matchedNodes = insertionPoint->MatchedNodes();
|
||||
// Find the appropriate position in the matched node list for the
|
||||
// newly distributed content.
|
||||
bool isIndexFound = false;
|
||||
MOZ_ASSERT(mPoolHost, "Where did the content come from if there is no pool host?");
|
||||
ExplicitChildIterator childIterator(mPoolHost);
|
||||
for (uint32_t i = 0; i < matchedNodes.Length(); i++) {
|
||||
// Seek through the host's explicit children until the inserted content
|
||||
// is found or when the current matched node is reached.
|
||||
if (childIterator.Seek(aContent, matchedNodes[i])) {
|
||||
// aContent was found before the current matched node.
|
||||
insertionPoint->InsertMatchedNode(i, aContent);
|
||||
isIndexFound = true;
|
||||
break;
|
||||
if (indexFound) {
|
||||
slot->InsertAssignedNode(insertionIndex, aContent);
|
||||
} else {
|
||||
slot->AppendAssignedNode(aContent);
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
const HTMLSlotElement*
|
||||
ShadowRoot::UnassignSlotFor(nsIContent* aNode, const nsAString& aSlotName)
|
||||
{
|
||||
// Find the insertion point to which the content belongs. Note that if slot
|
||||
// attribute is missing, unassign it from the first default slot, if exists.
|
||||
nsTArray<HTMLSlotElement*>* slots = mSlotMap.Get(aSlotName);
|
||||
if (!slots) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HTMLSlotElement* slot = slots->ElementAt(0);
|
||||
MOZ_ASSERT(slot);
|
||||
|
||||
if (!slot->AssignedNodes().Contains(aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slot->RemoveAssignedNode(aNode);
|
||||
return slot;
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::MaybeReassignElement(Element* aElement,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
nsIContent* parent = aElement->GetParent();
|
||||
if (parent && parent == GetHost()) {
|
||||
const HTMLSlotElement* oldSlot = UnassignSlotFor(aElement,
|
||||
aOldValue ? aOldValue->GetStringValue() : EmptyString());
|
||||
const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
|
||||
|
||||
if (oldSlot != newSlot) {
|
||||
if (oldSlot) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isIndexFound) {
|
||||
// We have still not found an index in the insertion point,
|
||||
// thus it must be at the end.
|
||||
MOZ_ASSERT(childIterator.Seek(aContent, nullptr),
|
||||
"Trying to match a node that is not a candidate to be matched");
|
||||
insertionPoint->AppendMatchedNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is a ShadowRoot
|
||||
// that is projected into the younger ShadowRoot's shadow insertion point.
|
||||
// The node distributed into the insertion point must be reprojected
|
||||
// to the shadow insertion point.
|
||||
if (insertionPoint->GetParent() == this &&
|
||||
mYoungerShadow && mYoungerShadow->GetShadowElement()) {
|
||||
mYoungerShadow->GetShadowElement()->DistributeSingleNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The node distributed into the insertion point must be reprojected to the
|
||||
// insertion points of the parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = insertionPoint->GetParent()->GetShadowRoot();
|
||||
if (parentShadow) {
|
||||
parentShadow->DistributeSingleNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is the <shadow>
|
||||
// element. The node distributed into the insertion point must be reprojected
|
||||
// into the older ShadowRoot's insertion points.
|
||||
if (mShadowElement && mShadowElement == insertionPoint->GetParent()) {
|
||||
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
|
||||
if (olderShadow) {
|
||||
olderShadow->DistributeSingleNode(aContent);
|
||||
if (newSlot) {
|
||||
newSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::RemoveDistributedNode(nsIContent* aContent)
|
||||
ShadowRoot::DistributionChanged()
|
||||
{
|
||||
// Find insertion point containing the content and remove the node.
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
if (mInsertionPoints[i]->MatchedNodes().Contains(aContent)) {
|
||||
// Removing the matched node may cause the insertion point to use
|
||||
// fallback content.
|
||||
if (mInsertionPoints[i]->MatchedNodes().Length() == 1 &&
|
||||
static_cast<nsINode*>(mInsertionPoints[i])->GetFirstChild()) {
|
||||
// Removing the matched node will cause fallback content to be
|
||||
// used instead. Give up optimization and distribute all nodes.
|
||||
DistributeAllNodes();
|
||||
return;
|
||||
}
|
||||
|
||||
mInsertionPoints[i]->RemoveMatchedNode(aContent);
|
||||
|
||||
// Handle the case where the parent of the insertion point is a ShadowRoot
|
||||
// that is projected into the younger ShadowRoot's shadow insertion point.
|
||||
// The removed node needs to be removed from the shadow insertion point.
|
||||
if (mInsertionPoints[i]->GetParent() == this) {
|
||||
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
|
||||
mYoungerShadow->GetShadowElement()->RemoveDistributedNode(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point has a ShadowRoot.
|
||||
// The removed node needs to be removed from the insertion points of the
|
||||
// parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = mInsertionPoints[i]->GetParent()->GetShadowRoot();
|
||||
if (parentShadow) {
|
||||
parentShadow->RemoveDistributedNode(aContent);
|
||||
}
|
||||
|
||||
// Handle the case where the parent of the insertion point is the <shadow>
|
||||
// element. The removed node must be removed from the older ShadowRoot's
|
||||
// insertion points.
|
||||
if (mShadowElement && mShadowElement == mInsertionPoints[i]->GetParent()) {
|
||||
ShadowRoot* olderShadow = mShadowElement->GetOlderShadowRoot();
|
||||
if (olderShadow) {
|
||||
olderShadow->RemoveDistributedNode(aContent);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// FIXME(emilio): We could be more granular in a bunch of cases.
|
||||
auto* host = GetHost();
|
||||
if (!host || !host->IsInComposedDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* shell = OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
shell->DestroyFramesForAndRestyle(host);
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DistributeAllNodes()
|
||||
{
|
||||
// Create node pool.
|
||||
nsTArray<nsIContent*> nodePool;
|
||||
//XXX Handle <slot>.
|
||||
|
||||
// Make sure there is a pool host, an older shadow may not have
|
||||
// one if the younger shadow does not have a <shadow> element.
|
||||
if (mPoolHost) {
|
||||
ExplicitChildIterator childIterator(mPoolHost);
|
||||
for (nsIContent* content = childIterator.GetNextChild();
|
||||
content;
|
||||
content = childIterator.GetNextChild()) {
|
||||
nodePool.AppendElement(content);
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<ShadowRoot*> shadowsToUpdate;
|
||||
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
mInsertionPoints[i]->ClearMatchedNodes();
|
||||
// Assign matching nodes from node pool.
|
||||
for (uint32_t j = 0; j < nodePool.Length(); j++) {
|
||||
if (mInsertionPoints[i]->Match(nodePool[j])) {
|
||||
mInsertionPoints[i]->AppendMatchedNode(nodePool[j]);
|
||||
nodePool.RemoveElementAt(j--);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of instances where the content insertion point is distributed
|
||||
// (parent of insertion point has a ShadowRoot).
|
||||
nsIContent* insertionParent = mInsertionPoints[i]->GetParent();
|
||||
MOZ_ASSERT(insertionParent, "The only way for an insertion point to be in the"
|
||||
"mInsertionPoints array is to be a descendant of a"
|
||||
"ShadowRoot, in which case, it should have a parent");
|
||||
|
||||
// If the parent of the insertion point has a ShadowRoot, the nodes distributed
|
||||
// to the insertion point must be reprojected to the insertion points of the
|
||||
// parent's ShadowRoot.
|
||||
ShadowRoot* parentShadow = insertionParent->GetShadowRoot();
|
||||
if (parentShadow && !shadowsToUpdate.Contains(parentShadow)) {
|
||||
shadowsToUpdate.AppendElement(parentShadow);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a shadow insertion point in this ShadowRoot, the children
|
||||
// of the shadow insertion point needs to be distributed into the insertion
|
||||
// points of the older ShadowRoot.
|
||||
if (mShadowElement && mOlderShadow) {
|
||||
mOlderShadow->DistributeAllNodes();
|
||||
}
|
||||
|
||||
// If there is a younger ShadowRoot with a shadow insertion point,
|
||||
// then the children of this ShadowRoot needs to be distributed to
|
||||
// the younger ShadowRoot's shadow insertion point.
|
||||
if (mYoungerShadow && mYoungerShadow->GetShadowElement()) {
|
||||
mYoungerShadow->GetShadowElement()->DistributeAllNodes();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < shadowsToUpdate.Length(); i++) {
|
||||
shadowsToUpdate[i]->DistributeAllNodes();
|
||||
}
|
||||
DistributionChanged();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -507,105 +538,6 @@ ShadowRoot::SetApplyAuthorStyles(bool aApplyAuthorStyles)
|
|||
}
|
||||
}
|
||||
|
||||
StyleSheetList*
|
||||
ShadowRoot::StyleSheets()
|
||||
{
|
||||
if (!mStyleSheetList) {
|
||||
mStyleSheetList = new ShadowRootStyleSheetList(this);
|
||||
}
|
||||
|
||||
return mStyleSheetList;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::SetShadowElement(HTMLShadowElement* aShadowElement)
|
||||
{
|
||||
// If there is already a shadow element point, remove
|
||||
// the projected shadow because it is no longer an insertion
|
||||
// point.
|
||||
if (mShadowElement) {
|
||||
mShadowElement->SetProjectedShadow(nullptr);
|
||||
}
|
||||
|
||||
if (mOlderShadow) {
|
||||
// Nodes for distribution will come from the new shadow element.
|
||||
mOlderShadow->ChangePoolHost(aShadowElement);
|
||||
}
|
||||
|
||||
// Set the new shadow element to project the older ShadowRoot because
|
||||
// it is the current shadow insertion point.
|
||||
mShadowElement = aShadowElement;
|
||||
if (mShadowElement) {
|
||||
mShadowElement->SetProjectedShadow(mOlderShadow);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::ChangePoolHost(nsIContent* aNewHost)
|
||||
{
|
||||
if (mPoolHost) {
|
||||
mPoolHost->RemoveMutationObserver(this);
|
||||
}
|
||||
|
||||
// Clear the nodes matched to content insertion points
|
||||
// because it is no longer relevant.
|
||||
for (uint32_t i = 0; i < mInsertionPoints.Length(); i++) {
|
||||
mInsertionPoints[i]->ClearMatchedNodes();
|
||||
}
|
||||
|
||||
mPoolHost = aNewHost;
|
||||
if (mPoolHost) {
|
||||
mPoolHost->AddMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ShadowRoot::IsShadowInsertionPoint(nsIContent* aContent)
|
||||
{
|
||||
if (!aContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HTMLShadowElement* shadowElem = HTMLShadowElement::FromContent(aContent);
|
||||
return shadowElem && shadowElem->IsInsertionPoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the web components pool population algorithm
|
||||
* on the host would contain |aContent|. This function ignores
|
||||
* insertion points in the pool, thus should only be used to
|
||||
* test nodes that have not yet been distributed.
|
||||
*/
|
||||
bool
|
||||
ShadowRoot::IsPooledNode(nsIContent* aContent, nsIContent* aContainer,
|
||||
nsIContent* aHost)
|
||||
{
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContent) ||
|
||||
IsShadowInsertionPoint(aContent)) {
|
||||
// Insertion points never end up in the pool.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aContainer == aHost &&
|
||||
nsContentUtils::IsInSameAnonymousTree(aContainer, aContent)) {
|
||||
// Children of the host will end up in the pool. We check to ensure
|
||||
// that the content is in the same anonymous tree as the container
|
||||
// because anonymous content may report its container as the host
|
||||
// but it may not be in the host's child list.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aContainer) {
|
||||
// Fallback content will end up in pool if its parent is a child of the host.
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
return content && content->IsInsertionPoint() &&
|
||||
content->MatchedNodes().IsEmpty() &&
|
||||
aContainer->GetParentNode() == aHost;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
||||
Element* aElement,
|
||||
|
@ -614,13 +546,26 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
|||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
|
||||
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::slot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attributes may change insertion point matching, find its new distribution.
|
||||
RemoveDistributedNode(aElement);
|
||||
DistributeSingleNode(aElement);
|
||||
if (!MaybeReassignElement(aElement, aOldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aElement->IsInComposedDoc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* shell = OwnerDoc()->GetShell();
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
|
||||
//XXX optimize this!
|
||||
shell->DestroyFramesForAndRestyle(aElement);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -629,29 +574,10 @@ ShadowRoot::ContentAppended(nsIDocument* aDocument,
|
|||
nsIContent* aFirstNewContent,
|
||||
int32_t aNewIndexInContainer)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for new nodes added to the pool because the node
|
||||
// may need to be added to an insertion point.
|
||||
nsIContent* currentChild = aFirstNewContent;
|
||||
while (currentChild) {
|
||||
// Add insertion point to destination insertion points of fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
currentChild->DestInsertionPoints().AppendElement(aContainer);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPooledNode(currentChild, aContainer, mPoolHost)) {
|
||||
DistributeSingleNode(currentChild);
|
||||
}
|
||||
|
||||
currentChild = currentChild->GetNextSibling();
|
||||
for (nsIContent* content = aFirstNewContent;
|
||||
content;
|
||||
content = content->GetNextSibling()) {
|
||||
ContentInserted(aDocument, aContainer, aFirstNewContent, aNewIndexInContainer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,24 +587,30 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
|
|||
nsIContent* aChild,
|
||||
int32_t aIndexInContainer)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for new nodes added to the pool because the node
|
||||
// may need to be added to an insertion point.
|
||||
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
|
||||
// Add insertion point to destination insertion points of fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().AppendElement(aContainer);
|
||||
}
|
||||
}
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DistributeSingleNode(aChild);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -689,25 +621,32 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
|||
int32_t aIndexInContainer,
|
||||
nsIContent* aPreviousSibling)
|
||||
{
|
||||
if (mInsertionPointChanged) {
|
||||
DistributeAllNodes();
|
||||
mInsertionPointChanged = false;
|
||||
// Check to ensure that the content is in the same anonymous tree
|
||||
// as the container because anonymous content may report its container
|
||||
// as the host but it may not be in the host's child list.
|
||||
if (!nsContentUtils::IsInSameAnonymousTree(aContainer, aChild)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear destination insertion points for removed
|
||||
// fallback content.
|
||||
if (nsContentUtils::IsContentInsertionPoint(aContainer)) {
|
||||
HTMLContentElement* content = HTMLContentElement::FromContent(aContainer);
|
||||
if (content->MatchedNodes().IsEmpty()) {
|
||||
aChild->DestInsertionPoints().Clear();
|
||||
}
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Watch for node that is removed from the pool because
|
||||
// it may need to be removed from an insertion point.
|
||||
if (IsPooledNode(aChild, aContainer, mPoolHost)) {
|
||||
RemoveDistributedNode(aChild);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
nsAutoString slotName;
|
||||
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,49 +656,3 @@ ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
|
|||
*aResult = nullptr;
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
void
|
||||
ShadowRoot::DestroyContent()
|
||||
{
|
||||
if (mOlderShadow) {
|
||||
mOlderShadow->DestroyContent();
|
||||
}
|
||||
DocumentFragment::DestroyContent();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
|
||||
mShadowRoot)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList)
|
||||
NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
|
||||
ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
|
||||
: mShadowRoot(aShadowRoot)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ShadowRootStyleSheetList);
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
|
||||
if (!aFound) {
|
||||
return nullptr;
|
||||
}
|
||||
return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ShadowRootStyleSheetList::Length()
|
||||
{
|
||||
return mShadowRoot->mProtoBinding->SheetCount();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
#define mozilla_dom_shadowroot_h__
|
||||
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/StyleSheetList.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/dom/StyleScope.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIContentInlines.h"
|
||||
|
@ -21,17 +20,17 @@ class nsIContent;
|
|||
class nsXBLPrototypeBinding;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Element;
|
||||
class HTMLContentElement;
|
||||
class HTMLShadowElement;
|
||||
class ShadowRootStyleSheetList;
|
||||
|
||||
class ShadowRoot final : public DocumentFragment,
|
||||
public StyleScope,
|
||||
public nsStubMutationObserver
|
||||
{
|
||||
friend class ShadowRootStyleSheetList;
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
|
||||
DocumentFragment)
|
||||
|
@ -42,46 +41,38 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
|
||||
ShadowRoot(nsIContent* aContent, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
ShadowRoot(Element* aElement, bool aClosed,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
nsXBLPrototypeBinding* aProtoBinding);
|
||||
|
||||
// Shadow DOM v1
|
||||
Element* Host();
|
||||
ShadowRootMode Mode() const
|
||||
{
|
||||
return mMode;
|
||||
}
|
||||
bool IsClosed() const
|
||||
{
|
||||
return mMode == ShadowRootMode::Closed;
|
||||
}
|
||||
|
||||
// StyleScope.
|
||||
nsINode& AsNode() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
// [deprecated] Shadow DOM v0
|
||||
void AddToIdTable(Element* aElement, nsIAtom* aId);
|
||||
void RemoveFromIdTable(Element* aElement, nsIAtom* aId);
|
||||
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
|
||||
void RemoveSheet(StyleSheet* aSheet);
|
||||
bool ApplyAuthorStyles();
|
||||
void SetApplyAuthorStyles(bool aApplyAuthorStyles);
|
||||
StyleSheetList* StyleSheets();
|
||||
HTMLShadowElement* GetShadowElement() { return mShadowElement; }
|
||||
|
||||
/**
|
||||
* Sets the current shadow insertion point where the older
|
||||
* ShadowRoot will be projected.
|
||||
*/
|
||||
void SetShadowElement(HTMLShadowElement* aShadowElement);
|
||||
|
||||
/**
|
||||
* Change the node that populates the distribution pool with
|
||||
* its children. This is distinct from the ShadowRoot host described
|
||||
* in the specifications. The ShadowRoot host is the element
|
||||
* which created this ShadowRoot and does not change. The pool host
|
||||
* is the same as the ShadowRoot host if this is the youngest
|
||||
* ShadowRoot. If this is an older ShadowRoot, the pool host is
|
||||
* the <shadow> element in the younger ShadowRoot (if it exists).
|
||||
*/
|
||||
void ChangePoolHost(nsIContent* aNewHost);
|
||||
|
||||
/**
|
||||
* Distributes a single explicit child of the pool host to the content
|
||||
* insertion points in this ShadowRoot.
|
||||
*/
|
||||
void DistributeSingleNode(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Removes a single explicit child of the pool host from the content
|
||||
* insertion points in this ShadowRoot.
|
||||
*/
|
||||
void RemoveDistributedNode(nsIContent* aContent);
|
||||
StyleSheetList* StyleSheets()
|
||||
{
|
||||
return &StyleScope::EnsureDOMStyleSheets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Distributes all the explicit children of the pool host to the content
|
||||
|
@ -89,29 +80,47 @@ public:
|
|||
*/
|
||||
void DistributeAllNodes();
|
||||
|
||||
void AddInsertionPoint(HTMLContentElement* aInsertionPoint);
|
||||
void RemoveInsertionPoint(HTMLContentElement* aInsertionPoint);
|
||||
private:
|
||||
/**
|
||||
* Try to reassign an element to a slot and returns whether the assignment
|
||||
* changed.
|
||||
*/
|
||||
bool MaybeReassignElement(Element* aElement, const nsAttrValue* aOldValue);
|
||||
|
||||
/**
|
||||
* Try to assign aContent to a slot in the shadow tree, returns the assigned
|
||||
* slot if found.
|
||||
*/
|
||||
const HTMLSlotElement* AssignSlotFor(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Unassign aContent from the assigned slot in the shadow tree, returns the
|
||||
* assigned slot if found.
|
||||
*
|
||||
* Note: slot attribute of aContent may have changed already, so pass slot
|
||||
* name explicity here.
|
||||
*/
|
||||
const HTMLSlotElement* UnassignSlotFor(nsIContent* aContent,
|
||||
const nsAString& aSlotName);
|
||||
|
||||
/**
|
||||
* Called when we redistribute content after insertion points have changed.
|
||||
*/
|
||||
void DistributionChanged();
|
||||
|
||||
bool IsPooledNode(nsIContent* aChild) const;
|
||||
|
||||
public:
|
||||
void AddSlot(HTMLSlotElement* aSlot);
|
||||
void RemoveSlot(HTMLSlotElement* aSlot);
|
||||
|
||||
void SetYoungerShadow(ShadowRoot* aYoungerShadow);
|
||||
ShadowRoot* GetYoungerShadowRoot() { return mYoungerShadow; }
|
||||
void SetInsertionPointChanged() { mInsertionPointChanged = true; }
|
||||
|
||||
void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
|
||||
|
||||
nsISupports* GetParentObject() const { return mPoolHost; }
|
||||
|
||||
nsIContent* GetPoolHost() { return mPoolHost; }
|
||||
nsTArray<HTMLShadowElement*>& ShadowDescendants() { return mShadowDescendants; }
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static bool IsPooledNode(nsIContent* aChild, nsIContent* aContainer,
|
||||
nsIContent* aHost);
|
||||
static ShadowRoot* FromNode(nsINode* aNode);
|
||||
static bool IsShadowInsertionPoint(nsIContent* aContent);
|
||||
|
||||
static void RemoveDestInsertionPoint(nsIContent* aInsertionPoint,
|
||||
nsTArray<nsIContent*>& aDestInsertionPoints);
|
||||
|
||||
// WebIDL methods.
|
||||
Element* GetElementById(const nsAString& aElementId);
|
||||
|
@ -124,8 +133,6 @@ public:
|
|||
GetElementsByClassName(const nsAString& aClasses);
|
||||
void GetInnerHTML(nsAString& aInnerHTML);
|
||||
void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
|
||||
Element* Host();
|
||||
ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; }
|
||||
void StyleSheetChanged();
|
||||
|
||||
bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
|
||||
|
@ -134,24 +141,17 @@ public:
|
|||
mIsComposedDocParticipant = aIsComposedDocParticipant;
|
||||
}
|
||||
|
||||
virtual void DestroyContent() override;
|
||||
nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
protected:
|
||||
virtual ~ShadowRoot();
|
||||
|
||||
// The pool host is the parent of the nodes that will be distributed
|
||||
// into the insertion points in this ShadowRoot. See |ChangeShadowRoot|.
|
||||
nsCOMPtr<nsIContent> mPoolHost;
|
||||
ShadowRootMode mMode;
|
||||
|
||||
// An array of content insertion points that are a descendant of the ShadowRoot
|
||||
// sorted in tree order. Insertion points are responsible for notifying
|
||||
// the ShadowRoot when they are removed or added as a descendant. The insertion
|
||||
// points are kept alive by the parent node, thus weak references are held
|
||||
// by the array.
|
||||
nsTArray<HTMLContentElement*> mInsertionPoints;
|
||||
|
||||
// An array of the <shadow> elements that are descendant of the ShadowRoot
|
||||
// sorted in tree order. Only the first may be a shadow insertion point.
|
||||
nsTArray<HTMLShadowElement*> mShadowDescendants;
|
||||
// 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, nsTArray<mozilla::dom::HTMLSlotElement*>> mSlotMap;
|
||||
|
||||
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
|
||||
nsXBLPrototypeBinding* mProtoBinding;
|
||||
|
@ -161,19 +161,6 @@ protected:
|
|||
// owns |mProtoBinding|.
|
||||
RefPtr<nsXBLBinding> mAssociatedBinding;
|
||||
|
||||
RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
|
||||
|
||||
// The current shadow insertion point of this ShadowRoot.
|
||||
HTMLShadowElement* mShadowElement;
|
||||
|
||||
// The ShadowRoot that was created by the host element before
|
||||
// this ShadowRoot was created.
|
||||
RefPtr<ShadowRoot> mOlderShadow;
|
||||
|
||||
// The ShadowRoot that was created by the host element after
|
||||
// this ShadowRoot was created.
|
||||
RefPtr<ShadowRoot> mYoungerShadow;
|
||||
|
||||
// A boolean that indicates that an insertion point was added or removed
|
||||
// from this ShadowRoot and that the nodes need to be redistributed into
|
||||
// the insertion points. After this flag is set, nodes will be distributed
|
||||
|
@ -189,28 +176,6 @@ protected:
|
|||
nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override;
|
||||
};
|
||||
|
||||
class ShadowRootStyleSheetList : public StyleSheetList
|
||||
{
|
||||
public:
|
||||
explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
|
||||
|
||||
virtual nsINode* GetParentObject() const override
|
||||
{
|
||||
return mShadowRoot;
|
||||
}
|
||||
|
||||
uint32_t Length() override;
|
||||
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
|
||||
|
||||
protected:
|
||||
virtual ~ShadowRootStyleSheetList();
|
||||
|
||||
RefPtr<ShadowRoot> mShadowRoot;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "StyleScope.h"
|
||||
#include "mozilla/dom/StyleSheetList.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
StyleScope::~StyleScope()
|
||||
{
|
||||
}
|
||||
|
||||
StyleSheetList&
|
||||
StyleScope::EnsureDOMStyleSheets()
|
||||
{
|
||||
if (!mDOMStyleSheets) {
|
||||
mDOMStyleSheets = new StyleSheetList(*this);
|
||||
}
|
||||
return *mDOMStyleSheets;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- 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_StyleScope_h__
|
||||
#define mozilla_dom_StyleScope_h__
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsINode;
|
||||
|
||||
namespace mozilla {
|
||||
class StyleSheet;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class StyleSheetList;
|
||||
|
||||
/**
|
||||
* A class meant to be shared by ShadowRoot and Document, that holds a list of
|
||||
* stylesheets.
|
||||
*
|
||||
* TODO(emilio, bug 1418159): In the future this should hold most of the
|
||||
* relevant style state, this should allow us to fix bug 548397.
|
||||
*/
|
||||
class StyleScope
|
||||
{
|
||||
public:
|
||||
virtual nsINode& AsNode() = 0;
|
||||
|
||||
const nsINode& AsNode() const
|
||||
{
|
||||
return const_cast<StyleScope&>(*this).AsNode();
|
||||
}
|
||||
|
||||
StyleSheet* SheetAt(size_t aIndex) const
|
||||
{
|
||||
return mStyleSheets.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
size_t SheetCount() const
|
||||
{
|
||||
return mStyleSheets.Length();
|
||||
}
|
||||
|
||||
int32_t IndexOfSheet(const StyleSheet& aSheet) const
|
||||
{
|
||||
return mStyleSheets.IndexOf(&aSheet);
|
||||
}
|
||||
|
||||
void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
|
||||
{
|
||||
mStyleSheets.InsertElementAt(aIndex, &aSheet);
|
||||
}
|
||||
|
||||
void RemoveSheet(StyleSheet& aSheet)
|
||||
{
|
||||
mStyleSheets.RemoveElement(&aSheet);
|
||||
}
|
||||
|
||||
void AppendStyleSheet(StyleSheet& aSheet)
|
||||
{
|
||||
mStyleSheets.AppendElement(&aSheet);
|
||||
}
|
||||
|
||||
StyleSheetList& EnsureDOMStyleSheets();
|
||||
|
||||
~StyleScope();
|
||||
|
||||
protected:
|
||||
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
|
||||
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "mozilla/CSSStyleSheet.h"
|
||||
#include "mozilla/dom/StyleSheetListBinding.h"
|
||||
#include "nsStubDocumentObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -17,7 +18,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
|
||||
|
@ -43,5 +45,24 @@ StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
|
||||
{
|
||||
mStyleScope = nullptr;
|
||||
}
|
||||
|
||||
StyleSheetList::StyleSheetList(StyleScope& aScope)
|
||||
: mStyleScope(&aScope)
|
||||
{
|
||||
mStyleScope->AsNode().AddMutationObserver(this);
|
||||
}
|
||||
|
||||
StyleSheetList::~StyleSheetList()
|
||||
{
|
||||
if (mStyleScope) {
|
||||
mStyleScope->AsNode().RemoveMutationObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#ifndef mozilla_dom_StyleSheetList_h
|
||||
#define mozilla_dom_StyleSheetList_h
|
||||
|
||||
#include "mozilla/dom/StyleScope.h"
|
||||
#include "nsIDOMStyleSheetList.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsStubDocumentObserver.h"
|
||||
|
||||
class nsINode;
|
||||
|
||||
|
@ -17,28 +19,54 @@ class StyleSheet;
|
|||
|
||||
namespace dom {
|
||||
|
||||
class StyleSheetList : public nsIDOMStyleSheetList
|
||||
, public nsWrapperCache
|
||||
class StyleSheetList final : public nsIDOMStyleSheetList
|
||||
, public nsWrapperCache
|
||||
, public nsStubDocumentObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
|
||||
|
||||
NS_DECL_NSIDOMSTYLESHEETLIST
|
||||
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
|
||||
|
||||
explicit StyleSheetList(StyleScope& aScope);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
|
||||
|
||||
virtual nsINode* GetParentObject() const = 0;
|
||||
nsINode* GetParentObject() const
|
||||
{
|
||||
return mStyleScope ? &mStyleScope->AsNode() : nullptr;
|
||||
}
|
||||
|
||||
virtual uint32_t Length() = 0;
|
||||
virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
|
||||
StyleSheet* Item(uint32_t aIndex)
|
||||
uint32_t Length() const
|
||||
{
|
||||
return mStyleScope ? mStyleScope->SheetCount() : 0;
|
||||
}
|
||||
|
||||
StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
|
||||
{
|
||||
if (!mStyleScope) {
|
||||
aFound = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StyleSheet* sheet = mStyleScope->SheetAt(aIndex);
|
||||
aFound = !!sheet;
|
||||
return sheet;
|
||||
}
|
||||
|
||||
StyleSheet* Item(uint32_t aIndex) const
|
||||
{
|
||||
bool dummy = false;
|
||||
return IndexedGetter(aIndex, dummy);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~StyleSheetList() {}
|
||||
virtual ~StyleSheetList();
|
||||
|
||||
StyleScope* mStyleScope; // Weak, cleared on "NodeWillBeDestroyed".
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<html>
|
||||
<head>
|
||||
<script>
|
||||
try { o1 = document.createElement('textarea') } catch(e) { }
|
||||
try { o2 = document.createElement('div') } catch(e) { }
|
||||
try { o3 = document.createElement('map') } catch(e) { }
|
||||
try { document.documentElement.appendChild(o2) } catch(e) { }
|
||||
try { o2.appendChild(o1) } catch(e) { }
|
||||
try { document.documentElement.getClientRects() } catch(e) { }
|
||||
try { o4 = o2.attachShadow({ mode: "open" }); } catch(e) { }
|
||||
try { o1.appendChild(o3) } catch(e) { }
|
||||
try { o5 = o3.parentElement } catch(e) { }
|
||||
try { o3.outerHTML = "\n" } catch(e) { }
|
||||
try { o4.prepend("", o5, "") } catch(e) { }
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<!-- Testing slot element with "dom.webcomponents.enabled" set to false -->
|
||||
<slot><div></div></slot>
|
||||
</html>
|
|
@ -193,7 +193,7 @@ load 930250.html
|
|||
load 942979.html
|
||||
load 973401.html
|
||||
load 978646.html
|
||||
pref(dom.webcomponents.enabled,true) load 1024428-1.html
|
||||
pref(dom.webcomponents.enabled,true) load 1024428-1.html # bug 1340009
|
||||
load 1026714.html
|
||||
pref(dom.webcomponents.enabled,true) load 1027461-1.html
|
||||
pref(dom.webcomponents.enabled,true) load 1029710.html
|
||||
|
@ -209,4 +209,6 @@ load 1230422.html
|
|||
load 1251361.html
|
||||
load 1304437.html
|
||||
pref(clipboard.autocopy,true) load 1385272-1.html
|
||||
pref(dom.webcomponents.customelements.enabled,true) load 1341693.html
|
||||
pref(dom.webcomponents.enabled,true) load 1341693.html
|
||||
pref(dom.webcomponents.enabled,true) load 1419799.html
|
||||
pref(dom.webcomponents.enabled,false) load 1422931.html
|
||||
|
|
|
@ -213,6 +213,7 @@ EXPORTS.mozilla.dom += [
|
|||
'SimpleTreeIterator.h',
|
||||
'StructuredCloneHolder.h',
|
||||
'StructuredCloneTags.h',
|
||||
'StyleScope.h',
|
||||
'StyleSheetList.h',
|
||||
'SubtleCrypto.h',
|
||||
'TabGroup.h',
|
||||
|
@ -358,6 +359,7 @@ SOURCES += [
|
|||
'ScriptSettings.cpp',
|
||||
'ShadowRoot.cpp',
|
||||
'StructuredCloneHolder.cpp',
|
||||
'StyleScope.cpp',
|
||||
'StyleSheetList.cpp',
|
||||
'SubtleCrypto.cpp',
|
||||
'TabGroup.cpp',
|
||||
|
|
|
@ -382,12 +382,15 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue)
|
||||
{
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -407,21 +410,22 @@ nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName,
|
||||
nsAttrValue& aValue, bool* aHadValue)
|
||||
{
|
||||
int32_t namespaceID = aName->NamespaceID();
|
||||
nsIAtom* localName = aName->NameAtom();
|
||||
if (namespaceID == kNameSpaceID_None) {
|
||||
return SetAndSwapAttr(localName, aValue);
|
||||
return SetAndSwapAttr(localName, aValue, aHadValue);
|
||||
}
|
||||
|
||||
*aHadValue = false;
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(localName, namespaceID)) {
|
||||
ATTRS(mImpl)[i].mName.SetTo(aName);
|
||||
ATTRS(mImpl)[i].mValue.Reset();
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
|
||||
*aHadValue = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -576,10 +580,11 @@ nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID) cons
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrAndChildArray::SetAndSwapMappedAttr(nsIAtom* aLocalName,
|
||||
nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet)
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue)
|
||||
{
|
||||
bool willAdd = true;
|
||||
if (mImpl && mImpl->mMappedAttrs) {
|
||||
|
@ -589,7 +594,7 @@ nsAttrAndChildArray::SetAndTakeMappedAttr(nsIAtom* aLocalName,
|
|||
RefPtr<nsMappedAttributes> mapped =
|
||||
GetModifiableMapped(aContent, aSheet, willAdd);
|
||||
|
||||
mapped->SetAndTakeAttr(aLocalName, aValue);
|
||||
mapped->SetAndSwapAttr(aLocalName, aValue, aHadValue);
|
||||
|
||||
return MakeMappedUnique(mapped);
|
||||
}
|
||||
|
@ -714,10 +719,19 @@ nsAttrAndChildArray::MappedAttrCount() const
|
|||
return mImpl && mImpl->mMappedAttrs ? (uint32_t)mImpl->mMappedAttrs->Count() : 0;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument)
|
||||
{
|
||||
nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
|
||||
RefPtr<nsMappedAttributes> mapped = GetModifiableMapped(aContent, sheet, false, 0);
|
||||
return MakeMappedUnique(mapped);
|
||||
}
|
||||
|
||||
nsMappedAttributes*
|
||||
nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool aWillAddAttr)
|
||||
bool aWillAddAttr,
|
||||
int32_t aAttrCount)
|
||||
{
|
||||
if (mImpl && mImpl->mMappedAttrs) {
|
||||
return mImpl->mMappedAttrs->Clone(aWillAddAttr);
|
||||
|
@ -727,7 +741,7 @@ nsAttrAndChildArray::GetModifiableMapped(nsMappedAttributeElement* aContent,
|
|||
|
||||
nsMapRuleToAttributesFunc mapRuleFunc =
|
||||
aContent->GetAttributeMappingFunction();
|
||||
return new nsMappedAttributes(aSheet, mapRuleFunc);
|
||||
return new (aAttrCount) nsMappedAttributes(aSheet, mapRuleFunc);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -91,8 +91,13 @@ public:
|
|||
nsCaseTreatment aCaseSensitive) const;
|
||||
const nsAttrValue* AttrAt(uint32_t aPos) const;
|
||||
// SetAndSwapAttr swaps the current attribute value with aValue.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
|
||||
bool* aHadValue);
|
||||
|
||||
// Remove the attr at position aPos. The value of the attr is placed in
|
||||
// aValue; any value that was already in aValue is destroyed.
|
||||
|
@ -110,9 +115,14 @@ public:
|
|||
const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
|
||||
int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
|
||||
|
||||
nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
// SetAndSwapMappedAttr swaps the current attribute value with aValue.
|
||||
// If the attribute was unset, an empty value will be swapped into aValue
|
||||
// and aHadValue will be set to false. Otherwise, aHadValue will be set to
|
||||
// true.
|
||||
nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
|
||||
nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet);
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool* aHadValue);
|
||||
nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
|
||||
if (!mImpl || !mImpl->mMappedAttrs) {
|
||||
return NS_OK;
|
||||
|
@ -135,6 +145,9 @@ public:
|
|||
return MappedAttrCount();
|
||||
}
|
||||
|
||||
// Force this to have mapped attributes, even if those attributes are empty.
|
||||
nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
|
||||
|
||||
private:
|
||||
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
|
||||
nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
|
||||
|
@ -148,7 +161,8 @@ private:
|
|||
nsMappedAttributes*
|
||||
GetModifiableMapped(nsMappedAttributeElement* aContent,
|
||||
nsHTMLStyleSheet* aSheet,
|
||||
bool aWillAddAttr);
|
||||
bool aWillAddAttr,
|
||||
int32_t aAttrCount = 1);
|
||||
nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
|
||||
|
||||
uint32_t AttrSlotsSize() const
|
||||
|
|
|
@ -49,20 +49,13 @@ public:
|
|||
, mCheapString(nullptr)
|
||||
{ }
|
||||
|
||||
void TakeParsedValue(nsAttrValue& aValue)
|
||||
void ResetToAttrValue(const nsAttrValue& aValue)
|
||||
{
|
||||
mStoredAttrValue.SwapValueWith(aValue);
|
||||
mAttrValue = &mStoredAttrValue;
|
||||
mAttrValue = &aValue;
|
||||
mStringPtr = nullptr;
|
||||
// No need to touch mCheapString here. If we need to use it, we will reset
|
||||
// it to the rigthe value anyway.
|
||||
}
|
||||
/**
|
||||
* If TakeParsedValue has been called, returns the value that it set.
|
||||
*/
|
||||
nsAttrValue* GetStoredAttrValue()
|
||||
{
|
||||
return mAttrValue == &mStoredAttrValue ? &mStoredAttrValue : nullptr;
|
||||
}
|
||||
const nsAttrValue* GetAttrValue() { return mAttrValue; }
|
||||
|
||||
/**
|
||||
* Returns a reference to the string value of the contents of this object.
|
||||
|
@ -85,11 +78,24 @@ public:
|
|||
return aOther.EqualsAsStrings(*mAttrValue);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the value stored is empty
|
||||
*/
|
||||
bool IsEmpty() const
|
||||
{
|
||||
if (mStringPtr) {
|
||||
return mStringPtr->IsEmpty();
|
||||
}
|
||||
if (mAttrValue) {
|
||||
return mAttrValue->IsEmptyString();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
const nsAttrValue* mAttrValue;
|
||||
mutable const nsAString* mStringPtr;
|
||||
mutable nsCheapString mCheapString;
|
||||
nsAttrValue mStoredAttrValue;
|
||||
};
|
||||
|
||||
#endif // nsAttrValueOrString_h___
|
||||
|
|
|
@ -44,9 +44,8 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FileSystemSecurity.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
#include "mozilla/dom/HTMLShadowElement.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
@ -102,7 +101,9 @@
|
|||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "nsHtml5Module.h"
|
||||
#include "nsHtml5StringParser.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "nsIAddonPolicyService.h"
|
||||
#include "nsIAnonymousContentCreator.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
|
@ -500,6 +501,8 @@ nsContentUtils::Init()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsHTMLTags::AddRefTable();
|
||||
|
||||
sNameSpaceManager = nsNameSpaceManager::GetInstance();
|
||||
NS_ENSURE_TRUE(sNameSpaceManager, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
|
@ -590,7 +593,7 @@ nsContentUtils::Init()
|
|||
"dom.webcomponents.enabled", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sIsCustomElementsEnabled,
|
||||
"dom.webcomponents.customelements.enabled", false);
|
||||
"dom.webcomponents.enabled", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sEncodeDecodeURLHash,
|
||||
"dom.url.encode_decode_hash", false);
|
||||
|
@ -1926,6 +1929,8 @@ nsContentUtils::Shutdown()
|
|||
{
|
||||
sInitialized = false;
|
||||
|
||||
nsHTMLTags::ReleaseTable();
|
||||
|
||||
NS_IF_RELEASE(sContentPolicyService);
|
||||
sTriedToGetContentPolicy = false;
|
||||
uint32_t i;
|
||||
|
@ -2390,6 +2395,9 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
|
|||
bool* aDisconnected)
|
||||
{
|
||||
if (aParent1 == aParent2) {
|
||||
// XXX This is odd. aOffset1 and/or aOffset2 may be -1, e.g., it's result
|
||||
// of nsINode::IndexOf(), but this compares such invalid offset with
|
||||
// valid offset.
|
||||
return aOffset1 < aOffset2 ? -1 :
|
||||
aOffset1 > aOffset2 ? 1 :
|
||||
0;
|
||||
|
@ -2440,10 +2448,14 @@ nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
|
|||
|
||||
if (!pos1) {
|
||||
nsINode* child2 = parents2.ElementAt(--pos2);
|
||||
// XXX aOffset1 may be -1 as mentioned above. So, why does this return
|
||||
// it's *before* of the valid DOM point?
|
||||
return aOffset1 <= parent->IndexOf(child2) ? -1 : 1;
|
||||
}
|
||||
|
||||
nsINode* child1 = parents1.ElementAt(--pos1);
|
||||
// XXX aOffset2 may be -1 as mentioned above. So, why does this return it's
|
||||
// *after* of the valid DOM point?
|
||||
return parent->IndexOf(child1) < aOffset2 ? -1 : 1;
|
||||
}
|
||||
|
||||
|
@ -4943,17 +4955,7 @@ nsContentUtils::IsInSameAnonymousTree(const nsINode* aNode,
|
|||
return aContent->GetBindingParent() == nullptr;
|
||||
}
|
||||
|
||||
const nsIContent* nodeAsContent = static_cast<const nsIContent*>(aNode);
|
||||
|
||||
// For nodes in a shadow tree, it is insufficient to simply compare
|
||||
// the binding parent because a node may host multiple ShadowRoots,
|
||||
// thus nodes in different shadow tree may have the same binding parent.
|
||||
if (aNode->IsInShadowTree()) {
|
||||
return nodeAsContent->GetContainingShadow() ==
|
||||
aContent->GetContainingShadow();
|
||||
}
|
||||
|
||||
return nodeAsContent->GetBindingParent() == aContent->GetBindingParent();
|
||||
return aNode->AsContent()->GetBindingParent() == aContent->GetBindingParent();
|
||||
}
|
||||
|
||||
class AnonymousContentDestroyer : public Runnable {
|
||||
|
@ -7015,25 +7017,11 @@ nsContentUtils::GetHTMLEditor(nsPresContext* aPresContext)
|
|||
return editor;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::IsContentInsertionPoint(nsIContent* aContent)
|
||||
{
|
||||
// Check if the content is a XBL insertion point.
|
||||
if (aContent->IsActiveChildrenElement()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the content is a web components content insertion point.
|
||||
HTMLContentElement* contentElement =
|
||||
HTMLContentElement::FromContent(aContent);
|
||||
return contentElement && contentElement->IsInsertionPoint();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
|
||||
{
|
||||
if (!aContent) {
|
||||
if (!aContent || !nsDocument::IsWebComponentsEnabled(aContent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -7043,26 +7031,11 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
|
|||
return true;
|
||||
}
|
||||
|
||||
ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
|
||||
if (shadow) {
|
||||
// Children of a shadow root are distributed to
|
||||
// the shadow insertion point of the younger shadow root.
|
||||
return shadow->GetYoungerShadowRoot();
|
||||
}
|
||||
|
||||
HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
|
||||
if (shadowEl && shadowEl->IsInsertionPoint()) {
|
||||
// Children of a shadow insertion points are distributed
|
||||
// to the insertion points in the older shadow root.
|
||||
return shadowEl->GetOlderShadowRoot();
|
||||
}
|
||||
|
||||
HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
|
||||
if (contentEl && contentEl->IsInsertionPoint()) {
|
||||
// Children of a content insertion point are distributed to the
|
||||
// content insertion point if the content insertion point does
|
||||
// not match any nodes (fallback content).
|
||||
return contentEl->MatchedNodes().IsEmpty();
|
||||
HTMLSlotElement* slotEl = HTMLSlotElement::FromContent(aContent);
|
||||
if (slotEl && slotEl->GetContainingShadow()) {
|
||||
// Children of a slot are rendered if the slot does not have any assigned
|
||||
// nodes (fallback content).
|
||||
return slotEl->AssignedNodes().IsEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -9675,35 +9648,6 @@ nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
|||
aDefinition);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
|
||||
int32_t aNamespaceID,
|
||||
nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
|
||||
// To support imported document.
|
||||
nsCOMPtr<nsIDocument> doc = aDoc->MasterDocument();
|
||||
|
||||
if (aNamespaceID != kNameSpaceID_XHTML ||
|
||||
!doc->GetDocShell()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(doc->GetInnerWindow());
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CustomElementRegistry> registry(window->CustomElements());
|
||||
if (!registry) {
|
||||
return;
|
||||
}
|
||||
|
||||
return registry->GetCustomPrototype(aAtom, aPrototype);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
|
||||
{
|
||||
|
@ -9837,6 +9781,24 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
|
|||
return reloadSucceeded;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
nsIDocument* aDocument,
|
||||
nsTArray<nsIContent*>& aElements)
|
||||
{
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
// XXXheycam This probably needs to find the nsCanvasFrame's NAC too.
|
||||
if (nsIPresShell* presShell = aDocument->GetShell()) {
|
||||
if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) {
|
||||
nsIAnonymousContentCreator* creator = do_QueryFrame(scrollFrame);
|
||||
MOZ_ASSERT(creator,
|
||||
"scroll frame should always implement nsIAnonymousContentCreator");
|
||||
creator->AppendAnonymousContentTo(aElements, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsContentUtils::IsLocalRefURL(const nsString& aString)
|
||||
{
|
||||
|
@ -9852,3 +9814,16 @@ nsContentUtils::IsLocalRefURL(const nsString& aString)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ Element*
|
||||
nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
MOZ_ASSERT(aElement->IsNativeAnonymous());
|
||||
|
||||
Element* e = aElement;
|
||||
while (e && e->IsNativeAnonymous()) {
|
||||
e = e->GetParentElement();
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -339,6 +339,13 @@ public:
|
|||
* NOTE! If the two nodes aren't in the same connected subtree,
|
||||
* the result is 1, and the optional aDisconnected parameter
|
||||
* is set to true.
|
||||
*
|
||||
* XXX aOffset1 and aOffset2 should be uint32_t since valid offset value is
|
||||
* between 0 - UINT32_MAX. However, these methods work even with
|
||||
* negative offset values! E.g., when aOffset1 is -1 and aOffset is 0,
|
||||
* these methods return -1. Some root callers depend on this behavior.
|
||||
* On the other hand, nsINode can have ATTRCHILD_ARRAY_MAX_CHILD_COUN
|
||||
* (0x3FFFFF) at most. Therefore, they can be int32_t for now.
|
||||
*/
|
||||
static int32_t ComparePoints(nsINode* aParent1, int32_t aOffset1,
|
||||
nsINode* aParent2, int32_t aOffset2,
|
||||
|
@ -582,7 +589,7 @@ public:
|
|||
|
||||
/**
|
||||
* Returns true if |aName| is a valid name to be registered via
|
||||
* document.registerElement.
|
||||
* customElements.define.
|
||||
*/
|
||||
static bool IsCustomElementName(nsIAtom* aName);
|
||||
|
||||
|
@ -2407,18 +2414,6 @@ public:
|
|||
*/
|
||||
static mozilla::LogModule* DOMDumpLog();
|
||||
|
||||
/**
|
||||
* Returns whether a content is an insertion point for XBL
|
||||
* bindings or web components ShadowRoot. In web components,
|
||||
* this corresponds to a <content> element that participates
|
||||
* in node distribution. In XBL this corresponds to an
|
||||
* <xbl:children> element in anonymous content.
|
||||
*
|
||||
* @param aContent The content to test for being an insertion point.
|
||||
*/
|
||||
static bool IsContentInsertionPoint(nsIContent* aContent);
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the children of the provided content are
|
||||
* nodes that are distributed to Shadow DOM insertion points.
|
||||
|
@ -2735,13 +2730,18 @@ public:
|
|||
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
|
||||
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
|
||||
|
||||
static void GetCustomPrototype(nsIDocument* aDoc,
|
||||
int32_t aNamespaceID,
|
||||
nsIAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> prototype);
|
||||
|
||||
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
|
||||
|
||||
/**
|
||||
* Appends all "document level" native anonymous content subtree roots for
|
||||
* aDocument to aElements. Document level NAC subtrees are those created
|
||||
* by ancestor frames of the document element's primary frame, such as
|
||||
* the scrollbar elements created by the root scroll frame.
|
||||
*/
|
||||
static void AppendDocumentLevelNativeAnonymousContentTo(
|
||||
nsIDocument* aDocument,
|
||||
nsTArray<nsIContent*>& aElements);
|
||||
|
||||
/**
|
||||
* Detect whether a string is a (CSS) local-url.
|
||||
* https://drafts.csswg.org/css-values/#local-urls
|
||||
|
@ -2752,6 +2752,12 @@ public:
|
|||
static bool
|
||||
IsWebComponentsEnabled() { return sIsWebComponentsEnabled; }
|
||||
|
||||
/**
|
||||
* Walks up the tree from aElement until it finds an element that is
|
||||
* not native anonymous content. aElement must be NAC itself.
|
||||
*/
|
||||
static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
|
||||
|
||||
static bool
|
||||
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
|
||||
|
||||
|
|
|
@ -524,3 +524,9 @@ nsDOMAttributeMap::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
{
|
||||
return NamedNodeMapBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
DocGroup*
|
||||
nsDOMAttributeMap::GetDocGroup() const
|
||||
{
|
||||
return mContent ? mContent->OwnerDoc()->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
|
||||
class nsIAtom;
|
||||
class nsIDocument;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class DocGroup;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
* Structure used as a key for caching Attrs in nsDOMAttributeMap's mAttributeCache.
|
||||
|
@ -87,6 +92,7 @@ class nsDOMAttributeMap final : public nsIDOMMozNamedAttrMap
|
|||
{
|
||||
public:
|
||||
typedef mozilla::dom::Attr Attr;
|
||||
typedef mozilla::dom::DocGroup DocGroup;
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
|
||||
|
@ -135,6 +141,7 @@ public:
|
|||
return mContent;
|
||||
}
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
// WebIDL
|
||||
Attr* GetNamedItem(const nsAString& aAttrName);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
|
@ -613,6 +614,28 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
nsDOMMutationObserver::QueueMutationObserverMicroTask()
|
||||
{
|
||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||
if (!ccjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MutationObserverMicroTask> momt =
|
||||
new MutationObserverMicroTask();
|
||||
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMutationObserver::HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||
{
|
||||
if (sScheduledMutationObservers ||
|
||||
mozilla::dom::DocGroup::sPendingDocGroups) {
|
||||
HandleMutationsInternal(aAso);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMutationObserver::RescheduleForRun()
|
||||
{
|
||||
|
@ -891,7 +914,23 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
|
|||
{
|
||||
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
|
||||
|
||||
while (sScheduledMutationObservers) {
|
||||
// Let signalList be a copy of unit of related similar-origin browsing
|
||||
// contexts' signal slot list.
|
||||
nsTArray<RefPtr<HTMLSlotElement>> signalList;
|
||||
if (DocGroup::sPendingDocGroups) {
|
||||
for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
|
||||
DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
|
||||
signalList.AppendElements(docGroup->SignalSlotList());
|
||||
|
||||
// Empty unit of related similar-origin browsing contexts' signal slot
|
||||
// list.
|
||||
docGroup->ClearSignalSlotList();
|
||||
}
|
||||
delete DocGroup::sPendingDocGroups;
|
||||
DocGroup::sPendingDocGroups = nullptr;
|
||||
}
|
||||
|
||||
if (sScheduledMutationObservers) {
|
||||
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
|
||||
sScheduledMutationObservers;
|
||||
sScheduledMutationObservers = nullptr;
|
||||
|
@ -921,6 +960,11 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
|
|||
delete suppressedObservers;
|
||||
suppressedObservers = nullptr;
|
||||
}
|
||||
|
||||
// Fire slotchange event for each slot in signalList.
|
||||
for (uint32_t i = 0; i < signalList.Length(); ++i) {
|
||||
signalList[i]->FireSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
nsDOMMutationRecord*
|
||||
|
|
|
@ -552,12 +552,9 @@ public:
|
|||
}
|
||||
|
||||
// static methods
|
||||
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||
{
|
||||
if (sScheduledMutationObservers) {
|
||||
HandleMutationsInternal(aAso);
|
||||
}
|
||||
}
|
||||
static void QueueMutationObserverMicroTask();
|
||||
|
||||
static void HandleMutations(mozilla::AutoSlowOperation& aAso);
|
||||
|
||||
static bool AllScheduledMutationObserversAreSuppressed()
|
||||
{
|
||||
|
|
|
@ -366,6 +366,12 @@ nsDOMTokenList::Stringify(nsAString& aResult)
|
|||
mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
|
||||
}
|
||||
|
||||
DocGroup*
|
||||
nsDOMTokenList::GetDocGroup() const
|
||||
{
|
||||
return mElement ? mElement->OwnerDoc()->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDOMTokenList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
class DocGroup;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsAttrValue;
|
||||
|
@ -35,6 +37,7 @@ class nsDOMTokenList : public nsISupports,
|
|||
{
|
||||
protected:
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef mozilla::dom::DocGroup DocGroup;
|
||||
typedef nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>
|
||||
WhitespaceTokenizer;
|
||||
|
||||
|
@ -52,6 +55,8 @@ public:
|
|||
return mElement;
|
||||
}
|
||||
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
uint32_t Length();
|
||||
void Item(uint32_t aIndex, nsAString& aResult)
|
||||
{
|
||||
|
|
|
@ -3473,7 +3473,7 @@ nsDOMWindowUtils::AddSheet(nsIDOMStyleSheet *aSheet, uint32_t aSheetType)
|
|||
nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
|
||||
RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
|
||||
NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
|
||||
if (sheet->GetOwningDocument()) {
|
||||
if (sheet->GetAssociatedDocument()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return doc->AddAdditionalStyleSheet(type, sheet);
|
||||
|
@ -3657,11 +3657,11 @@ nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
|
|||
|
||||
RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
|
||||
nsIFrame* frame = element->GetPrimaryFrame();
|
||||
if (frame && !aPseudoElement.IsEmpty()) {
|
||||
if (!aPseudoElement.IsEmpty()) {
|
||||
if (aPseudoElement.EqualsLiteral("::before")) {
|
||||
frame = nsLayoutUtils::GetBeforeFrame(frame);
|
||||
frame = nsLayoutUtils::GetBeforeFrame(element);
|
||||
} else if (aPseudoElement.EqualsLiteral("::after")) {
|
||||
frame = nsLayoutUtils::GetAfterFrame(frame);
|
||||
frame = nsLayoutUtils::GetAfterFrame(element);
|
||||
} else {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
|
|
@ -116,7 +116,6 @@
|
|||
|
||||
#include "nsBidiUtils.h"
|
||||
|
||||
#include "nsIParserService.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
|
||||
#include "nsIScriptContext.h"
|
||||
|
@ -571,78 +570,6 @@ struct nsRadioGroupStruct
|
|||
bool mGroupSuffersFromValueMissing;
|
||||
};
|
||||
|
||||
|
||||
nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
|
||||
{
|
||||
mLength = -1;
|
||||
// Not reference counted to avoid circular references.
|
||||
// The document will tell us when its going away.
|
||||
mDocument = aDocument;
|
||||
mDocument->AddObserver(this);
|
||||
}
|
||||
|
||||
nsDOMStyleSheetList::~nsDOMStyleSheetList()
|
||||
{
|
||||
if (mDocument) {
|
||||
mDocument->RemoveObserver(this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList,
|
||||
nsIDocumentObserver,
|
||||
nsIMutationObserver)
|
||||
|
||||
uint32_t
|
||||
nsDOMStyleSheetList::Length()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// XXX Find the number and then cache it. We'll use the
|
||||
// observer notification to figure out if new ones have
|
||||
// been added or removed.
|
||||
if (-1 == mLength) {
|
||||
mLength = mDocument->GetNumberOfStyleSheets();
|
||||
}
|
||||
return mLength;
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
{
|
||||
if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
|
||||
aFound = false;
|
||||
return nullptr;
|
||||
}
|
||||
aFound = true;
|
||||
return mDocument->GetStyleSheetAt(aIndex);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
|
||||
{
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMStyleSheetList::StyleSheetAdded(StyleSheet* aStyleSheet,
|
||||
bool aDocumentSheet)
|
||||
{
|
||||
if (aDocumentSheet && -1 != mLength) {
|
||||
mLength++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMStyleSheetList::StyleSheetRemoved(StyleSheet* aStyleSheet,
|
||||
bool aDocumentSheet)
|
||||
{
|
||||
if (aDocumentSheet && -1 != mLength) {
|
||||
mLength--;
|
||||
}
|
||||
}
|
||||
|
||||
// nsOnloadBlocker implementation
|
||||
NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
|
||||
|
||||
|
@ -1200,10 +1127,10 @@ nsDOMStyleSheetSetList::EnsureFresh()
|
|||
// no document, for sure
|
||||
}
|
||||
|
||||
int32_t count = mDocument->GetNumberOfStyleSheets();
|
||||
size_t count = mDocument->SheetCount();
|
||||
nsAutoString title;
|
||||
for (int32_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = mDocument->GetStyleSheetAt(index);
|
||||
for (size_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = mDocument->SheetAt(index);
|
||||
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
||||
// XXXheycam ServoStyleSheets don't expose their title yet.
|
||||
if (sheet->IsServo()) {
|
||||
|
@ -1333,6 +1260,10 @@ nsIDocument::nsIDocument()
|
|||
{
|
||||
SetIsInDocument();
|
||||
|
||||
// Set this when document is created and value stays the same for the lifetime
|
||||
// of the document.
|
||||
mIsWebComponentsEnabled = nsContentUtils::IsWebComponentsEnabled();
|
||||
|
||||
PR_INIT_CLIST(&mDOMMediaQueryLists);
|
||||
}
|
||||
|
||||
|
@ -1452,11 +1383,11 @@ nsDocument::~nsDocument()
|
|||
|
||||
// Let the stylesheets know we're going away
|
||||
for (StyleSheet* sheet : mStyleSheets) {
|
||||
sheet->SetOwningDocument(nullptr);
|
||||
sheet->ClearAssociatedDocument();
|
||||
}
|
||||
for (auto& sheets : mAdditionalSheets) {
|
||||
for (StyleSheet* sheet : sheets) {
|
||||
sheet->SetOwningDocument(nullptr);
|
||||
sheet->ClearAssociatedDocument();
|
||||
}
|
||||
}
|
||||
if (mAttrStyleSheet) {
|
||||
|
@ -2113,7 +2044,7 @@ nsDocument::RemoveDocStyleSheetsFromStyleSets()
|
|||
{
|
||||
// The stylesheets should forget us
|
||||
for (StyleSheet* sheet : Reversed(mStyleSheets)) {
|
||||
sheet->SetOwningDocument(nullptr);
|
||||
sheet->ClearAssociatedDocument();
|
||||
|
||||
if (sheet->IsApplicable()) {
|
||||
nsCOMPtr<nsIPresShell> shell = GetShell();
|
||||
|
@ -2132,7 +2063,7 @@ nsDocument::RemoveStyleSheetsFromStyleSets(
|
|||
{
|
||||
// The stylesheets should forget us
|
||||
for (StyleSheet* sheet : Reversed(aSheets)) {
|
||||
sheet->SetOwningDocument(nullptr);
|
||||
sheet->ClearAssociatedDocument();
|
||||
|
||||
if (sheet->IsApplicable()) {
|
||||
nsCOMPtr<nsIPresShell> shell = GetShell();
|
||||
|
@ -2311,6 +2242,29 @@ WarnIfSandboxIneffective(nsIDocShell* aDocShell,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
|
||||
{
|
||||
if (!nsContentUtils::IsWebComponentsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, aObject);
|
||||
|
||||
JSAutoCompartment ac(aCx, obj);
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
|
||||
|
||||
nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
|
||||
if (doc && doc->IsStyledByServo()) {
|
||||
NS_WARNING("stylo: Web Components not supported yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
@ -3927,24 +3881,6 @@ nsDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
|
|||
NotifyStyleSheetAdded(aSheet, false);
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsDocument::GetNumberOfStyleSheets() const
|
||||
{
|
||||
return mStyleSheets.Length();
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
nsDocument::GetStyleSheetAt(int32_t aIndex) const
|
||||
{
|
||||
return mStyleSheets.SafeElementAt(aIndex, nullptr);
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsDocument::GetIndexOfStyleSheet(const StyleSheet* aSheet) const
|
||||
{
|
||||
return mStyleSheets.IndexOf(aSheet);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
|
||||
{
|
||||
|
@ -4007,7 +3943,7 @@ nsDocument::AddStyleSheet(StyleSheet* aSheet)
|
|||
{
|
||||
NS_PRECONDITION(aSheet, "null arg");
|
||||
mStyleSheets.AppendElement(aSheet);
|
||||
aSheet->SetOwningDocument(this);
|
||||
aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
|
||||
|
||||
if (aSheet->IsApplicable()) {
|
||||
AddStyleSheetToStyleSets(aSheet);
|
||||
|
@ -4044,7 +3980,7 @@ nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
|
|||
NotifyStyleSheetRemoved(aSheet, true);
|
||||
}
|
||||
|
||||
aSheet->SetOwningDocument(nullptr);
|
||||
aSheet->ClearAssociatedDocument();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4072,7 +4008,7 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
|
|||
StyleSheet* newSheet = aNewSheets[i];
|
||||
if (newSheet) {
|
||||
mStyleSheets.InsertElementAt(oldIndex, newSheet);
|
||||
newSheet->SetOwningDocument(this);
|
||||
newSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
|
||||
if (newSheet->IsApplicable()) {
|
||||
AddStyleSheetToStyleSets(newSheet);
|
||||
}
|
||||
|
@ -4085,13 +4021,13 @@ nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
|
|||
}
|
||||
|
||||
void
|
||||
nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
|
||||
nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
|
||||
{
|
||||
NS_PRECONDITION(aSheet, "null ptr");
|
||||
MOZ_ASSERT(aSheet);
|
||||
|
||||
mStyleSheets.InsertElementAt(aIndex, aSheet);
|
||||
|
||||
aSheet->SetOwningDocument(this);
|
||||
aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
|
||||
|
||||
if (aSheet->IsApplicable()) {
|
||||
AddStyleSheetToStyleSets(aSheet);
|
||||
|
@ -4216,7 +4152,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
|
|||
nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
sheet->SetOwningDocument(this);
|
||||
sheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
|
||||
MOZ_ASSERT(sheet->IsApplicable());
|
||||
|
||||
return AddAdditionalStyleSheet(aType, sheet);
|
||||
|
@ -4274,7 +4210,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
|
|||
NotifyStyleSheetRemoved(sheetRef, false);
|
||||
EndUpdate(UPDATE_STYLE);
|
||||
|
||||
sheetRef->SetOwningDocument(nullptr);
|
||||
sheetRef->ClearAssociatedDocument();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5353,29 +5289,18 @@ bool IsLowercaseASCII(const nsAString& aValue)
|
|||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
nsDocument::GetCustomElementRegistry()
|
||||
// We only support pseudo-elements with two colons in this function.
|
||||
static CSSPseudoElementType
|
||||
GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoString contentType;
|
||||
GetContentType(contentType);
|
||||
if (!IsHTMLDocument() &&
|
||||
!contentType.EqualsLiteral("application/xhtml+xml")) {
|
||||
return nullptr;
|
||||
MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
|
||||
if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(
|
||||
do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
|
||||
: GetScopeObject()));
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CustomElementRegistry> registry = window->CustomElements();
|
||||
if (!registry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return registry.forget();
|
||||
nsCOMPtr<nsIAtom> pseudo = NS_Atomize(Substring(aString, 1));
|
||||
return nsCSSPseudoElements::GetPseudoType(pseudo,
|
||||
nsCSSProps::EnabledState::eInUASheets);
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
|
@ -5395,10 +5320,36 @@ nsDocument::CreateElement(const nsAString& aTagName,
|
|||
}
|
||||
|
||||
const nsString* is = nullptr;
|
||||
CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
|
||||
if (aOptions.IsElementCreationOptions()) {
|
||||
const ElementCreationOptions& options =
|
||||
aOptions.GetAsElementCreationOptions();
|
||||
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||
options.mIs.WasPassed()) {
|
||||
is = &options.mIs.Value();
|
||||
}
|
||||
|
||||
// Check 'pseudo' and throw an exception if it's not one allowed
|
||||
// with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC.
|
||||
if (options.mPseudo.WasPassed()) {
|
||||
pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv);
|
||||
if (rv.Failed() ||
|
||||
pseudoType == CSSPseudoElementType::NotPseudo ||
|
||||
!nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Element> elem = CreateElem(
|
||||
needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
|
||||
|
||||
if (pseudoType != CSSPseudoElementType::NotPseudo) {
|
||||
elem->SetPseudoElementType(pseudoType);
|
||||
}
|
||||
|
||||
if (is) {
|
||||
elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
|
||||
}
|
||||
|
@ -5413,8 +5364,8 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
|||
{
|
||||
*aReturn = nullptr;
|
||||
ElementCreationOptionsOrString options;
|
||||
options.SetAsString();
|
||||
|
||||
options.SetAsString();
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<Element> element =
|
||||
CreateElementNS(aNamespaceURI, aQualifiedName, options, rv);
|
||||
|
@ -5439,6 +5390,13 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
|||
}
|
||||
|
||||
const nsString* is = nullptr;
|
||||
if (CustomElementRegistry::IsCustomElementEnabled() &&
|
||||
aOptions.IsElementCreationOptions()) {
|
||||
const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions();
|
||||
if (options.mIs.WasPassed()) {
|
||||
is = &options.mIs.Value();
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> element;
|
||||
rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
|
||||
|
@ -5647,278 +5605,9 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
|
|||
}
|
||||
|
||||
bool
|
||||
nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
||||
nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
JS_GetGlobalForObject(aCx, &args.callee()));
|
||||
RefPtr<nsGlobalWindow> window;
|
||||
UNWRAP_OBJECT(Window, global, window);
|
||||
MOZ_ASSERT(window, "Should have a non-null window");
|
||||
|
||||
nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
|
||||
|
||||
// Function name is the type of the custom element.
|
||||
JSString* jsFunName =
|
||||
JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
|
||||
nsAutoJSString elemName;
|
||||
if (!elemName.init(aCx, jsFunName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::CustomElementRegistry> registry = window->CustomElements();
|
||||
if (!registry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
|
||||
CustomElementDefinition* definition =
|
||||
registry->mCustomDefinitions.GetWeak(typeAtom);
|
||||
if (!definition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Element> element;
|
||||
|
||||
// We integrate with construction stack and do prototype swizzling here, so
|
||||
// that old upgrade behavior could also share the new upgrade steps.
|
||||
// And this old upgrade will be remove at some point (when everything is
|
||||
// switched to latest custom element spec).
|
||||
nsTArray<RefPtr<nsGenericHTMLElement>>& constructionStack =
|
||||
definition->mConstructionStack;
|
||||
if (constructionStack.Length()) {
|
||||
element = constructionStack.LastElement();
|
||||
NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false);
|
||||
|
||||
// Do prototype swizzling if dom reflector exists.
|
||||
JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
|
||||
if (reflector) {
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype);
|
||||
if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) {
|
||||
ac.emplace(aCx, reflector);
|
||||
if (!JS_WrapObject(aCx, &prototype) ||
|
||||
!JS_SetPrototype(aCx, reflector, prototype)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// We want to set the custom prototype in the compartment where it was
|
||||
// registered. We store the prototype from define() without unwrapped,
|
||||
// hence the prototype's compartment is the compartment where it was
|
||||
// registered.
|
||||
// In the case that |reflector| and |prototype| are in different
|
||||
// compartments, this will set the prototype on the |reflector|'s wrapper
|
||||
// and thus only visible in the wrapper's compartment, since we know
|
||||
// reflector's principal does not subsume prototype's in this case.
|
||||
ac.emplace(aCx, prototype);
|
||||
if (!JS_WrapObject(aCx, &reflector) ||
|
||||
!JS_SetPrototype(aCx, reflector, prototype)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap into current context.
|
||||
if (!JS_WrapObject(aCx, &reflector)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*reflector);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
nsDependentAtomString localName(definition->mLocalName);
|
||||
element =
|
||||
document->CreateElem(localName, nullptr, kNameSpaceID_XHTML,
|
||||
(definition->mLocalName != typeAtom) ? &elemName
|
||||
: nullptr);
|
||||
NS_ENSURE_TRUE(element, false);
|
||||
}
|
||||
|
||||
// The prototype setup happens in Element::WrapObject().
|
||||
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
|
||||
{
|
||||
JS::Rooted<JSObject*> obj(aCx, aObject);
|
||||
|
||||
if (nsContentUtils::IsWebComponentsEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for the webcomponents permission. See Bug 1181555.
|
||||
JSAutoCompartment ac(aCx, obj);
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
|
||||
|
||||
return IsWebComponentsEnabled(window);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
|
||||
{
|
||||
if (nsContentUtils::IsWebComponentsEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsIDocument* doc = aNodeInfo->GetDocument();
|
||||
// Use GetScopeObject() here so that data documents work the same way as the
|
||||
// main document they're associated with.
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
do_QueryInterface(doc->GetScopeObject());
|
||||
return IsWebComponentsEnabled(window);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
if (aWindow) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
uint32_t perm;
|
||||
rv = permMgr->TestPermissionFromWindow(
|
||||
aWindow, "moz-extremely-unstable-and-will-change-webcomponents", &perm);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return perm == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
const ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry());
|
||||
if (!registry) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(),
|
||||
aCx);
|
||||
// Unconditionally convert TYPE to lowercase.
|
||||
nsAutoString lcType;
|
||||
nsContentUtils::ASCIIToLower(aType, lcType);
|
||||
|
||||
nsIGlobalObject* sgo = GetScopeObject();
|
||||
if (!sgo) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> protoObject(aCx);
|
||||
|
||||
if (!aOptions.mPrototype) {
|
||||
JS::Rooted<JSObject*> htmlProto(aCx);
|
||||
htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
|
||||
if (!htmlProto) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
|
||||
if (!protoObject) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
protoObject = aOptions.mPrototype;
|
||||
|
||||
// Get the unwrapped prototype to do some checks.
|
||||
JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
|
||||
if (!protoObjectUnwrapped) {
|
||||
// If the caller's compartment does not have permission to access the
|
||||
// unwrapped prototype then throw.
|
||||
rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// If PROTOTYPE is already an interface prototype object for any interface
|
||||
// object or PROTOTYPE has a non-configurable property named constructor,
|
||||
// throw a NotSupportedError and stop.
|
||||
const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
|
||||
if (IsDOMIfaceAndProtoClass(clasp)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
|
||||
// This check may go through a wrapper, but as we checked above
|
||||
// it should be transparent or an xray. This should be fine for now,
|
||||
// until the spec is sorted out.
|
||||
if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!desc.configurable()) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSFunction*> constructor(aCx);
|
||||
{
|
||||
// Go into the document's global compartment when creating the constructor
|
||||
// function because we want to get the correct document (where the
|
||||
// definition is registered) when it is called.
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
// Create constructor to return. Store the name of the custom element as the
|
||||
// name of the function.
|
||||
constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
|
||||
JSFUN_CONSTRUCTOR,
|
||||
NS_ConvertUTF16toUTF8(lcType).get());
|
||||
if (!constructor) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> wrappedConstructor(aCx);
|
||||
wrappedConstructor = JS_GetFunctionObject(constructor);
|
||||
if (!JS_WrapObject(aCx, &wrappedConstructor)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ElementDefinitionOptions options;
|
||||
if (!aOptions.mExtends.IsVoid()) {
|
||||
// Only convert NAME to lowercase in HTML documents.
|
||||
nsAutoString lcName;
|
||||
IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
|
||||
: lcName.Assign(aOptions.mExtends);
|
||||
|
||||
options.mExtends.Construct(lcName);
|
||||
}
|
||||
|
||||
RootedCallback<OwningNonNull<binding_detail::FastFunction>> functionConstructor(aCx);
|
||||
functionConstructor = new binding_detail::FastFunction(aCx, wrappedConstructor, sgo);
|
||||
|
||||
registry->Define(lcType, functionConstructor, options, rv);
|
||||
|
||||
aRetval.set(wrappedConstructor);
|
||||
return aNode->OwnerDoc()->IsWebComponentsEnabled();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -6006,15 +5695,6 @@ nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
StyleSheetList*
|
||||
nsDocument::StyleSheets()
|
||||
{
|
||||
if (!mDOMStyleSheets) {
|
||||
mDOMStyleSheets = new nsDOMStyleSheetList(this);
|
||||
}
|
||||
return mDOMStyleSheets;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet)
|
||||
{
|
||||
|
@ -6028,10 +5708,10 @@ nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
|
|||
aSheetSet.Truncate();
|
||||
|
||||
// Look through our sheets, find the selected set title
|
||||
int32_t count = GetNumberOfStyleSheets();
|
||||
size_t count = SheetCount();
|
||||
nsAutoString title;
|
||||
for (int32_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = GetStyleSheetAt(index);
|
||||
for (size_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = SheetAt(index);
|
||||
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
||||
|
||||
// XXXheycam Make this work with ServoStyleSheets.
|
||||
|
@ -6148,10 +5828,10 @@ nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
|
|||
bool aUpdateCSSLoader)
|
||||
{
|
||||
BeginUpdate(UPDATE_STYLE);
|
||||
int32_t count = GetNumberOfStyleSheets();
|
||||
size_t count = SheetCount();
|
||||
nsAutoString title;
|
||||
for (int32_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = GetStyleSheetAt(index);
|
||||
for (size_t index = 0; index < count; index++) {
|
||||
StyleSheet* sheet = SheetAt(index);
|
||||
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
||||
|
||||
// XXXheycam Make this work with ServoStyleSheets.
|
||||
|
@ -6421,7 +6101,7 @@ already_AddRefed<nsRange>
|
|||
nsIDocument::CreateRange(ErrorResult& rv)
|
||||
{
|
||||
RefPtr<nsRange> range = new nsRange(this);
|
||||
nsresult res = range->Set(this, 0, this, 0);
|
||||
nsresult res = range->CollapseTo(this, 0);
|
||||
if (NS_FAILED(res)) {
|
||||
rv.Throw(res);
|
||||
return nullptr;
|
||||
|
@ -7712,7 +7392,7 @@ nsDocument::GetExistingListenerManager() const
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
// FIXME! This is a hack to make middle mouse paste working also in Editor.
|
||||
|
@ -7722,8 +7402,8 @@ nsDocument::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
// Load events must not propagate to |window| object, see bug 335251.
|
||||
if (aVisitor.mEvent->mMessage != eLoad) {
|
||||
nsGlobalWindow* window = nsGlobalWindow::Cast(GetWindow());
|
||||
aVisitor.mParentTarget =
|
||||
window ? window->GetTargetForEventTargetChain() : nullptr;
|
||||
aVisitor.SetParentTarget(
|
||||
window ? window->GetTargetForEventTargetChain() : nullptr, false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9859,9 +9539,9 @@ nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
|
|||
|
||||
clonedDoc->mOriginalDocument->mStaticCloneCount++;
|
||||
|
||||
int32_t sheetsCount = GetNumberOfStyleSheets();
|
||||
for (int32_t i = 0; i < sheetsCount; ++i) {
|
||||
RefPtr<StyleSheet> sheet = GetStyleSheetAt(i);
|
||||
size_t sheetsCount = SheetCount();
|
||||
for (size_t i = 0; i < sheetsCount; ++i) {
|
||||
RefPtr<StyleSheet> sheet = SheetAt(i);
|
||||
if (sheet) {
|
||||
if (sheet->IsApplicable()) {
|
||||
// XXXheycam Need to make ServoStyleSheet cloning work.
|
||||
|
@ -12079,7 +11759,7 @@ SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
|
|||
size_t n = 0;
|
||||
n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (StyleSheet* sheet : aSheets) {
|
||||
if (!sheet->GetOwningDocument()) {
|
||||
if (!sheet->GetAssociatedDocument()) {
|
||||
// Avoid over-reporting shared sheets.
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -293,36 +293,6 @@ public:
|
|||
nsDocHeaderData* mNext;
|
||||
};
|
||||
|
||||
class nsDOMStyleSheetList : public mozilla::dom::StyleSheetList,
|
||||
public nsStubDocumentObserver
|
||||
{
|
||||
public:
|
||||
explicit nsDOMStyleSheetList(nsIDocument* aDocument);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// nsIDocumentObserver
|
||||
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
|
||||
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
|
||||
|
||||
// nsIMutationObserver
|
||||
NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
|
||||
|
||||
virtual nsINode* GetParentObject() const override
|
||||
{
|
||||
return mDocument;
|
||||
}
|
||||
|
||||
uint32_t Length() override;
|
||||
mozilla::StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
|
||||
|
||||
protected:
|
||||
virtual ~nsDOMStyleSheetList();
|
||||
|
||||
int32_t mLength;
|
||||
nsIDocument* mDocument;
|
||||
};
|
||||
|
||||
class nsOnloadBlocker final : public nsIRequest
|
||||
{
|
||||
public:
|
||||
|
@ -624,14 +594,6 @@ public:
|
|||
|
||||
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) override;
|
||||
|
||||
/**
|
||||
* Get the (document) style sheets owned by this document.
|
||||
* These are ordered, highest priority last
|
||||
*/
|
||||
virtual int32_t GetNumberOfStyleSheets() const override;
|
||||
virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
|
||||
virtual int32_t GetIndexOfStyleSheet(
|
||||
const mozilla::StyleSheet* aSheet) const override;
|
||||
virtual void AddStyleSheet(mozilla::StyleSheet* aSheet) override;
|
||||
virtual void RemoveStyleSheet(mozilla::StyleSheet* aSheet) override;
|
||||
|
||||
|
@ -642,7 +604,7 @@ public:
|
|||
virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
|
||||
|
||||
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
|
||||
int32_t aIndex) override;
|
||||
size_t aIndex) override;
|
||||
virtual void SetStyleSheetApplicableState(mozilla::StyleSheet* aSheet,
|
||||
bool aApplicable) override;
|
||||
|
||||
|
@ -793,7 +755,11 @@ public:
|
|||
|
||||
virtual void NotifyLayerManagerRecreated() override;
|
||||
|
||||
|
||||
// Check whether web components are enabled for the global of aObject.
|
||||
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
|
||||
// Check whether web components are enabled for the document this node belongs
|
||||
// to.
|
||||
static bool IsWebComponentsEnabled(const nsINode* aNode);
|
||||
private:
|
||||
void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
|
||||
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
|
||||
|
@ -810,7 +776,7 @@ public:
|
|||
NS_DECL_NSIDOMDOCUMENTXBL
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
virtual mozilla::EventListenerManager*
|
||||
GetOrCreateListenerManager() override;
|
||||
|
@ -1129,12 +1095,7 @@ public:
|
|||
// WebIDL bits
|
||||
virtual mozilla::dom::DOMImplementation*
|
||||
GetImplementation(mozilla::ErrorResult& rv) override;
|
||||
virtual void
|
||||
RegisterElement(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
mozilla::ErrorResult& rv) override;
|
||||
virtual mozilla::dom::StyleSheetList* StyleSheets() override;
|
||||
|
||||
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
|
||||
virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
|
||||
virtual mozilla::dom::DOMStringList* StyleSheetSets() override;
|
||||
|
@ -1356,7 +1317,6 @@ protected:
|
|||
// EndLoad() has already happened.
|
||||
nsWeakPtr mWeakSink;
|
||||
|
||||
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
|
||||
nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
|
||||
nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
|
||||
|
||||
|
@ -1385,23 +1345,8 @@ protected:
|
|||
// non-null when this document is in fullscreen mode.
|
||||
nsWeakPtr mFullscreenRoot;
|
||||
|
||||
private:
|
||||
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
|
||||
|
||||
public:
|
||||
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
GetCustomElementRegistry() override;
|
||||
|
||||
// Check whether web components are enabled for the global of aObject.
|
||||
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
|
||||
// Check whether web components are enabled for the global of the document
|
||||
// this nodeinfo comes from.
|
||||
static bool IsWebComponentsEnabled(mozilla::dom::NodeInfo* aNodeInfo);
|
||||
// Check whether web components are enabled for the given window.
|
||||
static bool IsWebComponentsEnabled(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
RefPtr<mozilla::EventListenerManager> mListenerManager;
|
||||
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
|
||||
RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
|
||||
RefPtr<nsScriptLoader> mScriptLoader;
|
||||
nsDocHeaderData* mHeaderData;
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "nsIDOMDocument.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
@ -40,6 +39,7 @@
|
|||
#include "nsISelectionPrivate.h"
|
||||
#include "nsITransferable.h" // for kUnicodeMime
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsElementTable.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
@ -1588,10 +1588,13 @@ nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
|
|||
nsresult
|
||||
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
||||
{
|
||||
if (!inRange) return NS_ERROR_NULL_POINTER;
|
||||
RefPtr<nsRange> range = static_cast<nsRange*>(inRange);
|
||||
if (!range) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
|
||||
int32_t startOffset, endOffset;
|
||||
uint32_t startOffset, endOffset;
|
||||
|
||||
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1609,9 +1612,11 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
|||
int32_t opStartOffset, opEndOffset;
|
||||
|
||||
// examine range endpoints.
|
||||
rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
|
||||
rv = GetPromotedPoint(kStart, startNode, static_cast<int32_t>(startOffset),
|
||||
address_of(opStartNode), &opStartOffset, common);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
|
||||
rv = GetPromotedPoint(kEnd, endNode, static_cast<int32_t>(endOffset),
|
||||
address_of(opEndNode), &opEndOffset, common);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
|
||||
|
@ -1623,9 +1628,9 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
|
|||
}
|
||||
|
||||
// set the range to the new values
|
||||
rv = inRange->SetStart(opStartNode, opStartOffset);
|
||||
rv = inRange->SetStart(opStartNode, static_cast<uint32_t>(opStartOffset));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = inRange->SetEnd(opEndNode, opEndOffset);
|
||||
rv = inRange->SetEnd(opEndNode, static_cast<uint32_t>(opEndOffset));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1736,9 +1741,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
|||
rv = GetNodeLocation(node, address_of(parent), &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
nsIParserService *parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
while ((IsFirstNode(node)) && (!IsRoot(parent)) && (parent != common))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
|
@ -1746,11 +1748,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
|||
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
|
||||
if (content && content->IsHTMLElement())
|
||||
{
|
||||
bool isBlock = false;
|
||||
parserService->IsBlock(parserService->HTMLAtomTagToId(
|
||||
content->NodeInfo()->NameAtom()), isBlock);
|
||||
if (isBlock)
|
||||
{
|
||||
if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
|
||||
content->NodeInfo()->NameAtom()))) {
|
||||
bResetPromotion = false;
|
||||
}
|
||||
}
|
||||
|
@ -1819,9 +1818,6 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
|||
rv = GetNodeLocation(node, address_of(parent), &offset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == -1) return NS_OK; // we hit generated content; STOP
|
||||
nsIParserService *parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
while ((IsLastNode(node)) && (!IsRoot(parent)) && (parent != common))
|
||||
{
|
||||
if (bResetPromotion)
|
||||
|
@ -1829,11 +1825,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
|
|||
nsCOMPtr<nsIContent> content = do_QueryInterface(parent);
|
||||
if (content && content->IsHTMLElement())
|
||||
{
|
||||
bool isBlock = false;
|
||||
parserService->IsBlock(parserService->HTMLAtomTagToId(
|
||||
content->NodeInfo()->NameAtom()), isBlock);
|
||||
if (isBlock)
|
||||
{
|
||||
if (nsHTMLElement::IsBlock(nsHTMLTags::AtomTagToId(
|
||||
content->NodeInfo()->NameAtom()))) {
|
||||
bResetPromotion = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2457,7 +2457,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
|
|||
nsCOMPtr<nsIDOMNode> startNode, endNode;
|
||||
bool isCollapsed = false;
|
||||
nsCOMPtr<nsIContent> startContent, endContent;
|
||||
int32_t startOffset = 0;
|
||||
uint32_t startOffset = 0;
|
||||
if (domSelection) {
|
||||
domSelection->GetIsCollapsed(&isCollapsed);
|
||||
nsCOMPtr<nsIDOMRange> domRange;
|
||||
|
@ -2471,7 +2471,6 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
|
|||
|
||||
startContent = do_QueryInterface(startNode);
|
||||
if (startContent && startContent->IsElement()) {
|
||||
NS_ASSERTION(startOffset >= 0, "Start offset cannot be negative");
|
||||
childContent = startContent->GetChildAt(startOffset);
|
||||
if (childContent) {
|
||||
startContent = childContent;
|
||||
|
@ -2480,9 +2479,8 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
|
|||
|
||||
endContent = do_QueryInterface(endNode);
|
||||
if (endContent && endContent->IsElement()) {
|
||||
int32_t endOffset = 0;
|
||||
uint32_t endOffset = 0;
|
||||
domRange->GetEndOffset(&endOffset);
|
||||
NS_ASSERTION(endOffset >= 0, "End offset cannot be negative");
|
||||
childContent = endContent->GetChildAt(endOffset);
|
||||
if (childContent) {
|
||||
endContent = childContent;
|
||||
|
@ -2510,7 +2508,7 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
|
|||
bool isFormControl =
|
||||
startContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL);
|
||||
|
||||
if (nodeValue.Length() == (uint32_t)startOffset && !isFormControl &&
|
||||
if (nodeValue.Length() == startOffset && !isFormControl &&
|
||||
startContent != aDocument->GetRootElement()) {
|
||||
// Yes, indeed we were at the end of the last node
|
||||
nsCOMPtr<nsIFrameEnumerator> frameTraversal;
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "nsGlobalWindow.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsView.h"
|
||||
#include "GroupedSHistory.h"
|
||||
#include "PartialSHistory.h"
|
||||
|
@ -936,6 +937,8 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
|
|||
RefPtr<nsPresContext> presContext;
|
||||
mDocShell->GetPresContext(getter_AddRefs(presContext));
|
||||
if (presContext)
|
||||
// rebuild, because now the same nsMappedAttributes* will produce
|
||||
// a different style
|
||||
presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
virtual EventStates IntrinsicState() const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override
|
||||
virtual nsresult GetEventTargetParent(EventChainPreVisitor& aVisitor) override
|
||||
{
|
||||
MOZ_ASSERT(IsInNativeAnonymousSubtree());
|
||||
if (aVisitor.mEvent->mMessage == eLoad ||
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
// Don't propagate the events to the parent.
|
||||
return NS_OK;
|
||||
}
|
||||
return nsXMLElement::PreHandleEvent(aVisitor);
|
||||
return nsXMLElement::GetEventTargetParent(aVisitor);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
|
@ -736,21 +737,18 @@ nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot)
|
|||
{
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>&
|
||||
nsGenericDOMDataNode::DestInsertionPoints()
|
||||
{
|
||||
nsDataSlots *slots = DataSlots();
|
||||
return slots->mDestInsertionPoints;
|
||||
}
|
||||
|
||||
nsTArray<nsIContent*>*
|
||||
nsGenericDOMDataNode::GetExistingDestInsertionPoints() const
|
||||
HTMLSlotElement*
|
||||
nsGenericDOMDataNode::GetAssignedSlot() const
|
||||
{
|
||||
nsDataSlots *slots = GetExistingDataSlots();
|
||||
if (slots) {
|
||||
return &slots->mDestInsertionPoints;
|
||||
}
|
||||
return nullptr;
|
||||
return slots ? slots->mAssignedSlot.get() : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericDOMDataNode::SetAssignedSlot(HTMLSlotElement* aSlot)
|
||||
{
|
||||
nsDataSlots *slots = DataSlots();
|
||||
slots->mAssignedSlot = aSlot;
|
||||
}
|
||||
|
||||
nsXBLBinding *
|
||||
|
@ -843,6 +841,9 @@ nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &
|
|||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mAssignedSlot");
|
||||
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mAssignedSlot.get()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -850,6 +851,7 @@ nsGenericDOMDataNode::nsDataSlots::Unlink()
|
|||
{
|
||||
mXBLInsertionParent = nullptr;
|
||||
mContainingShadow = nullptr;
|
||||
mAssignedSlot = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
class nsIDocument;
|
||||
class nsIDOMText;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class HTMLSlotElement;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
|
||||
|
||||
// Data node specific flags
|
||||
|
@ -154,9 +160,9 @@ public:
|
|||
virtual void SetXBLBinding(nsXBLBinding* aBinding,
|
||||
nsBindingManager* aOldBindingManager = nullptr) override;
|
||||
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const override;
|
||||
virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
|
||||
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
|
||||
virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
|
||||
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const override;
|
||||
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) override;
|
||||
virtual nsIContent *GetXBLInsertionParent() const override;
|
||||
virtual void SetXBLInsertionParent(nsIContent* aContent) override;
|
||||
virtual bool IsNodeOfType(uint32_t aFlags) const override;
|
||||
|
@ -261,9 +267,9 @@ protected:
|
|||
RefPtr<mozilla::dom::ShadowRoot> mContainingShadow;
|
||||
|
||||
/**
|
||||
* @see nsIContent::GetDestInsertionPoints
|
||||
* @see nsIContent::GetAssignedSlot
|
||||
*/
|
||||
nsTArray<nsIContent*> mDestInsertionPoints;
|
||||
RefPtr<mozilla::dom::HTMLSlotElement> mAssignedSlot;
|
||||
};
|
||||
|
||||
// Override from nsINode
|
||||
|
|
|
@ -1560,11 +1560,11 @@ GK_ATOM(saturate, "saturate")
|
|||
GK_ATOM(saturation, "saturation")
|
||||
GK_ATOM(set, "set")
|
||||
GK_ATOM(seed, "seed")
|
||||
GK_ATOM(shadow, "shadow")
|
||||
GK_ATOM(shape_rendering, "shape-rendering")
|
||||
GK_ATOM(skewX, "skewX")
|
||||
GK_ATOM(skewY, "skewY")
|
||||
GK_ATOM(slope, "slope")
|
||||
GK_ATOM(slot, "slot")
|
||||
GK_ATOM(softLight, "soft-light")
|
||||
GK_ATOM(spacing, "spacing")
|
||||
GK_ATOM(spacingAndGlyphs, "spacingAndGlyphs")
|
||||
|
@ -2144,12 +2144,14 @@ GK_ATOM(ongamepaddisconnected, "ongamepaddisconnected")
|
|||
#endif
|
||||
|
||||
// Content property names
|
||||
GK_ATOM(afterPseudoProperty, "afterPseudoProperty") // nsXMLElement*
|
||||
GK_ATOM(animationsProperty, "AnimationsProperty") // FrameAnimations*
|
||||
GK_ATOM(animationsOfBeforeProperty, "AnimationsOfBeforeProperty") // FrameAnimations*
|
||||
GK_ATOM(animationsOfAfterProperty, "AnimationsOfAfterProperty") // FrameAnimations*
|
||||
GK_ATOM(animationEffectsProperty, "AnimationEffectsProperty") // EffectSet*
|
||||
GK_ATOM(animationEffectsForBeforeProperty, "AnimationsEffectsForBeforeProperty") // EffectSet*
|
||||
GK_ATOM(animationEffectsForAfterProperty, "AnimationsEffectsForAfterProperty") // EffectSet*
|
||||
GK_ATOM(beforePseudoProperty, "beforePseudoProperty") // nsXMLElement*
|
||||
GK_ATOM(cssPseudoElementBeforeProperty, "CSSPseudoElementBeforeProperty") // CSSPseudoElement*
|
||||
GK_ATOM(cssPseudoElementAfterProperty, "CSSPseudoElementAfterProperty") // CSSPseudoElement*
|
||||
GK_ATOM(transitionsProperty, "TransitionsProperty") // FrameTransitions*
|
||||
|
@ -2162,6 +2164,7 @@ GK_ATOM(lockedStyleStates, "lockedStyleStates")
|
|||
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
|
||||
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
|
||||
GK_ATOM(paintRequestTime, "PaintRequestTime")
|
||||
GK_ATOM(pseudoProperty, "PseudoProperty") // CSSPseudoElementType
|
||||
|
||||
// Languages for lang-specific transforms
|
||||
GK_ATOM(Japanese, "ja")
|
||||
|
|
|
@ -3577,9 +3577,10 @@ nsGlobalWindow::WillHandleEvent(EventChainPostVisitor& aVisitor)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsGlobalWindow::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?");
|
||||
NS_PRECONDITION(IsInnerWindow(),
|
||||
"GetEventTargetParent is used on outer window!?");
|
||||
EventMessage msg = aVisitor.mEvent->mMessage;
|
||||
|
||||
aVisitor.mCanHandle = true;
|
||||
|
@ -3607,7 +3608,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
}
|
||||
}
|
||||
|
||||
aVisitor.mParentTarget = GetParentTarget();
|
||||
aVisitor.SetParentTarget(GetParentTarget(), true);
|
||||
|
||||
// Handle 'active' event.
|
||||
if (!mIdleObservers.IsEmpty() &&
|
||||
|
@ -3812,7 +3813,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
|||
} else if (aVisitor.mEvent->mMessage == eLoad &&
|
||||
aVisitor.mEvent->IsTrusted()) {
|
||||
// This is page load event since load events don't propagate to |window|.
|
||||
// @see nsDocument::PreHandleEvent.
|
||||
// @see nsDocument::GetEventTargetParent.
|
||||
mIsDocumentLoaded = true;
|
||||
|
||||
nsCOMPtr<Element> element = GetOuterWindow()->GetFrameElementInternal();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsIDOMElement.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsElementTable.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
@ -347,20 +348,13 @@ nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
|
|||
}
|
||||
|
||||
if (ns == kNameSpaceID_XHTML) {
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
if (parserService) {
|
||||
bool isContainer;
|
||||
|
||||
parserService->
|
||||
IsContainer(parserService->HTMLCaseSensitiveAtomTagToId(name),
|
||||
isContainer);
|
||||
if (!isContainer) {
|
||||
// Keep this in sync with the cleanup at the end of this method.
|
||||
MOZ_ASSERT(name != nsGkAtoms::body);
|
||||
MaybeLeaveFromPreContent(content);
|
||||
return NS_OK;
|
||||
}
|
||||
bool isContainer =
|
||||
nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(name));
|
||||
if (!isContainer) {
|
||||
// Keep this in sync with the cleanup at the end of this method.
|
||||
MOZ_ASSERT(name != nsGkAtoms::body);
|
||||
MaybeLeaveFromPreContent(content);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace mozilla {
|
|||
class EventChainPreVisitor;
|
||||
namespace dom {
|
||||
class ShadowRoot;
|
||||
class HTMLSlotElement;
|
||||
} // namespace dom
|
||||
namespace widget {
|
||||
struct IMEState;
|
||||
|
@ -144,7 +145,14 @@ public:
|
|||
* Skip native anonymous content created for placeholder of HTML input,
|
||||
* used in conjunction with eAllChildren or eAllButXBL.
|
||||
*/
|
||||
eSkipPlaceholderContent = 2
|
||||
eSkipPlaceholderContent = 2,
|
||||
|
||||
/**
|
||||
* Skip native anonymous content created by ancestor frames of the root
|
||||
* element's primary frame, such as scrollbar elements created by the root
|
||||
* scroll frame.
|
||||
*/
|
||||
eSkipDocumentLevelNativeAnonymousContent = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -186,7 +194,7 @@ public:
|
|||
void SetIsNativeAnonymousRoot()
|
||||
{
|
||||
SetFlags(NODE_IS_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
|
||||
NODE_IS_NATIVE_ANONYMOUS_ROOT);
|
||||
NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_NATIVE_ANONYMOUS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -689,18 +697,27 @@ public:
|
|||
virtual mozilla::dom::ShadowRoot *GetContainingShadow() const = 0;
|
||||
|
||||
/**
|
||||
* Gets an array of destination insertion points where this content
|
||||
* is distributed by web component distribution algorithms.
|
||||
* The array is created if it does not already exist.
|
||||
* Gets the assigned slot associated with this content.
|
||||
*
|
||||
* @return The assigned slot element or null.
|
||||
*/
|
||||
virtual nsTArray<nsIContent*> &DestInsertionPoints() = 0;
|
||||
virtual mozilla::dom::HTMLSlotElement* GetAssignedSlot() const = 0;
|
||||
|
||||
/**
|
||||
* Same as DestInsertionPoints except that this method will return
|
||||
* null if the array of destination insertion points does not already
|
||||
* exist.
|
||||
* Sets the assigned slot associated with this content.
|
||||
*
|
||||
* @param aSlot The assigned slot.
|
||||
*/
|
||||
virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const = 0;
|
||||
virtual void SetAssignedSlot(mozilla::dom::HTMLSlotElement* aSlot) = 0;
|
||||
|
||||
/**
|
||||
* Gets the assigned slot associated with this content based on parent's
|
||||
* shadow root mode. Returns null if parent's shadow root is "closed".
|
||||
* https://dom.spec.whatwg.org/#dom-slotable-assignedslot
|
||||
*
|
||||
* @return The assigned slot element or null.
|
||||
*/
|
||||
mozilla::dom::HTMLSlotElement* GetAssignedSlotByMode() const;
|
||||
|
||||
/**
|
||||
* Gets the insertion parent element of the XBL binding.
|
||||
|
@ -723,10 +740,9 @@ public:
|
|||
*/
|
||||
inline nsIContent *GetFlattenedTreeParent() const;
|
||||
|
||||
/**
|
||||
* Helper method, which we leave public so that it's accessible from nsINode.
|
||||
*/
|
||||
nsINode *GetFlattenedTreeParentNodeInternal() const;
|
||||
// Helper method, which we leave public so that it's accessible from nsINode.
|
||||
enum FlattenedParentType { eNotForStyle, eForStyle };
|
||||
nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
|
||||
|
||||
/**
|
||||
* API to check if this is a link that's traversed in response to user input
|
||||
|
@ -944,10 +960,18 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
// Returns true if this element is native-anonymous scrollbar content.
|
||||
bool IsNativeScrollbarContent() const {
|
||||
return IsNativeAnonymous() &&
|
||||
IsAnyOfXULElements(nsGkAtoms::scrollbar,
|
||||
nsGkAtoms::resizer,
|
||||
nsGkAtoms::scrollcorner);
|
||||
}
|
||||
|
||||
// Overloaded from nsINode
|
||||
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
|
||||
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
virtual bool IsPurple() = 0;
|
||||
|
@ -961,6 +985,12 @@ protected:
|
|||
*/
|
||||
nsIAtom* DoGetID() const;
|
||||
|
||||
/**
|
||||
* Returns the assigned slot, if it exists, or the direct parent, if it's a
|
||||
* fallback content of a slot.
|
||||
*/
|
||||
nsINode* GetFlattenedTreeParentForMaybeAssignedNode() const;
|
||||
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
|
@ -1014,7 +1044,15 @@ inline nsIContent* nsINode::AsContent()
|
|||
{ \
|
||||
return aContent->_check ? static_cast<_class*>(aContent) : nullptr; \
|
||||
} \
|
||||
static const _class* FromContent(const nsIContent* aContent) \
|
||||
{ \
|
||||
return aContent->_check ? static_cast<const _class*>(aContent) : nullptr; \
|
||||
} \
|
||||
static _class* FromContentOrNull(nsIContent* aContent) \
|
||||
{ \
|
||||
return aContent ? FromContent(aContent) : nullptr; \
|
||||
} \
|
||||
static const _class* FromContentOrNull(const nsIContent* aContent) \
|
||||
{ \
|
||||
return aContent ? FromContent(aContent) : nullptr; \
|
||||
}
|
||||
|
|
|
@ -33,14 +33,15 @@ inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const
|
|||
return AsElement()->FastGetShadowRoot();
|
||||
}
|
||||
|
||||
inline nsINode* nsINode::GetFlattenedTreeParentNode() const
|
||||
template<nsIContent::FlattenedParentType Type>
|
||||
static inline nsINode*
|
||||
GetFlattenedTreeParentNode(const nsINode* aNode)
|
||||
{
|
||||
nsINode* parent = GetParentNode();
|
||||
|
||||
nsINode* parent = aNode->GetParentNode();
|
||||
// Try to short-circuit past the complicated and not-exactly-fast logic for
|
||||
// computing the flattened parent.
|
||||
//
|
||||
// There are three cases where we need might something other than parentNode:
|
||||
// There are four cases where we need might something other than parentNode:
|
||||
// (1) The node is an explicit child of an XBL-bound element, re-bound
|
||||
// to an XBL insertion point.
|
||||
// (2) The node is a top-level element in a shadow tree, whose flattened
|
||||
|
@ -48,18 +49,31 @@ inline nsINode* nsINode::GetFlattenedTreeParentNode() const
|
|||
// is the shadow root).
|
||||
// (3) The node is an explicit child of an element with a shadow root,
|
||||
// re-bound to an insertion point.
|
||||
bool needSlowCall = HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
|
||||
IsInShadowTree() ||
|
||||
(parent && parent->IsContent() &&
|
||||
parent->AsContent()->GetShadowRoot());
|
||||
// (4) We want the flattened parent for style, and the node is the root
|
||||
// of a native anonymous content subtree parented to the document's
|
||||
// root element.
|
||||
bool needSlowCall = aNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
|
||||
aNode->IsInShadowTree() ||
|
||||
(parent &&
|
||||
parent->IsContent() &&
|
||||
parent->AsContent()->GetShadowRoot()) ||
|
||||
(Type == nsIContent::eForStyle &&
|
||||
aNode->IsContent() &&
|
||||
aNode->AsContent()->IsRootOfNativeAnonymousSubtree() &&
|
||||
aNode->OwnerDoc()->GetRootElement() == parent);
|
||||
if (MOZ_UNLIKELY(needSlowCall)) {
|
||||
MOZ_ASSERT(IsContent());
|
||||
return AsContent()->GetFlattenedTreeParentNodeInternal();
|
||||
MOZ_ASSERT(aNode->IsContent());
|
||||
return aNode->AsContent()->GetFlattenedTreeParentNodeInternal(Type);
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
inline nsINode*
|
||||
nsINode::GetFlattenedTreeParentNode() const
|
||||
{
|
||||
return ::GetFlattenedTreeParentNode<nsIContent::eNotForStyle>(this);
|
||||
}
|
||||
|
||||
inline nsIContent*
|
||||
nsIContent::GetFlattenedTreeParent() const
|
||||
{
|
||||
|
@ -67,5 +81,16 @@ nsIContent::GetFlattenedTreeParent() const
|
|||
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
|
||||
}
|
||||
|
||||
inline nsINode*
|
||||
nsINode::GetFlattenedTreeParentNodeForStyle() const
|
||||
{
|
||||
return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsINode::NodeOrAncestorHasDirAuto() const
|
||||
{
|
||||
return AncestorHasDirAuto() || (IsElement() && AsElement()->HasDirAuto());
|
||||
}
|
||||
|
||||
#endif // nsIContentInlines_h
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "prclist.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/dom/StyleScope.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
|
@ -133,7 +134,6 @@ class DOMIntersectionObserver;
|
|||
class DOMStringList;
|
||||
class Element;
|
||||
struct ElementCreationOptions;
|
||||
struct ElementRegistrationOptions;
|
||||
class Event;
|
||||
class EventTarget;
|
||||
class FontFaceSet;
|
||||
|
@ -197,7 +197,8 @@ class nsContentList;
|
|||
|
||||
// Document interface. This is implemented by all document objects in
|
||||
// Gecko.
|
||||
class nsIDocument : public nsINode
|
||||
class nsIDocument : public nsINode,
|
||||
public mozilla::dom::StyleScope
|
||||
{
|
||||
typedef mozilla::dom::GlobalObject GlobalObject;
|
||||
|
||||
|
@ -1070,40 +1071,24 @@ public:
|
|||
*/
|
||||
virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) = 0;
|
||||
|
||||
/**
|
||||
* Get the number of (document) stylesheets
|
||||
*
|
||||
* @return the number of stylesheets
|
||||
* @throws no exceptions
|
||||
*/
|
||||
virtual int32_t GetNumberOfStyleSheets() const = 0;
|
||||
nsINode& AsNode() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a particular stylesheet
|
||||
* @param aIndex the index the stylesheet lives at. This is zero-based
|
||||
* @return the stylesheet at aIndex. Null if aIndex is out of range.
|
||||
* @throws no exceptions
|
||||
*/
|
||||
virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
|
||||
mozilla::dom::StyleSheetList* StyleSheets()
|
||||
{
|
||||
return &StyleScope::EnsureDOMStyleSheets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a sheet at a particular spot in the stylesheet list (zero-based)
|
||||
* @param aSheet the sheet to insert
|
||||
* @param aIndex the index to insert at. This index will be
|
||||
* adjusted for the "special" sheets.
|
||||
* @param aIndex the index to insert at.
|
||||
* @throws no exceptions
|
||||
*/
|
||||
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
|
||||
int32_t aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Get the index of a particular stylesheet. This will _always_
|
||||
* consider the "special" sheets as part of the sheet list.
|
||||
* @param aSheet the sheet to get the index of
|
||||
* @return aIndex the index of the sheet in the full list
|
||||
*/
|
||||
virtual int32_t GetIndexOfStyleSheet(
|
||||
const mozilla::StyleSheet* aSheet) const = 0;
|
||||
size_t aIndex) = 0;
|
||||
|
||||
/**
|
||||
* Replace the stylesheets in aOldSheets with the stylesheets in
|
||||
|
@ -1154,11 +1139,13 @@ public:
|
|||
* sheets for this document, returns the index that aSheet should
|
||||
* be inserted at to maintain document ordering.
|
||||
*
|
||||
* Type T has to cast to StyleSheet*.
|
||||
*
|
||||
* Defined in nsIDocumentInlines.h.
|
||||
*/
|
||||
template<typename T>
|
||||
size_t FindDocStyleSheetInsertionPoint(const nsTArray<RefPtr<T>>& aDocSheets,
|
||||
T* aSheet);
|
||||
size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
|
||||
const mozilla::StyleSheet& aSheet);
|
||||
|
||||
/**
|
||||
* Get this document's CSSLoader. This is guaranteed to not return null.
|
||||
|
@ -2587,14 +2574,6 @@ public:
|
|||
|
||||
nsIDocument* GetTopLevelContentDocument();
|
||||
|
||||
virtual void
|
||||
RegisterElement(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
mozilla::ErrorResult& rv) = 0;
|
||||
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
GetCustomElementRegistry() = 0;
|
||||
|
||||
already_AddRefed<nsContentList>
|
||||
GetElementsByTagName(const nsAString& aTagName)
|
||||
{
|
||||
|
@ -2706,7 +2685,6 @@ public:
|
|||
return mVisibilityState;
|
||||
}
|
||||
#endif
|
||||
virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
|
||||
void GetSelectedStyleSheetSet(nsAString& aSheetSet);
|
||||
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
|
||||
virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
|
||||
|
@ -2894,6 +2872,11 @@ public:
|
|||
--mThrowOnDynamicMarkupInsertionCounter;
|
||||
}
|
||||
|
||||
bool IsWebComponentsEnabled() const
|
||||
{
|
||||
return mIsWebComponentsEnabled;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
|
@ -3037,6 +3020,9 @@ protected:
|
|||
// container for per-context fonts (downloadable, SVG, etc.)
|
||||
RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
|
||||
|
||||
// True if dom.webcomponents.enabled pref is set when document is created.
|
||||
bool mIsWebComponentsEnabled : 1;
|
||||
|
||||
// Compatibility mode
|
||||
nsCompatibility mCompatMode;
|
||||
|
||||
|
|
|
@ -19,24 +19,23 @@ nsIDocument::GetBodyElement()
|
|||
template<typename T>
|
||||
size_t
|
||||
nsIDocument::FindDocStyleSheetInsertionPoint(
|
||||
const nsTArray<RefPtr<T>>& aDocSheets,
|
||||
T* aSheet)
|
||||
const nsTArray<T>& aDocSheets,
|
||||
const mozilla::StyleSheet& aSheet)
|
||||
{
|
||||
nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
|
||||
|
||||
// lowest index first
|
||||
int32_t newDocIndex = GetIndexOfStyleSheet(aSheet);
|
||||
int32_t newDocIndex = IndexOfSheet(aSheet);
|
||||
|
||||
int32_t count = aDocSheets.Length();
|
||||
int32_t index;
|
||||
for (index = 0; index < count; index++) {
|
||||
T* sheet = aDocSheets[index];
|
||||
int32_t sheetDocIndex = GetIndexOfStyleSheet(sheet);
|
||||
size_t count = aDocSheets.Length();
|
||||
size_t index = 0;
|
||||
for (; index < count; index++) {
|
||||
auto* sheet = static_cast<mozilla::StyleSheet*>(aDocSheets[index]);
|
||||
MOZ_ASSERT(sheet);
|
||||
int32_t sheetDocIndex = IndexOfSheet(*sheet);
|
||||
if (sheetDocIndex > newDocIndex)
|
||||
break;
|
||||
|
||||
mozilla::StyleSheet* sheetHandle = sheet;
|
||||
|
||||
// If the sheet is not owned by the document it can be an author
|
||||
// sheet registered at nsStyleSheetService or an additional author
|
||||
// sheet on the document, which means the new
|
||||
|
@ -44,11 +43,11 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
|
|||
if (sheetDocIndex < 0) {
|
||||
if (sheetService) {
|
||||
auto& authorSheets = *sheetService->AuthorStyleSheets();
|
||||
if (authorSheets.IndexOf(sheetHandle) != authorSheets.NoIndex) {
|
||||
if (authorSheets.IndexOf(sheet) != authorSheets.NoIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sheetHandle == GetFirstAdditionalAuthorSheet()) {
|
||||
if (sheet == GetFirstAdditionalAuthorSheet()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1243,7 +1243,7 @@ nsINode::RemoveEventListener(const nsAString& aType,
|
|||
NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
|
||||
|
||||
nsresult
|
||||
nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsINode::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
// This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
|
||||
NS_ABORT();
|
||||
|
@ -1515,7 +1515,6 @@ nsINode::SetExplicitBaseURI(nsIURI* aURI)
|
|||
{
|
||||
nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SetHasExplicitBaseURI();
|
||||
NS_ADDREF(aURI);
|
||||
}
|
||||
return rv;
|
||||
|
@ -3133,3 +3132,9 @@ nsINode::IsStyledByServo() const
|
|||
return OwnerDoc()->IsStyledByServo();
|
||||
}
|
||||
#endif
|
||||
|
||||
DocGroup*
|
||||
nsINode::GetDocGroup() const
|
||||
{
|
||||
return OwnerDoc()->GetDocGroup();
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ inline bool IsSpaceCharacter(char aChar) {
|
|||
class AccessibleNode;
|
||||
struct BoxQuadOptions;
|
||||
struct ConvertCoordinateOptions;
|
||||
class DocGroup;
|
||||
class DOMPoint;
|
||||
class DOMQuad;
|
||||
class DOMRectReadOnly;
|
||||
|
@ -126,9 +127,28 @@ enum {
|
|||
|
||||
NODE_IS_EDITABLE = NODE_FLAG_BIT(7),
|
||||
|
||||
// For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
|
||||
// node in fact has a class, but may be set even if it doesn't.
|
||||
NODE_MAY_HAVE_CLASS = NODE_FLAG_BIT(8),
|
||||
// This node was created by layout as native anonymous content. This
|
||||
// generally corresponds to things created by nsIAnonymousContentCreator,
|
||||
// though there are exceptions (svg:use content does not have this flag
|
||||
// set, and any non-nsIAnonymousContentCreator callers of
|
||||
// SetIsNativeAnonymousRoot also get this flag).
|
||||
//
|
||||
// One very important aspect here is that this node is not transitive over
|
||||
// the subtree (if you want that, use NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE).
|
||||
// If Gecko code somewhere attaches children to a node with this bit set,
|
||||
// the children will not have the bit themselves unless the calling code sets
|
||||
// it explicitly. This means that XBL content bound to NAC doesn't get this
|
||||
// bit, nor do nodes inserted by editor.
|
||||
//
|
||||
// For now, this bit exists primarily to control style inheritance behavior,
|
||||
// since the nodes for which we set it are often used to implement pseudo-
|
||||
// elements, which need to inherit style from a script-visible element.
|
||||
//
|
||||
// A more general principle for this bit might be this: If the node is entirely
|
||||
// a detail of layout, is not script-observable in any way, and other engines
|
||||
// might accomplish the same task with a nodeless layout frame, then the node
|
||||
// should have this bit set.
|
||||
NODE_IS_NATIVE_ANONYMOUS = NODE_FLAG_BIT(8),
|
||||
|
||||
// Whether the node participates in a shadow tree.
|
||||
NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(9),
|
||||
|
@ -280,6 +300,7 @@ class nsINode : public mozilla::dom::EventTarget
|
|||
public:
|
||||
typedef mozilla::dom::BoxQuadOptions BoxQuadOptions;
|
||||
typedef mozilla::dom::ConvertCoordinateOptions ConvertCoordinateOptions;
|
||||
typedef mozilla::dom::DocGroup DocGroup;
|
||||
typedef mozilla::dom::DOMPoint DOMPoint;
|
||||
typedef mozilla::dom::DOMPointInit DOMPointInit;
|
||||
typedef mozilla::dom::DOMQuad DOMQuad;
|
||||
|
@ -389,6 +410,12 @@ public:
|
|||
*/
|
||||
virtual bool IsNodeOfType(uint32_t aFlags) const = 0;
|
||||
|
||||
bool
|
||||
IsSlotable() const
|
||||
{
|
||||
return IsElement() || IsNodeOfType(eTEXT);
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
|
@ -588,6 +615,11 @@ public:
|
|||
return mNodeInfo->NamespaceID() == aNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DocGroup of the "node document" of this node.
|
||||
*/
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
/**
|
||||
* Print a debugger friendly descriptor of this element. This will describe
|
||||
* the position of this element in the document.
|
||||
|
@ -920,6 +952,14 @@ public:
|
|||
*/
|
||||
inline nsINode* GetFlattenedTreeParentNode() const;
|
||||
|
||||
/**
|
||||
* Like GetFlattenedTreeParentNode, but returns null for any native
|
||||
* anonymous content that was generated for ancestor frames of the
|
||||
* root element's primary frame, such as scrollbar elements created
|
||||
* by the root scroll frame.
|
||||
*/
|
||||
inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
|
||||
|
||||
/**
|
||||
* Get the parent nsINode for this node if it is an Element.
|
||||
* @return the parent node
|
||||
|
@ -1203,6 +1243,15 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if |this| is native anonymous (i.e. created by
|
||||
* nsIAnonymousContentCreator);
|
||||
*/
|
||||
bool IsNativeAnonymous() const
|
||||
{
|
||||
return HasFlag(NODE_IS_NATIVE_ANONYMOUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if |this| or any of its ancestors is native anonymous.
|
||||
*/
|
||||
|
@ -1335,10 +1384,11 @@ public:
|
|||
|
||||
protected:
|
||||
nsIURI* GetExplicitBaseURI() const {
|
||||
if (HasExplicitBaseURI()) {
|
||||
return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
|
||||
if (!HasProperties()) {
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -1541,6 +1591,8 @@ private:
|
|||
// cases lie for nsXMLElement, such as when the node has been moved between
|
||||
// documents with different id mappings.
|
||||
ElementHasID,
|
||||
// Set if the element might have a class.
|
||||
ElementMayHaveClass,
|
||||
// Set if the element might have inline style.
|
||||
ElementMayHaveStyle,
|
||||
// Set if the element has a name attribute set.
|
||||
|
@ -1559,8 +1611,6 @@ private:
|
|||
// Maybe set if the node is a root of a subtree
|
||||
// which needs to be kept in the purple buffer.
|
||||
NodeIsPurpleRoot,
|
||||
// Set if the node has an explicit base URI stored
|
||||
NodeHasExplicitBaseURI,
|
||||
// Set if the element has some style states locked
|
||||
ElementHasLockedStyleStates,
|
||||
// Set if element has pointer locked
|
||||
|
@ -1571,10 +1621,11 @@ private:
|
|||
NodeIsContent,
|
||||
// Set if the node has animations or transitions
|
||||
ElementHasAnimations,
|
||||
// Set if node has a dir attribute with a valid value (ltr, rtl, or auto)
|
||||
// Set if node has a dir attribute with a valid value (ltr, rtl, or auto).
|
||||
// Note that we cannot compute this from the dir attribute event state
|
||||
// flags, because we can't use those to distinguish
|
||||
// <bdi dir="some-invalid-value"> and <bdi dir="auto">.
|
||||
NodeHasValidDirAttribute,
|
||||
// Set if node has a dir attribute with a fixed value (ltr or rtl, NOT auto)
|
||||
NodeHasFixedDir,
|
||||
// Set if the node has dir=auto and has a property pointing to the text
|
||||
// node that determines its direction
|
||||
NodeHasDirAutoSet,
|
||||
|
@ -1582,8 +1633,6 @@ private:
|
|||
// and has a TextNodeDirectionalityMap property listing the elements whose
|
||||
// direction it determines.
|
||||
NodeHasTextNodeDirectionalityMap,
|
||||
// Set if the node has dir=auto.
|
||||
NodeHasDirAuto,
|
||||
// Set if a node in the node's parent chain has dir=auto.
|
||||
NodeAncestorHasDirAuto,
|
||||
// Set if the element is in the scope of a scoped style sheet; this flag is
|
||||
|
@ -1637,6 +1686,8 @@ public:
|
|||
{ SetBoolFlag(NodeHasRenderingObservers, aValue); }
|
||||
bool IsContent() const { return GetBoolFlag(NodeIsContent); }
|
||||
bool HasID() const { return GetBoolFlag(ElementHasID); }
|
||||
bool MayHaveClass() const { return GetBoolFlag(ElementMayHaveClass); }
|
||||
void SetMayHaveClass() { SetBoolFlag(ElementMayHaveClass); }
|
||||
bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
|
||||
bool HasName() const { return GetBoolFlag(ElementHasName); }
|
||||
bool MayHaveContentEditableAttr() const
|
||||
|
@ -1676,17 +1727,6 @@ public:
|
|||
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
|
||||
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
|
||||
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
|
||||
void SetHasFixedDir() {
|
||||
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
|
||||
"SetHasFixedDir on text node");
|
||||
SetBoolFlag(NodeHasFixedDir);
|
||||
}
|
||||
void ClearHasFixedDir() {
|
||||
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
|
||||
"ClearHasFixedDir on text node");
|
||||
ClearBoolFlag(NodeHasFixedDir);
|
||||
}
|
||||
bool HasFixedDir() const { return GetBoolFlag(NodeHasFixedDir); }
|
||||
void SetHasDirAutoSet() {
|
||||
MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
|
||||
"SetHasDirAutoSet on text node");
|
||||
|
@ -1715,16 +1755,12 @@ public:
|
|||
return GetBoolFlag(NodeHasTextNodeDirectionalityMap);
|
||||
}
|
||||
|
||||
void SetHasDirAuto() { SetBoolFlag(NodeHasDirAuto); }
|
||||
void ClearHasDirAuto() { ClearBoolFlag(NodeHasDirAuto); }
|
||||
bool HasDirAuto() const { return GetBoolFlag(NodeHasDirAuto); }
|
||||
|
||||
void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
|
||||
void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
|
||||
bool AncestorHasDirAuto() const { return GetBoolFlag(NodeAncestorHasDirAuto); }
|
||||
|
||||
bool NodeOrAncestorHasDirAuto() const
|
||||
{ return HasDirAuto() || AncestorHasDirAuto(); }
|
||||
// Implemented in nsIContentInlines.h.
|
||||
inline bool NodeOrAncestorHasDirAuto() const;
|
||||
|
||||
void SetIsElementInStyleScope(bool aValue) {
|
||||
MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
|
||||
|
@ -1766,8 +1802,6 @@ protected:
|
|||
void ClearHasName() { ClearBoolFlag(ElementHasName); }
|
||||
void SetMayHaveContentEditableAttr()
|
||||
{ SetBoolFlag(ElementMayHaveContentEditableAttr); }
|
||||
bool HasExplicitBaseURI() const { return GetBoolFlag(NodeHasExplicitBaseURI); }
|
||||
void SetHasExplicitBaseURI() { SetBoolFlag(NodeHasExplicitBaseURI); }
|
||||
void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
|
||||
void ClearHasLockedStyleStates() { ClearBoolFlag(ElementHasLockedStyleStates); }
|
||||
bool HasLockedStyleStates() const
|
||||
|
|
|
@ -97,7 +97,7 @@ nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
|
|||
mozilla::HoldJSObjects(this);
|
||||
|
||||
// If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
|
||||
// have to tweak our PreHandleEvent implementation.
|
||||
// GetEventTargetParent implementation.
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
|
||||
if (browserFrame) {
|
||||
mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
|
||||
|
@ -251,7 +251,7 @@ nsInProcessTabChildGlobal::GetOwnerContent()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsInProcessTabChildGlobal::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mForceContentDispatch = true;
|
||||
aVisitor.mCanHandle = true;
|
||||
|
@ -270,7 +270,7 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
#endif
|
||||
|
||||
if (mPreventEventsEscaping) {
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -278,11 +278,13 @@ nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
(!mOwner || !nsContentUtils::IsInChromeDocshell(mOwner->OwnerDoc()))) {
|
||||
if (mOwner) {
|
||||
if (nsPIDOMWindowInner* innerWindow = mOwner->OwnerDoc()->GetInnerWindow()) {
|
||||
aVisitor.mParentTarget = innerWindow->GetParentTarget();
|
||||
// 'this' is already a "chrome handler", so we consider window's
|
||||
// parent target to be part of that same part of the event path.
|
||||
aVisitor.SetParentTarget(innerWindow->GetParentTarget(), false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aVisitor.mParentTarget = mOwner;
|
||||
aVisitor.SetParentTarget(mOwner, false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult PreHandleEvent(
|
||||
virtual nsresult GetEventTargetParent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
NS_IMETHOD AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
|
@ -168,7 +168,7 @@ protected:
|
|||
|
||||
// Is this the message manager for an in-process <iframe mozbrowser> or
|
||||
// <iframe mozapp>? This affects where events get sent, so it affects
|
||||
// PreHandleEvent.
|
||||
// GetEventTargetParent.
|
||||
bool mIsBrowserOrAppFrame;
|
||||
bool mPreventEventsEscaping;
|
||||
|
||||
|
|
|
@ -15,17 +15,19 @@ nsMappedAttributeElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
|
|||
}
|
||||
|
||||
bool
|
||||
nsMappedAttributeElement::SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval)
|
||||
nsMappedAttributeElement::SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval)
|
||||
|
||||
{
|
||||
NS_PRECONDITION(aDocument == GetComposedDoc(), "Unexpected document");
|
||||
nsHTMLStyleSheet* sheet = aDocument ?
|
||||
aDocument->GetAttributeStyleSheet() : nullptr;
|
||||
|
||||
*aRetval = mAttrsAndChildren.SetAndTakeMappedAttr(aName, aValue,
|
||||
this, sheet);
|
||||
*aRetval = mAttrsAndChildren.SetAndSwapMappedAttr(aName, aValue,
|
||||
this, sheet, aValueWasSet);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,10 +39,11 @@ public:
|
|||
nsRuleData* aRuleData);
|
||||
|
||||
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
|
||||
virtual bool SetMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
nsresult* aRetval) override;
|
||||
virtual bool SetAndSwapMappedAttribute(nsIDocument* aDocument,
|
||||
nsIAtom* aName,
|
||||
nsAttrValue& aValue,
|
||||
bool* aValueWasSet,
|
||||
nsresult* aRetval) override;
|
||||
};
|
||||
|
||||
#endif // NS_MAPPEDATTRIBUTEELEMENT_H_
|
||||
|
|
|
@ -62,11 +62,17 @@ nsMappedAttributes::Clone(bool aWillAddAttr)
|
|||
|
||||
void* nsMappedAttributes::operator new(size_t aSize, uint32_t aAttrCount) CPP_THROW_NEW
|
||||
{
|
||||
NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested");
|
||||
size_t size = aSize + aAttrCount * sizeof(InternalAttr);
|
||||
|
||||
// aSize will include the mAttrs buffer so subtract that.
|
||||
void* newAttrs = ::operator new(aSize - sizeof(void*[1]) +
|
||||
aAttrCount * sizeof(InternalAttr));
|
||||
// We don't want to under-allocate, however, so do not subtract
|
||||
// if we have zero attributes. The zero attribute case only happens
|
||||
// for <body>'s mapped attributes
|
||||
if (aAttrCount != 0) {
|
||||
size -= sizeof(void*[1]);
|
||||
}
|
||||
|
||||
void* newAttrs = ::operator new(size);
|
||||
|
||||
#ifdef DEBUG
|
||||
static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
|
||||
|
@ -79,15 +85,16 @@ NS_IMPL_ISUPPORTS(nsMappedAttributes,
|
|||
nsIStyleRule)
|
||||
|
||||
void
|
||||
nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
|
||||
nsMappedAttributes::SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
|
||||
bool* aValueWasSet)
|
||||
{
|
||||
NS_PRECONDITION(aAttrName, "null name");
|
||||
|
||||
*aValueWasSet = false;
|
||||
uint32_t i;
|
||||
for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
|
||||
if (Attrs()[i].mName.Equals(aAttrName)) {
|
||||
Attrs()[i].mValue.Reset();
|
||||
Attrs()[i].mValue.SwapValueWith(aValue);
|
||||
*aValueWasSet = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
void SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue);
|
||||
void SetAndSwapAttr(nsIAtom* aAttrName, nsAttrValue& aValue,
|
||||
bool* aValueWasSet);
|
||||
const nsAttrValue* GetAttr(nsIAtom* aAttrName) const;
|
||||
const nsAttrValue* GetAttr(const nsAString& aAttrName) const;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ using mozilla::AutoJSContext;
|
|||
} \
|
||||
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
|
||||
if (shadow) { \
|
||||
node = shadow->GetPoolHost(); \
|
||||
node = shadow->GetHost(); \
|
||||
} else { \
|
||||
node = node->GetParentNode(); \
|
||||
} \
|
||||
|
@ -93,7 +93,7 @@ using mozilla::AutoJSContext;
|
|||
} \
|
||||
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
|
||||
if (shadow) { \
|
||||
node = shadow->GetPoolHost(); \
|
||||
node = shadow->GetHost(); \
|
||||
} else { \
|
||||
node = node->GetParentNode(); \
|
||||
} \
|
||||
|
|
|
@ -49,6 +49,12 @@ nsRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return RangeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
DocGroup*
|
||||
nsRange::GetDocGroup() const
|
||||
{
|
||||
return mOwner ? mOwner->GetDocGroup() : nullptr;
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* stack based utilty class for managing monitor
|
||||
******************************************************/
|
||||
|
@ -111,31 +117,37 @@ nsRange::CompareNodeToRange(nsINode* aNode, nsRange* aRange,
|
|||
// so instead represent it by (node,0) and (node,numChildren)
|
||||
parent = aNode;
|
||||
nodeStart = 0;
|
||||
nodeEnd = aNode->GetChildCount();
|
||||
uint32_t childCount = aNode->GetChildCount();
|
||||
MOZ_ASSERT(childCount <= INT32_MAX,
|
||||
"There shouldn't be over INT32_MAX children");
|
||||
nodeEnd = static_cast<int32_t>(childCount);
|
||||
}
|
||||
else {
|
||||
nodeStart = parent->IndexOf(aNode);
|
||||
nodeEnd = nodeStart + 1;
|
||||
MOZ_ASSERT(nodeStart < nodeEnd, "nodeStart shouldn't be INT32_MAX");
|
||||
}
|
||||
|
||||
nsINode* rangeStartParent = aRange->GetStartParent();
|
||||
nsINode* rangeEndParent = aRange->GetEndParent();
|
||||
int32_t rangeStartOffset = aRange->StartOffset();
|
||||
int32_t rangeEndOffset = aRange->EndOffset();
|
||||
uint32_t rangeStartOffset = aRange->StartOffset();
|
||||
uint32_t rangeEndOffset = aRange->EndOffset();
|
||||
|
||||
// is RANGE(start) <= NODE(start) ?
|
||||
bool disconnected = false;
|
||||
*outNodeBefore = nsContentUtils::ComparePoints(rangeStartParent,
|
||||
rangeStartOffset,
|
||||
parent, nodeStart,
|
||||
&disconnected) > 0;
|
||||
*outNodeBefore =
|
||||
nsContentUtils::ComparePoints(rangeStartParent,
|
||||
static_cast<int32_t>(rangeStartOffset),
|
||||
parent, nodeStart,
|
||||
&disconnected) > 0;
|
||||
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
|
||||
|
||||
// is RANGE(end) >= NODE(end) ?
|
||||
*outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
|
||||
rangeEndOffset,
|
||||
parent, nodeEnd,
|
||||
&disconnected) < 0;
|
||||
*outNodeAfter =
|
||||
nsContentUtils::ComparePoints(rangeEndParent,
|
||||
static_cast<int32_t>(rangeEndOffset),
|
||||
parent, nodeEnd,
|
||||
&disconnected) < 0;
|
||||
NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -164,13 +176,17 @@ struct IsItemInRangeComparator
|
|||
|
||||
int operator()(const nsRange* const aRange) const
|
||||
{
|
||||
int32_t cmp = nsContentUtils::ComparePoints(mNode, mEndOffset,
|
||||
aRange->GetStartParent(),
|
||||
aRange->StartOffset());
|
||||
int32_t cmp =
|
||||
nsContentUtils::ComparePoints(
|
||||
mNode, static_cast<int32_t>(mEndOffset),
|
||||
aRange->GetStartParent(),
|
||||
static_cast<int32_t>(aRange->StartOffset()));
|
||||
if (cmp == 1) {
|
||||
cmp = nsContentUtils::ComparePoints(mNode, mStartOffset,
|
||||
aRange->GetEndParent(),
|
||||
aRange->EndOffset());
|
||||
cmp =
|
||||
nsContentUtils::ComparePoints(
|
||||
mNode, static_cast<int32_t>(mStartOffset),
|
||||
aRange->GetEndParent(),
|
||||
static_cast<int32_t>(aRange->EndOffset()));
|
||||
if (cmp == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -266,48 +282,38 @@ nsRange::nsRange(nsINode* aNode)
|
|||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> startDomNode = do_QueryInterface(aStartParent);
|
||||
nsCOMPtr<nsIDOMNode> endDomNode = do_QueryInterface(aEndParent);
|
||||
|
||||
nsresult rv = CreateRange(startDomNode, aStartOffset, endDomNode, aEndOffset,
|
||||
aRange);
|
||||
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
nsRange::CreateRange(nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
MOZ_ASSERT(aRange);
|
||||
*aRange = nullptr;
|
||||
|
||||
nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
|
||||
NS_ENSURE_ARG_POINTER(startParent);
|
||||
|
||||
RefPtr<nsRange> range = new nsRange(startParent);
|
||||
|
||||
nsresult rv = range->SetStart(startParent, aStartOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = range->SetEnd(aEndParent, aEndOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<nsRange> range = new nsRange(aStartParent);
|
||||
nsresult rv = range->SetStartAndEnd(aStartParent, aStartOffset,
|
||||
aEndParent, aEndOffset);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
range.forget(aRange);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, uint32_t aEndOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
nsCOMPtr<nsINode> startParent = do_QueryInterface(aStartParent);
|
||||
nsCOMPtr<nsINode> endParent = do_QueryInterface(aEndParent);
|
||||
return CreateRange(startParent, aStartOffset, endParent, aEndOffset, aRange);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsRange::CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, uint32_t aEndOffset,
|
||||
nsIDOMRange** aRange)
|
||||
{
|
||||
RefPtr<nsRange> range;
|
||||
|
@ -465,15 +471,27 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
// again (when the new text node is notified).
|
||||
nsINode* parentNode = aContent->GetParentNode();
|
||||
int32_t index = -1;
|
||||
if (parentNode == mEndParent && mEndOffset > 0 &&
|
||||
(index = parentNode->IndexOf(aContent)) + 1 == mEndOffset) {
|
||||
++mEndOffset;
|
||||
mEndOffsetWasIncremented = true;
|
||||
if (parentNode == mEndParent && mEndOffset > 0) {
|
||||
index = parentNode->IndexOf(aContent);
|
||||
NS_WARNING_ASSERTION(index >= 0,
|
||||
"Shouldn't be called during removing the node or something");
|
||||
if (static_cast<uint32_t>(index + 1) == mEndOffset) {
|
||||
newEndNode = mEndParent;
|
||||
newEndOffset = mEndOffset + 1;
|
||||
MOZ_ASSERT(IsValidOffset(newEndOffset));
|
||||
mEndOffsetWasIncremented = true;
|
||||
}
|
||||
}
|
||||
if (parentNode == mStartParent && mStartOffset > 0 &&
|
||||
(index != -1 ? index : parentNode->IndexOf(aContent)) + 1 == mStartOffset) {
|
||||
++mStartOffset;
|
||||
mStartOffsetWasIncremented = true;
|
||||
if (parentNode == mStartParent && mStartOffset > 0) {
|
||||
if (index <= 0) {
|
||||
index = parentNode->IndexOf(aContent);
|
||||
}
|
||||
if (static_cast<uint32_t>(index + 1) == mStartOffset) {
|
||||
newStartNode = mStartParent;
|
||||
newStartOffset = mStartOffset + 1;
|
||||
MOZ_ASSERT(IsValidOffset(newStartOffset));
|
||||
mStartOffsetWasIncremented = true;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (mStartOffsetWasIncremented || mEndOffsetWasIncremented) {
|
||||
|
@ -486,16 +504,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
|
||||
// If the changed node contains our start boundary and the change starts
|
||||
// before the boundary we'll need to adjust the offset.
|
||||
if (aContent == mStartParent &&
|
||||
aInfo->mChangeStart < static_cast<uint32_t>(mStartOffset)) {
|
||||
if (aContent == mStartParent && aInfo->mChangeStart < mStartOffset) {
|
||||
if (aInfo->mDetails) {
|
||||
// splitText(), aInfo->mDetails->mNextSibling is the new text node
|
||||
NS_ASSERTION(aInfo->mDetails->mType ==
|
||||
CharacterDataChangeInfo::Details::eSplit,
|
||||
"only a split can start before the end");
|
||||
NS_ASSERTION(static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd + 1,
|
||||
NS_ASSERTION(mStartOffset <= aInfo->mChangeEnd + 1,
|
||||
"mStartOffset is beyond the end of this node");
|
||||
newStartOffset = static_cast<uint32_t>(mStartOffset) - aInfo->mChangeStart;
|
||||
newStartOffset = mStartOffset - aInfo->mChangeStart;
|
||||
newStartNode = aInfo->mDetails->mNextSibling;
|
||||
if (MOZ_UNLIKELY(aContent == mRoot)) {
|
||||
newRoot = IsValidBoundary(newStartNode);
|
||||
|
@ -512,7 +529,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
} else {
|
||||
// If boundary is inside changed text, position it before change
|
||||
// else adjust start offset for the change in length.
|
||||
mStartOffset = static_cast<uint32_t>(mStartOffset) <= aInfo->mChangeEnd ?
|
||||
mStartOffset = mStartOffset <= aInfo->mChangeEnd ?
|
||||
aInfo->mChangeStart :
|
||||
mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
|
||||
aInfo->mReplaceLength;
|
||||
|
@ -522,16 +539,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
// Do the same thing for the end boundary, except for splitText of a node
|
||||
// with no parent then only switch to the new node if the start boundary
|
||||
// did so too (otherwise the range would end up with disconnected nodes).
|
||||
if (aContent == mEndParent &&
|
||||
aInfo->mChangeStart < static_cast<uint32_t>(mEndOffset)) {
|
||||
if (aContent == mEndParent && aInfo->mChangeStart < mEndOffset) {
|
||||
if (aInfo->mDetails && (aContent->GetParentNode() || newStartNode)) {
|
||||
// splitText(), aInfo->mDetails->mNextSibling is the new text node
|
||||
NS_ASSERTION(aInfo->mDetails->mType ==
|
||||
CharacterDataChangeInfo::Details::eSplit,
|
||||
"only a split can start before the end");
|
||||
NS_ASSERTION(static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd + 1,
|
||||
NS_ASSERTION(mEndOffset <= aInfo->mChangeEnd + 1,
|
||||
"mEndOffset is beyond the end of this node");
|
||||
newEndOffset = static_cast<uint32_t>(mEndOffset) - aInfo->mChangeStart;
|
||||
newEndOffset = mEndOffset - aInfo->mChangeStart;
|
||||
newEndNode = aInfo->mDetails->mNextSibling;
|
||||
|
||||
bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
|
||||
|
@ -544,7 +560,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
|
||||
}
|
||||
} else {
|
||||
mEndOffset = static_cast<uint32_t>(mEndOffset) <= aInfo->mChangeEnd ?
|
||||
mEndOffset = mEndOffset <= aInfo->mChangeEnd ?
|
||||
aInfo->mChangeStart :
|
||||
mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
|
||||
aInfo->mReplaceLength;
|
||||
|
@ -557,14 +573,14 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
// that will be removed
|
||||
nsIContent* removed = aInfo->mDetails->mNextSibling;
|
||||
if (removed == mStartParent) {
|
||||
newStartOffset = static_cast<uint32_t>(mStartOffset) + aInfo->mChangeStart;
|
||||
newStartOffset = mStartOffset + aInfo->mChangeStart;
|
||||
newStartNode = aContent;
|
||||
if (MOZ_UNLIKELY(removed == mRoot)) {
|
||||
newRoot = IsValidBoundary(newStartNode);
|
||||
}
|
||||
}
|
||||
if (removed == mEndParent) {
|
||||
newEndOffset = static_cast<uint32_t>(mEndOffset) + aInfo->mChangeStart;
|
||||
newEndOffset = mEndOffset + aInfo->mChangeStart;
|
||||
newEndNode = aContent;
|
||||
if (MOZ_UNLIKELY(removed == mRoot)) {
|
||||
newRoot = IsValidBoundary(newEndNode);
|
||||
|
@ -578,13 +594,13 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
|
|||
// point before the first child is never affected by normalize().)
|
||||
nsINode* parentNode = aContent->GetParentNode();
|
||||
if (parentNode == mStartParent && mStartOffset > 0 &&
|
||||
uint32_t(mStartOffset) < parentNode->GetChildCount() &&
|
||||
mStartOffset < parentNode->GetChildCount() &&
|
||||
removed == parentNode->GetChildAt(mStartOffset)) {
|
||||
newStartNode = aContent;
|
||||
newStartOffset = aInfo->mChangeStart;
|
||||
}
|
||||
if (parentNode == mEndParent && mEndOffset > 0 &&
|
||||
uint32_t(mEndOffset) < parentNode->GetChildCount() &&
|
||||
mEndOffset < parentNode->GetChildCount() &&
|
||||
removed == parentNode->GetChildAt(mEndOffset)) {
|
||||
newEndNode = aContent;
|
||||
newEndOffset = aInfo->mChangeEnd;
|
||||
|
@ -649,13 +665,19 @@ nsRange::ContentInserted(nsIDocument* aDocument,
|
|||
nsINode* container = NODE_FROM(aContainer, aDocument);
|
||||
|
||||
// Adjust position if a sibling was inserted.
|
||||
if (container == mStartParent && aIndexInContainer < mStartOffset &&
|
||||
if (container == mStartParent &&
|
||||
(NS_WARN_IF(aIndexInContainer < 0) ||
|
||||
static_cast<uint32_t>(aIndexInContainer) < mStartOffset) &&
|
||||
!mStartOffsetWasIncremented) {
|
||||
++mStartOffset;
|
||||
MOZ_ASSERT(IsValidOffset(mStartOffset));
|
||||
}
|
||||
if (container == mEndParent && aIndexInContainer < mEndOffset &&
|
||||
if (container == mEndParent &&
|
||||
(NS_WARN_IF(aIndexInContainer < 0) ||
|
||||
static_cast<uint32_t>(aIndexInContainer) < mEndOffset) &&
|
||||
!mEndOffsetWasIncremented) {
|
||||
++mEndOffset;
|
||||
MOZ_ASSERT(IsValidOffset(mEndOffset));
|
||||
}
|
||||
if (container->IsSelectionDescendant() &&
|
||||
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
|
||||
|
@ -694,7 +716,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
|
|||
|
||||
// Adjust position if a sibling was removed...
|
||||
if (container == mStartParent) {
|
||||
if (aIndexInContainer < mStartOffset) {
|
||||
if (aIndexInContainer < static_cast<int32_t>(mStartOffset)) {
|
||||
--mStartOffset;
|
||||
}
|
||||
} else { // ...or gravitate if an ancestor was removed.
|
||||
|
@ -704,7 +726,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
|
|||
|
||||
// Do same thing for end boundry.
|
||||
if (container == mEndParent) {
|
||||
if (aIndexInContainer < mEndOffset) {
|
||||
if (aIndexInContainer < static_cast<int32_t>(mEndOffset)) {
|
||||
--mEndOffset;
|
||||
}
|
||||
} else if (didCheckStartParentDescendant && mStartParent == mEndParent) {
|
||||
|
@ -763,12 +785,15 @@ nsRange::ParentChainChanged(nsIContent *aContent)
|
|||
* Utilities for comparing points: API from nsIDOMRange
|
||||
******************************************************/
|
||||
NS_IMETHODIMP
|
||||
nsRange::IsPointInRange(nsIDOMNode* aParent, int32_t aOffset, bool* aResult)
|
||||
nsRange::IsPointInRange(nsIDOMNode* aParent, uint32_t aOffset, bool* aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
||||
if (!parent) {
|
||||
return NS_ERROR_DOM_NOT_OBJECT_ERR;
|
||||
}
|
||||
if (NS_WARN_IF(!IsValidOffset(aOffset))) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
*aResult = IsPointInRange(*parent, aOffset, rv);
|
||||
|
@ -791,7 +816,7 @@ nsRange::IsPointInRange(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
|
|||
// returns -1 if point is before range, 0 if point is in range,
|
||||
// 1 if point is after range.
|
||||
NS_IMETHODIMP
|
||||
nsRange::ComparePoint(nsIDOMNode* aParent, int32_t aOffset, int16_t* aResult)
|
||||
nsRange::ComparePoint(nsIDOMNode* aParent, uint32_t aOffset, int16_t* aResult)
|
||||
{
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
||||
NS_ENSURE_TRUE(parent, NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
||||
|
@ -825,14 +850,18 @@ nsRange::ComparePoint(nsINode& aParent, uint32_t aOffset, ErrorResult& aRv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t cmp;
|
||||
if ((cmp = nsContentUtils::ComparePoints(&aParent, aOffset,
|
||||
mStartParent, mStartOffset)) <= 0) {
|
||||
|
||||
int32_t cmp =
|
||||
nsContentUtils::ComparePoints(&aParent,
|
||||
static_cast<int32_t>(aOffset),
|
||||
mStartParent,
|
||||
static_cast<int32_t>(mStartOffset));
|
||||
if (cmp <= 0) {
|
||||
return cmp;
|
||||
}
|
||||
if (nsContentUtils::ComparePoints(mEndParent, mEndOffset,
|
||||
&aParent, aOffset) == -1) {
|
||||
if (nsContentUtils::ComparePoints(mEndParent,
|
||||
static_cast<int32_t>(mEndOffset),
|
||||
&aParent,
|
||||
static_cast<int32_t>(aOffset)) == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -875,12 +904,15 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
|
|||
// Steps 6-7.
|
||||
// Note: if disconnected is true, ComparePoints returns 1.
|
||||
bool disconnected = false;
|
||||
bool result = nsContentUtils::ComparePoints(mStartParent, mStartOffset,
|
||||
parent, nodeIndex + 1,
|
||||
&disconnected) < 0 &&
|
||||
nsContentUtils::ComparePoints(parent, nodeIndex,
|
||||
mEndParent, mEndOffset,
|
||||
&disconnected) < 0;
|
||||
bool result =
|
||||
nsContentUtils::ComparePoints(mStartParent,
|
||||
static_cast<int32_t>(mStartOffset),
|
||||
parent, nodeIndex + 1,
|
||||
&disconnected) < 0 &&
|
||||
nsContentUtils::ComparePoints(parent, nodeIndex,
|
||||
mEndParent,
|
||||
static_cast<int32_t>(mEndOffset),
|
||||
&disconnected) < 0;
|
||||
|
||||
// Step 2.
|
||||
if (disconnected) {
|
||||
|
@ -899,8 +931,8 @@ nsRange::IntersectsNode(nsINode& aNode, ErrorResult& aRv)
|
|||
// Calling DoSetRange with either parent argument null will collapse
|
||||
// the range to have both endpoints point to the other node
|
||||
void
|
||||
nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
|
||||
nsINode* aEndN, int32_t aEndOffset,
|
||||
nsRange::DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
|
||||
nsINode* aEndN, uint32_t aEndOffset,
|
||||
nsINode* aRoot, bool aNotInsertedYet)
|
||||
{
|
||||
NS_PRECONDITION((aStartN && aEndN && aRoot) ||
|
||||
|
@ -926,6 +958,8 @@ nsRange::DoSetRange(nsINode* aStartN, int32_t aStartOffset,
|
|||
/*For backward compatibility*/
|
||||
aRoot->IsNodeOfType(nsINode::eCONTENT))),
|
||||
"Bad root");
|
||||
MOZ_ASSERT(IsValidOffset(aStartOffset));
|
||||
MOZ_ASSERT(IsValidOffset(aEndOffset));
|
||||
|
||||
if (mRoot != aRoot) {
|
||||
if (mRoot) {
|
||||
|
@ -1038,7 +1072,7 @@ nsRange::GetStartContainer(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRange::GetStartOffset(int32_t* aStartOffset)
|
||||
nsRange::GetStartOffset(uint32_t* aStartOffset)
|
||||
{
|
||||
if (!mIsPositioned)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
@ -1080,7 +1114,7 @@ nsRange::GetEndContainer(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRange::GetEndOffset(int32_t* aEndOffset)
|
||||
nsRange::GetEndOffset(uint32_t* aEndOffset)
|
||||
{
|
||||
if (!mIsPositioned)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
@ -1137,6 +1171,15 @@ nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
|
|||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsRange::IsValidOffset(nsINode* aNode, uint32_t aOffset)
|
||||
{
|
||||
return aNode &&
|
||||
IsValidOffset(aOffset) &&
|
||||
static_cast<size_t>(aOffset) <= aNode->Length();
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsRange::IsValidBoundary(nsINode* aNode)
|
||||
{
|
||||
|
@ -1197,7 +1240,7 @@ nsRange::SetStart(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
|
||||
nsRange::SetStart(nsIDOMNode* aParent, uint32_t aOffset)
|
||||
{
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
||||
if (!parent) {
|
||||
|
@ -1210,22 +1253,24 @@ nsRange::SetStart(nsIDOMNode* aParent, int32_t aOffset)
|
|||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
nsRange::SetStart(nsINode* aParent, int32_t aOffset)
|
||||
nsRange::SetStart(nsINode* aParent, uint32_t aOffset)
|
||||
{
|
||||
nsINode* newRoot = IsValidBoundary(aParent);
|
||||
if (!newRoot) {
|
||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||
}
|
||||
|
||||
if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
|
||||
if (!IsValidOffset(aParent, aOffset)) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
// Collapse if not positioned yet, if positioned in another doc or
|
||||
// if the new start is after end.
|
||||
if (!mIsPositioned || newRoot != mRoot ||
|
||||
nsContentUtils::ComparePoints(aParent, aOffset,
|
||||
mEndParent, mEndOffset) == 1) {
|
||||
nsContentUtils::ComparePoints(aParent,
|
||||
static_cast<int32_t>(aOffset),
|
||||
mEndParent,
|
||||
static_cast<int32_t>(mEndOffset)) == 1) {
|
||||
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1246,7 +1291,12 @@ nsRange::SetStartBefore(nsINode& aNode, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
AutoInvalidateSelection atEndOfBlock(this);
|
||||
aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode));
|
||||
// If the node is being removed from its parent, GetContainerAndOffsetBefore()
|
||||
// returns nullptr. Then, SetStart() will throw
|
||||
// NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
|
||||
uint32_t offset = UINT32_MAX;
|
||||
nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
|
||||
aRv = SetStart(parent, offset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1272,7 +1322,12 @@ nsRange::SetStartAfter(nsINode& aNode, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
AutoInvalidateSelection atEndOfBlock(this);
|
||||
aRv = SetStart(aNode.GetParentNode(), IndexOf(&aNode) + 1);
|
||||
// If the node is being removed from its parent, GetContainerAndOffsetAfter()
|
||||
// returns nullptr. Then, SetStart() will throw
|
||||
// NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
|
||||
uint32_t offset = UINT32_MAX;
|
||||
nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
|
||||
aRv = SetStart(parent, offset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1301,7 +1356,7 @@ nsRange::SetEnd(nsINode& aNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
|
||||
nsRange::SetEnd(nsIDOMNode* aParent, uint32_t aOffset)
|
||||
{
|
||||
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
|
||||
if (!parent) {
|
||||
|
@ -1314,22 +1369,24 @@ nsRange::SetEnd(nsIDOMNode* aParent, int32_t aOffset)
|
|||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
|
||||
nsRange::SetEnd(nsINode* aParent, uint32_t aOffset)
|
||||
{
|
||||
nsINode* newRoot = IsValidBoundary(aParent);
|
||||
if (!newRoot) {
|
||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||
}
|
||||
|
||||
if (aOffset < 0 || uint32_t(aOffset) > aParent->Length()) {
|
||||
if (!IsValidOffset(aParent, aOffset)) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
// Collapse if not positioned yet, if positioned in another doc or
|
||||
// if the new end is before start.
|
||||
if (!mIsPositioned || newRoot != mRoot ||
|
||||
nsContentUtils::ComparePoints(mStartParent, mStartOffset,
|
||||
aParent, aOffset) == 1) {
|
||||
nsContentUtils::ComparePoints(mStartParent,
|
||||
static_cast<int32_t>(mStartOffset),
|
||||
aParent,
|
||||
static_cast<int32_t>(aOffset)) == 1) {
|
||||
DoSetRange(aParent, aOffset, aParent, aOffset, newRoot);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1340,6 +1397,66 @@ nsRange::SetEnd(nsINode* aParent, int32_t aOffset)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRange::SetStartAndEnd(nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset)
|
||||
{
|
||||
if (NS_WARN_IF(!aStartParent) || NS_WARN_IF(!aEndParent)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsINode* newStartRoot = IsValidBoundary(aStartParent);
|
||||
if (!newStartRoot) {
|
||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||
}
|
||||
if (!IsValidOffset(aStartParent, aStartOffset)) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
if (aStartParent == aEndParent) {
|
||||
if (!IsValidOffset(aEndParent, aEndOffset)) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
// If the end offset is less than the start offset, this should be
|
||||
// collapsed at the end offset.
|
||||
if (aStartOffset > aEndOffset) {
|
||||
DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newStartRoot);
|
||||
} else {
|
||||
DoSetRange(aStartParent, aStartOffset,
|
||||
aEndParent, aEndOffset, newStartRoot);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsINode* newEndRoot = IsValidBoundary(aEndParent);
|
||||
if (!newEndRoot) {
|
||||
return NS_ERROR_DOM_INVALID_NODE_TYPE_ERR;
|
||||
}
|
||||
if (!IsValidOffset(aEndParent, aEndOffset)) {
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
// If they have different root, this should be collapsed at the end point.
|
||||
if (newStartRoot != newEndRoot) {
|
||||
DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the end point is before the start point, this should be collapsed at
|
||||
// the end point.
|
||||
if (nsContentUtils::ComparePoints(aStartParent,
|
||||
static_cast<int32_t>(aStartOffset),
|
||||
aEndParent,
|
||||
static_cast<int32_t>(aEndOffset)) == 1) {
|
||||
DoSetRange(aEndParent, aEndOffset, aEndParent, aEndOffset, newEndRoot);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, set the range as specified.
|
||||
DoSetRange(aStartParent, aStartOffset, aEndParent, aEndOffset, newStartRoot);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -1350,7 +1467,12 @@ nsRange::SetEndBefore(nsINode& aNode, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
AutoInvalidateSelection atEndOfBlock(this);
|
||||
aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode));
|
||||
// If the node is being removed from its parent, GetContainerAndOffsetBefore()
|
||||
// returns nullptr. Then, SetEnd() will throw
|
||||
// NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
|
||||
uint32_t offset = UINT32_MAX;
|
||||
nsINode* parent = GetParentAndOffsetBefore(&aNode, &offset);
|
||||
aRv = SetEnd(parent, offset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1376,7 +1498,12 @@ nsRange::SetEndAfter(nsINode& aNode, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
AutoInvalidateSelection atEndOfBlock(this);
|
||||
aRv = SetEnd(aNode.GetParentNode(), IndexOf(&aNode) + 1);
|
||||
// If the node is being removed from its parent, GetContainerAndOffsetAfter()
|
||||
// returns nullptr. Then, SetEnd() will throw
|
||||
// NS_ERROR_DOM_INVALID_NODE_TYPE_ERR.
|
||||
uint32_t offset = UINT32_MAX;
|
||||
nsINode* parent = GetParentAndOffsetAfter(&aNode, &offset);
|
||||
aRv = SetEnd(parent, offset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1435,7 +1562,9 @@ nsRange::SelectNode(nsINode& aNode, ErrorResult& aRv)
|
|||
}
|
||||
|
||||
int32_t index = parent->IndexOf(&aNode);
|
||||
if (index < 0) {
|
||||
if (NS_WARN_IF(index < 0) ||
|
||||
!IsValidOffset(static_cast<uint32_t>(index)) ||
|
||||
!IsValidOffset(static_cast<uint32_t>(index) + 1)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_NODE_TYPE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -1884,9 +2013,9 @@ nsRange::CutContents(DocumentFragment** aFragment)
|
|||
// of Range gravity during our edits!
|
||||
|
||||
nsCOMPtr<nsINode> startContainer = mStartParent;
|
||||
int32_t startOffset = mStartOffset;
|
||||
uint32_t startOffset = mStartOffset;
|
||||
nsCOMPtr<nsINode> endContainer = mEndParent;
|
||||
int32_t endOffset = mEndOffset;
|
||||
uint32_t endOffset = mEndOffset;
|
||||
|
||||
if (retval) {
|
||||
// For extractContents(), abort early if there's a doctype (bug 719533).
|
||||
|
@ -1897,10 +2026,12 @@ nsRange::CutContents(DocumentFragment** aFragment)
|
|||
RefPtr<DocumentType> doctype = commonAncestorDocument->GetDoctype();
|
||||
|
||||
if (doctype &&
|
||||
nsContentUtils::ComparePoints(startContainer, startOffset,
|
||||
nsContentUtils::ComparePoints(startContainer,
|
||||
static_cast<int32_t>(startOffset),
|
||||
doctype, 0) < 0 &&
|
||||
nsContentUtils::ComparePoints(doctype, 0,
|
||||
endContainer, endOffset) < 0) {
|
||||
endContainer,
|
||||
static_cast<int32_t>(endOffset)) < 0) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
}
|
||||
|
@ -1995,8 +2126,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
|
|||
rv = charData->GetLength(&dataLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (dataLength >= (uint32_t)startOffset)
|
||||
{
|
||||
if (dataLength >= startOffset) {
|
||||
nsMutationGuard guard;
|
||||
nsCOMPtr<nsIDOMCharacterData> cutNode;
|
||||
rv = SplitDataNode(charData, startOffset, getter_AddRefs(cutNode));
|
||||
|
@ -2012,22 +2142,17 @@ nsRange::CutContents(DocumentFragment** aFragment)
|
|||
else if (node == endContainer)
|
||||
{
|
||||
// Delete or extract everything before endOffset.
|
||||
|
||||
if (endOffset >= 0)
|
||||
{
|
||||
nsMutationGuard guard;
|
||||
nsCOMPtr<nsIDOMCharacterData> cutNode;
|
||||
/* The Range spec clearly states clones get cut and original nodes
|
||||
remain behind, so use false as the last parameter.
|
||||
*/
|
||||
rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(!guard.Mutated(1) ||
|
||||
ValidateCurrentNode(this, iter));
|
||||
nodeToResult = do_QueryInterface(cutNode);
|
||||
}
|
||||
|
||||
nsMutationGuard guard;
|
||||
nsCOMPtr<nsIDOMCharacterData> cutNode;
|
||||
/* The Range spec clearly states clones get cut and original nodes
|
||||
remain behind, so use false as the last parameter.
|
||||
*/
|
||||
rv = SplitDataNode(charData, endOffset, getter_AddRefs(cutNode),
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(!guard.Mutated(1) ||
|
||||
ValidateCurrentNode(this, iter));
|
||||
nodeToResult = do_QueryInterface(cutNode);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -2037,8 +2162,7 @@ nsRange::CutContents(DocumentFragment** aFragment)
|
|||
if (node && node->IsElement() &&
|
||||
((node == endContainer && endOffset == 0) ||
|
||||
(node == startContainer &&
|
||||
int32_t(node->AsElement()->GetChildCount()) == startOffset)))
|
||||
{
|
||||
node->AsElement()->GetChildCount() == startOffset))) {
|
||||
if (retval) {
|
||||
ErrorResult rv;
|
||||
nodeToResult = node->CloneNode(false, rv);
|
||||
|
@ -2183,7 +2307,7 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
|
|||
}
|
||||
|
||||
nsINode *ourNode, *otherNode;
|
||||
int32_t ourOffset, otherOffset;
|
||||
uint32_t ourOffset, otherOffset;
|
||||
|
||||
switch (aHow) {
|
||||
case nsIDOMRange::START_TO_START:
|
||||
|
@ -2221,8 +2345,10 @@ nsRange::CompareBoundaryPoints(uint16_t aHow, nsRange& aOtherRange,
|
|||
return 0;
|
||||
}
|
||||
|
||||
return nsContentUtils::ComparePoints(ourNode, ourOffset,
|
||||
otherNode, otherOffset);
|
||||
return nsContentUtils::ComparePoints(ourNode,
|
||||
static_cast<int32_t>(ourOffset),
|
||||
otherNode,
|
||||
static_cast<int32_t>(otherOffset));
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
|
@ -2339,8 +2465,7 @@ nsRange::CloneContents(ErrorResult& aRv)
|
|||
bool deepClone = !node->IsElement() ||
|
||||
(!(node == mEndParent && mEndOffset == 0) &&
|
||||
!(node == mStartParent &&
|
||||
mStartOffset ==
|
||||
int32_t(node->AsElement()->GetChildCount())));
|
||||
mStartOffset == node->AsElement()->GetChildCount()));
|
||||
|
||||
// Clone the current subtree!
|
||||
|
||||
|
@ -2370,7 +2495,7 @@ nsRange::CloneContents(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (dataLength > (uint32_t)mEndOffset)
|
||||
if (dataLength > mEndOffset)
|
||||
{
|
||||
aRv = charData->DeleteData(mEndOffset, dataLength - mEndOffset);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -2528,7 +2653,7 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
int32_t tStartOffset = StartOffset();
|
||||
uint32_t tStartOffset = StartOffset();
|
||||
|
||||
nsCOMPtr<nsINode> tStartContainer = GetStartContainer(aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -2589,18 +2714,20 @@ nsRange::InsertNode(nsINode& aNode, ErrorResult& aRv)
|
|||
// We might need to update the end to include the new node (bug 433662).
|
||||
// Ideally we'd only do this if needed, but it's tricky to know when it's
|
||||
// needed in advance (bug 765799).
|
||||
int32_t newOffset;
|
||||
uint32_t newOffset;
|
||||
|
||||
if (referenceNode) {
|
||||
newOffset = IndexOf(referenceNode);
|
||||
int32_t indexInParent = IndexOf(referenceNode);
|
||||
if (NS_WARN_IF(indexInParent < 0)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
newOffset = static_cast<uint32_t>(indexInParent);
|
||||
} else {
|
||||
uint32_t length;
|
||||
aRv = tChildList->GetLength(&length);
|
||||
aRv = tChildList->GetLength(&newOffset);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
newOffset = length;
|
||||
}
|
||||
|
||||
if (aNode.NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
||||
|
@ -2956,10 +3083,15 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
|
|||
nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
nsRange* aRange,
|
||||
nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset,
|
||||
bool aClampToEdge, bool aFlushLayout)
|
||||
{
|
||||
// Currently, this method is called with start of end offset of nsRange.
|
||||
// So, they must be between 0 - INT32_MAX.
|
||||
MOZ_ASSERT(IsValidOffset(aStartOffset));
|
||||
MOZ_ASSERT(IsValidOffset(aEndOffset));
|
||||
|
||||
// Hold strong pointers across the flush
|
||||
nsCOMPtr<nsINode> startContainer = aStartParent;
|
||||
nsCOMPtr<nsINode> endContainer = aEndParent;
|
||||
|
@ -2990,13 +3122,15 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
|||
if (textFrame) {
|
||||
int32_t outOffset;
|
||||
nsIFrame* outFrame;
|
||||
textFrame->GetChildFrameContainingOffset(aStartOffset, false,
|
||||
&outOffset, &outFrame);
|
||||
textFrame->GetChildFrameContainingOffset(
|
||||
static_cast<int32_t>(aStartOffset), false,
|
||||
&outOffset, &outFrame);
|
||||
if (outFrame) {
|
||||
nsIFrame* relativeTo =
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
|
||||
nsRect r = outFrame->GetRectRelativeToSelf();
|
||||
ExtractRectFromOffset(outFrame, aStartOffset, &r, false, aClampToEdge);
|
||||
ExtractRectFromOffset(outFrame, static_cast<int32_t>(aStartOffset),
|
||||
&r, false, aClampToEdge);
|
||||
r.width = 0;
|
||||
r = nsLayoutUtils::TransformFrameRectToAncestor(outFrame, r, relativeTo);
|
||||
aCollector->AddRect(r);
|
||||
|
@ -3015,12 +3149,14 @@ nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
|||
if (content->IsNodeOfType(nsINode::eTEXT)) {
|
||||
if (node == startContainer) {
|
||||
int32_t offset = startContainer == endContainer ?
|
||||
aEndOffset : content->GetText()->GetLength();
|
||||
GetPartialTextRect(aCollector, aTextList, content, aStartOffset, offset,
|
||||
static_cast<int32_t>(aEndOffset) : content->GetText()->GetLength();
|
||||
GetPartialTextRect(aCollector, aTextList, content,
|
||||
static_cast<int32_t>(aStartOffset), offset,
|
||||
aClampToEdge, aFlushLayout);
|
||||
continue;
|
||||
} else if (node == endContainer) {
|
||||
GetPartialTextRect(aCollector, aTextList, content, 0, aEndOffset,
|
||||
GetPartialTextRect(aCollector, aTextList, content,
|
||||
0, static_cast<int32_t>(aEndOffset),
|
||||
aClampToEdge, aFlushLayout);
|
||||
continue;
|
||||
}
|
||||
|
@ -3397,7 +3533,7 @@ ElementIsVisibleNoFlush(Element* aElement)
|
|||
static void
|
||||
AppendTransformedText(InnerTextAccumulator& aResult,
|
||||
nsGenericDOMDataNode* aTextNode,
|
||||
int32_t aStart, int32_t aEnd)
|
||||
uint32_t aStart, uint32_t aEnd)
|
||||
{
|
||||
nsIFrame* frame = aTextNode->GetPrimaryFrame();
|
||||
if (!IsVisibleAndNotInReplacedElement(frame)) {
|
||||
|
@ -3506,7 +3642,7 @@ nsRange::GetInnerTextNoFlush(DOMString& aValue, ErrorResult& aError,
|
|||
if (aEndParent->IsNodeOfType(nsINode::eTEXT)) {
|
||||
endState = AT_NODE;
|
||||
} else {
|
||||
if (uint32_t(aEndOffset) < aEndParent->GetChildCount()) {
|
||||
if (aEndOffset < aEndParent->GetChildCount()) {
|
||||
endNode = aEndParent->GetChildAt(aEndOffset);
|
||||
endState = AT_NODE;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace mozilla {
|
|||
class ErrorResult;
|
||||
namespace dom {
|
||||
struct ClientRectsAndTexts;
|
||||
class DocGroup;
|
||||
class DocumentFragment;
|
||||
class DOMRect;
|
||||
class DOMRectList;
|
||||
|
@ -38,6 +39,7 @@ class nsRange final : public nsIDOMRange,
|
|||
public nsWrapperCache
|
||||
{
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
typedef mozilla::dom::DocGroup DocGroup;
|
||||
typedef mozilla::dom::DOMRect DOMRect;
|
||||
typedef mozilla::dom::DOMRectList DOMRectList;
|
||||
|
||||
|
@ -46,14 +48,14 @@ class nsRange final : public nsIDOMRange,
|
|||
public:
|
||||
explicit nsRange(nsINode* aNode);
|
||||
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, uint32_t aEndOffset,
|
||||
nsRange** aRange);
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, int32_t aEndOffset,
|
||||
static nsresult CreateRange(nsIDOMNode* aStartParent, uint32_t aStartOffset,
|
||||
nsIDOMNode* aEndParent, uint32_t aEndOffset,
|
||||
nsIDOMRange** aRange);
|
||||
static nsresult CreateRange(nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
static nsresult CreateRange(nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset,
|
||||
nsRange** aRange);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -91,12 +93,12 @@ public:
|
|||
return mEndParent;
|
||||
}
|
||||
|
||||
int32_t StartOffset() const
|
||||
uint32_t StartOffset() const
|
||||
{
|
||||
return mStartOffset;
|
||||
}
|
||||
|
||||
int32_t EndOffset() const
|
||||
uint32_t EndOffset() const
|
||||
{
|
||||
return mEndOffset;
|
||||
}
|
||||
|
@ -148,19 +150,74 @@ public:
|
|||
|
||||
nsINode* GetCommonAncestor() const;
|
||||
void Reset();
|
||||
nsresult SetStart(nsINode* aParent, int32_t aOffset);
|
||||
nsresult SetEnd(nsINode* aParent, int32_t aOffset);
|
||||
|
||||
/**
|
||||
* SetStart() and SetEnd() sets start point or end point separately.
|
||||
* However, this is expensive especially when it's a range of Selection.
|
||||
* When you set both start and end of a range, you should use
|
||||
* SetStartAndEnd() instead.
|
||||
*/
|
||||
nsresult SetStart(nsINode* aParent, uint32_t aOffset);
|
||||
nsresult SetEnd(nsINode* aParent, uint32_t aOffset);
|
||||
|
||||
already_AddRefed<nsRange> CloneRange() const;
|
||||
|
||||
nsresult Set(nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset)
|
||||
{
|
||||
// If this starts being hot, we may be able to optimize this a bit,
|
||||
// but for now just set start and end separately.
|
||||
nsresult rv = SetStart(aStartParent, aStartOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
/**
|
||||
* SetStartAndEnd() works similar to call both SetStart() and SetEnd().
|
||||
* Different from calls them separately, this does nothing if either
|
||||
* the start point or the end point is invalid point.
|
||||
* If the specified start point is after the end point, the range will be
|
||||
* collapsed at the end point. Similarly, if they are in different root,
|
||||
* the range will be collapsed at the end point.
|
||||
*/
|
||||
nsresult SetStartAndEnd(nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset);
|
||||
|
||||
return SetEnd(aEndParent, aEndOffset);
|
||||
/**
|
||||
* CollapseTo() works similar to call both SetStart() and SetEnd() with
|
||||
* same node and offset. This just calls SetStartAndParent() to set
|
||||
* collapsed range at aParent and aOffset.
|
||||
*/
|
||||
nsresult CollapseTo(nsINode* aParent, uint32_t aOffset)
|
||||
{
|
||||
return SetStartAndEnd(aParent, aOffset, aParent, aOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves node and offset for setting start or end of a range to
|
||||
* before or after aNode.
|
||||
*/
|
||||
static nsINode* GetParentAndOffsetAfter(nsINode* aNode, uint32_t* aOffset)
|
||||
{
|
||||
MOZ_ASSERT(aNode);
|
||||
MOZ_ASSERT(aOffset);
|
||||
*aOffset = 0;
|
||||
nsINode* parentNode = aNode->GetParentNode();
|
||||
if (!parentNode) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t indexInParent = parentNode->IndexOf(aNode);
|
||||
if (NS_WARN_IF(indexInParent < 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
*aOffset = static_cast<uint32_t>(indexInParent) + 1;
|
||||
return parentNode;
|
||||
}
|
||||
static nsINode* GetParentAndOffsetBefore(nsINode* aNode, uint32_t* aOffset)
|
||||
{
|
||||
MOZ_ASSERT(aNode);
|
||||
MOZ_ASSERT(aOffset);
|
||||
*aOffset = 0;
|
||||
nsINode* parentNode = aNode->GetParentNode();
|
||||
if (!parentNode) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t indexInParent = parentNode->IndexOf(aNode);
|
||||
if (NS_WARN_IF(indexInParent < 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
*aOffset = static_cast<uint32_t>(indexInParent);
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
|
||||
|
@ -225,6 +282,7 @@ public:
|
|||
|
||||
nsINode* GetParentObject() const { return mOwner; }
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override final;
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
private:
|
||||
// no copy's or assigns
|
||||
|
@ -274,8 +332,8 @@ public:
|
|||
static void CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
|
||||
mozilla::dom::DOMStringList* aTextList,
|
||||
nsRange* aRange,
|
||||
nsINode* aStartParent, int32_t aStartOffset,
|
||||
nsINode* aEndParent, int32_t aEndOffset,
|
||||
nsINode* aStartParent, uint32_t aStartOffset,
|
||||
nsINode* aEndParent, uint32_t aEndOffset,
|
||||
bool aClampToEdge, bool aFlushLayout);
|
||||
|
||||
/**
|
||||
|
@ -297,12 +355,24 @@ protected:
|
|||
void UnregisterCommonAncestor(nsINode* aNode);
|
||||
nsINode* IsValidBoundary(nsINode* aNode);
|
||||
|
||||
/**
|
||||
* XXX nsRange should accept 0 - UINT32_MAX as offset. However, users of
|
||||
* nsRange treat offset as int32_t. Additionally, some other internal
|
||||
* APIs like nsINode::IndexOf() use int32_t. Therefore, nsRange should
|
||||
* accept only 0 - INT32_MAX as valid offset for now.
|
||||
*/
|
||||
static bool IsValidOffset(uint32_t aOffset)
|
||||
{
|
||||
return aOffset <= INT32_MAX;
|
||||
}
|
||||
static bool IsValidOffset(nsINode* aNode, uint32_t aOffset);
|
||||
|
||||
// CharacterDataChanged set aNotInsertedYet to true to disable an assertion
|
||||
// and suppress re-registering a range common ancestor node since
|
||||
// the new text node of a splitText hasn't been inserted yet.
|
||||
// CharacterDataChanged does the re-registering when needed.
|
||||
void DoSetRange(nsINode* aStartN, int32_t aStartOffset,
|
||||
nsINode* aEndN, int32_t aEndOffset,
|
||||
void DoSetRange(nsINode* aStartN, uint32_t aStartOffset,
|
||||
nsINode* aEndN, uint32_t aEndOffset,
|
||||
nsINode* aRoot, bool aNotInsertedYet = false);
|
||||
|
||||
/**
|
||||
|
@ -350,8 +420,8 @@ protected:
|
|||
nsCOMPtr<nsINode> mStartParent;
|
||||
nsCOMPtr<nsINode> mEndParent;
|
||||
RefPtr<mozilla::dom::Selection> mSelection;
|
||||
int32_t mStartOffset;
|
||||
int32_t mEndOffset;
|
||||
uint32_t mStartOffset;
|
||||
uint32_t mEndOffset;
|
||||
|
||||
bool mIsPositioned : 1;
|
||||
bool mMaySpanAnonymousSubtrees : 1;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsStyledElement.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
|
@ -39,7 +40,6 @@ nsStyledElement::ParseAttribute(int32_t aNamespaceID,
|
|||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
|
||||
SetMayHaveStyle();
|
||||
ParseStyleAttribute(aValue, aResult, false);
|
||||
return true;
|
||||
}
|
||||
|
@ -48,6 +48,22 @@ nsStyledElement::ParseAttribute(int32_t aNamespaceID,
|
|||
aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::style) {
|
||||
if (aValue) {
|
||||
SetMayHaveStyle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
|
||||
const nsAString* aSerialized,
|
||||
|
@ -56,6 +72,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
|
|||
SetMayHaveStyle();
|
||||
bool modification = false;
|
||||
nsAttrValue oldValue;
|
||||
bool oldValueSet = false;
|
||||
|
||||
bool hasListeners = aNotify &&
|
||||
nsContentUtils::HasMutationListeners(this,
|
||||
|
@ -75,6 +92,7 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
|
|||
oldValueStr);
|
||||
if (modification) {
|
||||
oldValue.SetTo(oldValueStr);
|
||||
oldValueSet = true;
|
||||
}
|
||||
}
|
||||
else if (aNotify && IsInUncomposedDoc()) {
|
||||
|
@ -88,9 +106,12 @@ nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
|
|||
static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
|
||||
static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
|
||||
|
||||
nsIDocument* document = GetComposedDoc();
|
||||
mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
|
||||
return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
|
||||
oldValue, attrValue, modType, hasListeners,
|
||||
aNotify, kDontCallAfterSetAttr);
|
||||
oldValueSet ? &oldValue : nullptr, attrValue, modType,
|
||||
hasListeners, aNotify, kDontCallAfterSetAttr,
|
||||
document, updateBatch);
|
||||
}
|
||||
|
||||
DeclarationBlock*
|
||||
|
@ -141,7 +162,9 @@ nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc)
|
|||
ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
|
||||
// Don't bother going through SetInlineStyleDeclaration; we don't
|
||||
// want to fire off mutation events or document notifications anyway
|
||||
nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
|
||||
bool oldValueSet;
|
||||
nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
|
||||
&oldValueSet);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,10 @@ protected:
|
|||
* document.
|
||||
*/
|
||||
nsresult ReparseStyleAttribute(bool aForceInDataDoc);
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsStyledElement, NS_STYLED_ELEMENT_IID)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifdef DEBUG
|
||||
#include "nsRange.h"
|
||||
#endif
|
||||
#include "nsDocument.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -155,6 +156,12 @@ void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
bool
|
||||
nsTextNode::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
|
||||
{
|
||||
return nsDocument::IsWebComponentsEnabled(aCx, aObject);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsTextNode::List(FILE* out, int32_t aIndent) const
|
||||
|
|
|
@ -75,6 +75,10 @@ public:
|
|||
|
||||
virtual nsIDOMNode* AsDOMNode() override { return this; }
|
||||
|
||||
// Need to have a copy here because including nsDocument.h in this file will
|
||||
// fail to build on Windows.
|
||||
static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out, int32_t aIndent) const override;
|
||||
virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
|
||||
|
|
|
@ -180,13 +180,13 @@ nsWindowRoot::GetContextForEventHandlers(nsresult* aRv)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
nsWindowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119
|
||||
// To keep mWindow alive
|
||||
aVisitor.mItemData = static_cast<nsISupports *>(mWindow);
|
||||
aVisitor.mParentTarget = mParent;
|
||||
aVisitor.SetParentTarget(mParent, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsIDOMElement.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsElementTable.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
@ -27,7 +28,6 @@
|
|||
#include "nsEscape.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLWBrkCIID.h"
|
||||
#include "nsIScriptElement.h"
|
||||
|
@ -667,18 +667,7 @@ nsXHTMLContentSerializer::LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aNa
|
|||
aName == nsGkAtoms::html) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
if (parserService) {
|
||||
bool res;
|
||||
parserService->
|
||||
IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return mAddSpace;
|
||||
return nsHTMLElement::IsBlock(nsHTMLTags::CaseSensitiveAtomTagToId(aName));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -748,31 +737,15 @@ nsXHTMLContentSerializer::LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aNa
|
|||
(aName == nsGkAtoms::tr) ||
|
||||
(aName == nsGkAtoms::th) ||
|
||||
(aName == nsGkAtoms::td) ||
|
||||
(aName == nsGkAtoms::pre) ||
|
||||
(aName == nsGkAtoms::title) ||
|
||||
(aName == nsGkAtoms::li) ||
|
||||
(aName == nsGkAtoms::dt) ||
|
||||
(aName == nsGkAtoms::dd) ||
|
||||
(aName == nsGkAtoms::blockquote) ||
|
||||
(aName == nsGkAtoms::select) ||
|
||||
(aName == nsGkAtoms::option) ||
|
||||
(aName == nsGkAtoms::p) ||
|
||||
(aName == nsGkAtoms::map) ||
|
||||
(aName == nsGkAtoms::div)) {
|
||||
(aName == nsGkAtoms::map)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
|
||||
if (parserService) {
|
||||
bool res;
|
||||
parserService->
|
||||
IsBlock(parserService->HTMLCaseSensitiveAtomTagToId(aName), res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return nsHTMLElement::IsBlock(nsHTMLTags::CaseSensitiveAtomTagToId(aName));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsElementTable.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsString.h"
|
||||
|
@ -994,14 +994,9 @@ ElementNeedsSeparateEndTag(Element* aElement, Element* aOriginalElement)
|
|||
// HTML container tags should have a separate end tag even if empty, per spec.
|
||||
// See
|
||||
// https://w3c.github.io/DOM-Parsing/#dfn-concept-xml-serialization-algorithm
|
||||
bool isHTMLContainer = true; // Default in case we get no parser service.
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (parserService) {
|
||||
nsIAtom* localName = aElement->NodeInfo()->NameAtom();
|
||||
parserService->IsContainer(
|
||||
parserService->HTMLCaseSensitiveAtomTagToId(localName),
|
||||
isHTMLContainer);
|
||||
}
|
||||
nsIAtom* localName = aElement->NodeInfo()->NameAtom();
|
||||
bool isHTMLContainer =
|
||||
nsHTMLElement::IsContainer(nsHTMLTags::CaseSensitiveAtomTagToId(localName));
|
||||
return isHTMLContainer;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ support-files =
|
|||
file_bug1209621.xul
|
||||
fileconstructor_file.png
|
||||
frame_bug814638.xul
|
||||
frame_registerElement_content.html
|
||||
registerElement_ep.js
|
||||
frame_custom_element_content.html
|
||||
custom_element_ep.js
|
||||
host_bug814638.xul
|
||||
window_nsITextInputProcessor.xul
|
||||
title_window.xul
|
||||
|
@ -62,8 +62,8 @@ support-files = ../file_bug357450.js
|
|||
[test_bug1139964.xul]
|
||||
[test_bug1209621.xul]
|
||||
[test_cpows.xul]
|
||||
[test_registerElement_content.xul]
|
||||
[test_registerElement_ep.xul]
|
||||
[test_custom_element_content.xul]
|
||||
[test_custom_element_ep.xul]
|
||||
[test_domparsing.xul]
|
||||
[test_fileconstructor.xul]
|
||||
[test_fileconstructor_tempfile.xul]
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
var proto = Object.create(HTMLElement.prototype);
|
||||
proto.magicNumber = 42;
|
||||
proto.connectedCallback = function() {
|
||||
finishTest(this.magicNumber === 42);
|
||||
};
|
||||
document.registerElement("x-foo", { prototype: proto });
|
||||
|
||||
document.firstChild.appendChild(document.createElement("x-foo"));
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
||||
-->
|
||||
<window title="Mozilla Bug 1130028"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
|
||||
target="_blank">Mozilla Bug 1130028</a>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
/** Test for Bug 1130028 **/
|
||||
var connectedCallbackCount = 0;
|
||||
|
||||
// Callback should be called only once by element created in content.
|
||||
function connectedCallbackCalled() {
|
||||
connectedCallbackCount++;
|
||||
is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
|
||||
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
var frame = $("frame");
|
||||
|
||||
var c = frame.contentDocument.registerElement("x-foo");
|
||||
var elem = new c();
|
||||
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
|
||||
|
||||
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
|
||||
proto.magicNumber = 42;
|
||||
proto.connectedCallback = connectedCallbackCalled;
|
||||
|
||||
frame.contentDocument.registerElement("x-bar", { prototype: proto });
|
||||
is(connectedCallbackCount, 1, "Connected callback should be called by element created in content.");
|
||||
|
||||
var element = frame.contentDocument.createElement("x-bar");
|
||||
is(element.magicNumber, 42, "Should be able to see the custom prototype on created element.");
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
||||
-->
|
||||
<window title="Mozilla Bug 1130028"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
|
||||
target="_blank">Mozilla Bug 1130028</a>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/** Test for Bug 1130028 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function finishTest(canSeePrototype) {
|
||||
ok(true, "connectedCallback called when reigsterElement was called with an extended principal.");
|
||||
ok(canSeePrototype, "connectedCallback should be able to see custom prototype.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
var frame = $("frame");
|
||||
|
||||
// Create a sandbox with an extended principal then run a script that registers a custom element in the sandbox.
|
||||
var sandbox = Components.utils.Sandbox([frame.contentWindow], { sandboxPrototype: frame.contentWindow });
|
||||
sandbox.finishTest = finishTest;
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/registerElement_ep.js", sandbox);
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -630,7 +630,7 @@ skip-if = toolkit == 'android' #bug 904183
|
|||
[test_document.all_unqualified.html]
|
||||
[test_document_constructor.html]
|
||||
[test_document_importNode_document.html]
|
||||
[test_document_register.html]
|
||||
[test_custom_element.html]
|
||||
[test_domcursor.html]
|
||||
[test_domparser_null_char.html]
|
||||
[test_domparsing.html]
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function startTests() {
|
||||
var c = document.getElementById("fooframe").contentDocument.registerElement("x-foo");
|
||||
var elem = new c();
|
||||
var frame = document.getElementById("fooframe");
|
||||
class XFoo extends frame.contentWindow.HTMLElement {};
|
||||
frame.contentWindow.customElements.define("x-foo", XFoo);
|
||||
var elem = new XFoo();
|
||||
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
|
||||
|
||||
var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
|
||||
|
|
|
@ -612,7 +612,7 @@ function testOutsideShadowDOM() {
|
|||
is(records.length, 1);
|
||||
is(records[0].type, "attributes", "Should have got attributes");
|
||||
observer.disconnect();
|
||||
then(testInsideShadowDOM);
|
||||
then(testMarquee);
|
||||
});
|
||||
m.observe(div, {
|
||||
attributes: true,
|
||||
|
@ -628,32 +628,6 @@ function testOutsideShadowDOM() {
|
|||
div.setAttribute("foo", "bar");
|
||||
}
|
||||
|
||||
function testInsideShadowDOM() {
|
||||
var m = new M(function(records, observer) {
|
||||
is(records.length, 4);
|
||||
is(records[0].type, "childList");
|
||||
is(records[1].type, "attributes");
|
||||
is(records[2].type, "characterData");
|
||||
is(records[3].type, "childList");
|
||||
observer.disconnect();
|
||||
then(testMarquee);
|
||||
});
|
||||
var sr = div.createShadowRoot();
|
||||
m.observe(sr, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
sr.innerHTML = "<div" + ">text</" + "div>";
|
||||
sr.firstChild.setAttribute("foo", "bar");
|
||||
sr.firstChild.firstChild.data = "text2";
|
||||
sr.firstChild.appendChild(document.createElement("div"));
|
||||
div.setAttribute("foo", "bar2");
|
||||
|
||||
}
|
||||
|
||||
function testMarquee() {
|
||||
var m = new M(function(records, observer) {
|
||||
is(records.length, 1);
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include "nsContentCreatorFunctions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
@ -3406,28 +3406,6 @@ GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
|||
return true;
|
||||
}
|
||||
|
||||
CustomElementReactionsStack*
|
||||
GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
// This might not be the right object, if there are wrappers. Unwrap if we can.
|
||||
JSObject* obj = js::CheckedUnwrap(aObj);
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsGlobalWindow* window = xpc::WindowGlobalOrNull(obj);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DocGroup* docGroup = window->AsInner()->GetDocGroup();
|
||||
if (!docGroup) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return docGroup->CustomElementReactionsStack();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/dom.html#htmlconstructor
|
||||
already_AddRefed<nsGenericHTMLElement>
|
||||
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
|
||||
|
@ -3493,13 +3471,7 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
|
|||
// Step 5.
|
||||
// If the definition is for a customized built-in element, the localName
|
||||
// should be defined in the specification.
|
||||
nsIParserService* parserService = nsContentUtils::GetParserService();
|
||||
if (!parserService) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
tag = parserService->HTMLCaseSensitiveAtomTagToId(definition->mLocalName);
|
||||
tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
|
||||
if (tag == eHTMLTag_userdefined) {
|
||||
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
||||
return nullptr;
|
||||
|
|
|
@ -3422,12 +3422,6 @@ bool
|
|||
GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
|
||||
JS::MutableHandle<JSObject*> aDesiredProto);
|
||||
|
||||
// Get the CustomElementReactionsStack for the docgroup of the global
|
||||
// of the underlying object of aObj. This can be null if aObj can't
|
||||
// be CheckUnwrapped, or if the global of the result has no docgroup
|
||||
// (e.g. because it's not a Window global).
|
||||
CustomElementReactionsStack*
|
||||
GetCustomElementReactionsStack(JS::Handle<JSObject*> aObj);
|
||||
// This function is expected to be called from the constructor function for an
|
||||
// HTML element interface; the global/callargs need to be whatever was passed to
|
||||
// that constructor function.
|
||||
|
|
|
@ -7680,14 +7680,14 @@ class CGPerSignatureCall(CGThing):
|
|||
|
||||
if (idlNode.getExtendedAttribute('CEReactions') is not None and
|
||||
not getter):
|
||||
cgThings.append(CGGeneric(fill(
|
||||
cgThings.append(CGGeneric(dedent(
|
||||
"""
|
||||
CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(${obj});
|
||||
Maybe<AutoCEReaction> ceReaction;
|
||||
if (reactionsStack) {
|
||||
ceReaction.emplace(reactionsStack, cx);
|
||||
Maybe<AutoCEReaction> ceReaction;
|
||||
DocGroup* docGroup = self->GetDocGroup();
|
||||
if (docGroup) {
|
||||
ceReaction.emplace(docGroup->CustomElementReactionsStack(), cx);
|
||||
}
|
||||
""", obj=objectName)))
|
||||
""")))
|
||||
|
||||
# If this is a method that was generated by a maplike/setlike
|
||||
# interface, use the maplike/setlike generator to fill in the body.
|
||||
|
@ -13786,6 +13786,8 @@ class CGForwardDeclarations(CGWrapper):
|
|||
builder.add(d.nativeType + "Atoms", isStruct=True)
|
||||
for t in getTypesFromDescriptor(d):
|
||||
builder.forwardDeclareForType(t, config)
|
||||
if d.hasCEReactions():
|
||||
builder.addInMozillaDom("DocGroup")
|
||||
|
||||
for d in dictionaries:
|
||||
if len(d.members) > 0:
|
||||
|
@ -13857,18 +13859,15 @@ class CGBindingRoot(CGThing):
|
|||
iface = desc.interface
|
||||
return any(m.getExtendedAttribute("Deprecated") for m in iface.members + [iface])
|
||||
|
||||
def descriptorHasCEReactions(desc):
|
||||
iface = desc.interface
|
||||
return any(m.getExtendedAttribute("CEReactions") for m in iface.members + [iface])
|
||||
|
||||
bindingHeaders["nsIDocument.h"] = any(
|
||||
descriptorDeprecated(d) for d in descriptors)
|
||||
bindingHeaders["mozilla/Preferences.h"] = any(
|
||||
descriptorRequiresPreferences(d) for d in descriptors)
|
||||
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
|
||||
d.concrete and d.proxy for d in descriptors)
|
||||
bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = any(
|
||||
descriptorHasCEReactions(d) for d in descriptors)
|
||||
hasCEReactions = any(d.hasCEReactions() for d in descriptors)
|
||||
bindingHeaders["mozilla/dom/CustomElementRegistry.h"] = hasCEReactions
|
||||
bindingHeaders["mozilla/dom/DocGroup.h"] = hasCEReactions
|
||||
|
||||
def descriptorHasChromeOnly(desc):
|
||||
ctor = desc.interface.ctor()
|
||||
|
@ -14704,6 +14703,12 @@ class CGBindingImplClass(CGClass):
|
|||
breakAfterReturnDecl=" ",
|
||||
override=descriptor.wrapperCache,
|
||||
body=self.getWrapObjectBody()))
|
||||
if descriptor.hasCEReactions():
|
||||
self.methodDecls.insert(0,
|
||||
ClassMethod("GetDocGroup", "DocGroup*", [],
|
||||
const=True,
|
||||
breakAfterReturnDecl=" ",
|
||||
body=self.getGetDocGroupBody()))
|
||||
if wantGetParent:
|
||||
self.methodDecls.insert(0,
|
||||
ClassMethod("GetParentObject",
|
||||
|
@ -14724,6 +14729,9 @@ class CGBindingImplClass(CGClass):
|
|||
def getGetParentObjectBody(self):
|
||||
return None
|
||||
|
||||
def getGetDocGroupBody(self):
|
||||
return None
|
||||
|
||||
def deps(self):
|
||||
return self._deps
|
||||
|
||||
|
@ -14863,6 +14871,8 @@ class CGExampleRoot(CGThing):
|
|||
self.root = CGNamespace.build(["mozilla", "dom"], self.root)
|
||||
|
||||
builder = ForwardDeclarationBuilder()
|
||||
if descriptor.hasCEReactions():
|
||||
builder.addInMozillaDom("DocGroup")
|
||||
for member in descriptor.interface.members:
|
||||
if not member.isAttr() and not member.isMethod():
|
||||
continue
|
||||
|
@ -15174,7 +15184,7 @@ class CGJSImplClass(CGBindingImplClass):
|
|||
|
||||
private:
|
||||
RefPtr<${jsImplName}> mImpl;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsCOMPtr<nsIGlobalObject> mParent;
|
||||
|
||||
""",
|
||||
isupportsDecl=isupportsDecl,
|
||||
|
@ -15253,6 +15263,16 @@ class CGJSImplClass(CGBindingImplClass):
|
|||
def getGetParentObjectBody(self):
|
||||
return "return mParent;\n"
|
||||
|
||||
def getGetDocGroupBody(self):
|
||||
return dedent(
|
||||
"""
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
return window->GetDocGroup();
|
||||
""")
|
||||
|
||||
def getCreateFromExistingBody(self):
|
||||
# XXXbz we could try to get parts of this (e.g. the argument
|
||||
# conversions) auto-generated by somehow creating an IDLMethod and
|
||||
|
|
|
@ -631,6 +631,9 @@ class Descriptor(DescriptorProvider):
|
|||
not self.interface.isExposedInWindow()) or
|
||||
self.interface.isExposedInSomeButNotAllWorkers())
|
||||
|
||||
def hasCEReactions(self):
|
||||
return any(m.getExtendedAttribute("CEReactions") for m in self.interface.members)
|
||||
|
||||
def isExposedConditionally(self):
|
||||
return (self.interface.isExposedConditionally() or
|
||||
self.interface.isExposedInSomeButNotAllWorkers())
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
// this one for it, for ParentDict. Hopefully it won't begin to rely on it in more fundamental ways.
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class DocGroup;
|
||||
class TestExternalInterface;
|
||||
class Promise;
|
||||
} // namespace dom
|
||||
|
@ -46,8 +47,9 @@ public:
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_RENAMED_INTERFACE_IID)
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// We need a GetParentObject to make binding codegen happy
|
||||
// We need a GetParentObject and GetDocGroup to make binding codegen happy
|
||||
virtual nsISupports* GetParentObject();
|
||||
DocGroup* GetDocGroup() const;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsRenamedInterface, NS_RENAMED_INTERFACE_IID)
|
||||
|
@ -64,8 +66,9 @@ public:
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INDIRECTLY_IMPLEMENTED_INTERFACE_IID)
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// We need a GetParentObject to make binding codegen happy
|
||||
// We need a GetParentObject and GetDocGroup to make binding codegen happy
|
||||
virtual nsISupports* GetParentObject();
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
bool IndirectlyImplementedProperty();
|
||||
void IndirectlyImplementedProperty(bool);
|
||||
|
|
|
@ -980,11 +980,7 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
|
|||
|
||||
// Special case like <br contenteditable>
|
||||
if (!mRootContent->HasChildren()) {
|
||||
nsresult rv = aRange->SetStart(mRootContent, 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
rv = aRange->SetEnd(mRootContent, 0);
|
||||
nsresult rv = aRange->CollapseTo(mRootContent, 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2880,8 +2876,7 @@ ContentEventHandler::AdjustCollapsedRangeMaybeIntoTextNode(nsRange* aRange)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = aRange->Set(childNode, offsetInChildNode,
|
||||
childNode, offsetInChildNode);
|
||||
nsresult rv = aRange->CollapseTo(childNode, offsetInChildNode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -329,10 +329,10 @@ DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
|
|||
}
|
||||
|
||||
nsresult
|
||||
DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
DOMEventTargetHelper::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mCanHandle = true;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
aVisitor.SetParentTarget(nullptr, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -248,10 +248,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(DOMEventTargetHelper,
|
|||
|
||||
/* Use this macro to declare functions that forward the behavior of this
|
||||
* interface to another object.
|
||||
* This macro doesn't forward PreHandleEvent because sometimes subclasses
|
||||
* This macro doesn't forward GetEventTargetParent because sometimes subclasses
|
||||
* want to override it.
|
||||
*/
|
||||
#define NS_FORWARD_NSIDOMEVENTTARGET_NOPREHANDLEEVENT(_to) \
|
||||
#define NS_FORWARD_NSIDOMEVENTTARGET_NOGETEVENTTARGETPARENT(_to) \
|
||||
NS_IMETHOD AddEventListener(const nsAString & type, nsIDOMEventListener *listener, bool useCapture, bool wantsUntrusted, uint8_t _argc) { \
|
||||
return _to AddEventListener(type, listener, useCapture, wantsUntrusted, _argc); \
|
||||
} \
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/InternalMutationEvent.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
|
@ -157,18 +158,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
|
|||
tmp->mEvent->mTarget = nullptr;
|
||||
tmp->mEvent->mCurrentTarget = nullptr;
|
||||
tmp->mEvent->mOriginalTarget = nullptr;
|
||||
tmp->mEvent->mRelatedTarget = nullptr;
|
||||
switch (tmp->mEvent->mClass) {
|
||||
case eMouseEventClass:
|
||||
case eMouseScrollEventClass:
|
||||
case eWheelEventClass:
|
||||
case eSimpleGestureEventClass:
|
||||
case ePointerEventClass:
|
||||
tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
|
||||
break;
|
||||
case eDragEventClass: {
|
||||
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
|
||||
dragEvent->mDataTransfer = nullptr;
|
||||
dragEvent->relatedTarget = nullptr;
|
||||
break;
|
||||
}
|
||||
case eClipboardEventClass:
|
||||
|
@ -177,9 +171,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
|
|||
case eMutationEventClass:
|
||||
tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
|
||||
break;
|
||||
case eFocusEventClass:
|
||||
tmp->mEvent->AsFocusEvent()->mRelatedTarget = nullptr;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -195,21 +186,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
|
||||
switch (tmp->mEvent->mClass) {
|
||||
case eMouseEventClass:
|
||||
case eMouseScrollEventClass:
|
||||
case eWheelEventClass:
|
||||
case eSimpleGestureEventClass:
|
||||
case ePointerEventClass:
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
|
||||
cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
|
||||
break;
|
||||
case eDragEventClass: {
|
||||
WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
|
||||
cb.NoteXPCOMChild(dragEvent->mDataTransfer);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
|
||||
cb.NoteXPCOMChild(dragEvent->relatedTarget);
|
||||
break;
|
||||
}
|
||||
case eClipboardEventClass:
|
||||
|
@ -220,10 +202,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
|
|||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
|
||||
cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
|
||||
break;
|
||||
case eFocusEventClass:
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedTarget");
|
||||
cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->mRelatedTarget);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -298,6 +276,12 @@ Event::GetCurrentTarget() const
|
|||
return mEvent->GetCurrentDOMEventTarget();
|
||||
}
|
||||
|
||||
void
|
||||
Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath)
|
||||
{
|
||||
EventDispatcher::GetComposedPathFor(mEvent, aPath);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
|
||||
{
|
||||
|
|
|
@ -157,6 +157,8 @@ public:
|
|||
EventTarget* GetTarget() const;
|
||||
EventTarget* GetCurrentTarget() const;
|
||||
|
||||
void ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath);
|
||||
|
||||
uint16_t EventPhase() const;
|
||||
|
||||
// xpidl implementation
|
||||
|
|
|
@ -130,13 +130,6 @@ static bool IsEventTargetChrome(EventTarget* aEventTarget,
|
|||
return isChrome;
|
||||
}
|
||||
|
||||
|
||||
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
|
||||
#define NS_TARGET_CHAIN_CHECKED_IF_CHROME (1 << 3)
|
||||
#define NS_TARGET_CHAIN_IS_CHROME_CONTENT (1 << 4)
|
||||
|
||||
// EventTargetChainItem represents a single item in the event target chain.
|
||||
class EventTargetChainItem
|
||||
{
|
||||
|
@ -144,8 +137,7 @@ private:
|
|||
explicit EventTargetChainItem(EventTarget* aTarget);
|
||||
public:
|
||||
EventTargetChainItem()
|
||||
: mFlags(0)
|
||||
, mItemFlags(0)
|
||||
: mItemFlags(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -153,7 +145,8 @@ public:
|
|||
EventTarget* aTarget,
|
||||
EventTargetChainItem* aChild = nullptr)
|
||||
{
|
||||
MOZ_ASSERT(!aChild || &aChain.ElementAt(aChain.Length() - 1) == aChild);
|
||||
// The last item which can handle the event must be aChild.
|
||||
MOZ_ASSERT(GetLastCanHandleEventTarget(aChain) == aChild);
|
||||
return new (aChain.AppendElement()) EventTargetChainItem(aTarget);
|
||||
}
|
||||
|
||||
|
@ -165,6 +158,38 @@ public:
|
|||
aChain.RemoveElementAt(lastIndex);
|
||||
}
|
||||
|
||||
static EventTargetChainItem* GetFirstCanHandleEventTarget(
|
||||
nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
return &aChain[GetFirstCanHandleEventTargetIdx(aChain)];
|
||||
}
|
||||
|
||||
static uint32_t GetFirstCanHandleEventTargetIdx(nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
// aChain[i].PreHandleEventOnly() = true only when the target element wants
|
||||
// PreHandleEvent and set mCanHandle=false. So we find the first element
|
||||
// which can handle the event.
|
||||
for (uint32_t i = 0; i < aChain.Length(); ++i) {
|
||||
if (!aChain[i].PreHandleEventOnly()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EventTargetChainItem* GetLastCanHandleEventTarget(
|
||||
nsTArray<EventTargetChainItem>& aChain)
|
||||
{
|
||||
// Fine the last item which can handle the event.
|
||||
for (int32_t i = aChain.Length() - 1; i >= 0; --i) {
|
||||
if (!aChain[i].PreHandleEventOnly()) {
|
||||
return &aChain[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsValid()
|
||||
{
|
||||
NS_WARNING_ASSERTION(!!(mTarget), "Event target is not valid!");
|
||||
|
@ -183,44 +208,82 @@ public:
|
|||
|
||||
void SetForceContentDispatch(bool aForce)
|
||||
{
|
||||
if (aForce) {
|
||||
mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
|
||||
}
|
||||
mFlags.mForceContentDispatch = aForce;
|
||||
}
|
||||
|
||||
bool ForceContentDispatch()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
|
||||
return mFlags.mForceContentDispatch;
|
||||
}
|
||||
|
||||
void SetWantsWillHandleEvent(bool aWants)
|
||||
{
|
||||
if (aWants) {
|
||||
mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
|
||||
}
|
||||
mFlags.mWantsWillHandleEvent = aWants;
|
||||
}
|
||||
|
||||
bool WantsWillHandleEvent()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
|
||||
return mFlags.mWantsWillHandleEvent;
|
||||
}
|
||||
|
||||
void SetWantsPreHandleEvent(bool aWants)
|
||||
{
|
||||
mFlags.mWantsPreHandleEvent = aWants;
|
||||
}
|
||||
|
||||
bool WantsPreHandleEvent()
|
||||
{
|
||||
return mFlags.mWantsPreHandleEvent;
|
||||
}
|
||||
|
||||
void SetPreHandleEventOnly(bool aWants)
|
||||
{
|
||||
mFlags.mPreHandleEventOnly = aWants;
|
||||
}
|
||||
|
||||
bool PreHandleEventOnly()
|
||||
{
|
||||
return mFlags.mPreHandleEventOnly;
|
||||
}
|
||||
|
||||
void SetRootOfClosedTree(bool aSet)
|
||||
{
|
||||
mFlags.mRootOfClosedTree = aSet;
|
||||
}
|
||||
|
||||
bool IsRootOfClosedTree()
|
||||
{
|
||||
return mFlags.mRootOfClosedTree;
|
||||
}
|
||||
|
||||
void SetIsSlotInClosedTree(bool aSet)
|
||||
{
|
||||
mFlags.mIsSlotInClosedTree = aSet;
|
||||
}
|
||||
|
||||
bool IsSlotInClosedTree()
|
||||
{
|
||||
return mFlags.mIsSlotInClosedTree;
|
||||
}
|
||||
|
||||
void SetIsChromeHandler(bool aSet)
|
||||
{
|
||||
mFlags.mIsChromeHandler = aSet;
|
||||
}
|
||||
|
||||
bool IsChromeHandler()
|
||||
{
|
||||
return mFlags.mIsChromeHandler;
|
||||
}
|
||||
|
||||
void SetMayHaveListenerManager(bool aMayHave)
|
||||
{
|
||||
if (aMayHave) {
|
||||
mFlags |= NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
|
||||
} else {
|
||||
mFlags &= ~NS_TARGET_CHAIN_MAY_HAVE_MANAGER;
|
||||
}
|
||||
mFlags.mMayHaveManager = aMayHave;
|
||||
}
|
||||
|
||||
bool MayHaveListenerManager()
|
||||
{
|
||||
return !!(mFlags & NS_TARGET_CHAIN_MAY_HAVE_MANAGER);
|
||||
return mFlags.mMayHaveManager;
|
||||
}
|
||||
|
||||
EventTarget* CurrentTarget()
|
||||
|
@ -240,10 +303,15 @@ public:
|
|||
ELMCreationDetector& aCd);
|
||||
|
||||
/**
|
||||
* Resets aVisitor object and calls PreHandleEvent.
|
||||
* Resets aVisitor object and calls GetEventTargetParent.
|
||||
* Copies mItemFlags and mItemData to the current EventTargetChainItem.
|
||||
*/
|
||||
void PreHandleEvent(EventChainPreVisitor& aVisitor);
|
||||
void GetEventTargetParent(EventChainPreVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* Calls PreHandleEvent for those items which called SetWantsPreHandleEvent.
|
||||
*/
|
||||
void PreHandleEvent(EventChainVisitor& aVisitor);
|
||||
|
||||
/**
|
||||
* If the current item in the event target chain has an event listener
|
||||
|
@ -288,7 +356,37 @@ public:
|
|||
|
||||
private:
|
||||
nsCOMPtr<EventTarget> mTarget;
|
||||
uint16_t mFlags;
|
||||
|
||||
class EventTargetChainFlags
|
||||
{
|
||||
public:
|
||||
explicit EventTargetChainFlags()
|
||||
{
|
||||
SetRawFlags(0);
|
||||
}
|
||||
// Cached flags for each EventTargetChainItem which are set when calling
|
||||
// GetEventTargetParent to create event target chain. They are used to
|
||||
// manage or speedup event dispatching.
|
||||
bool mForceContentDispatch : 1;
|
||||
bool mWantsWillHandleEvent : 1;
|
||||
bool mMayHaveManager : 1;
|
||||
bool mChechedIfChrome : 1;
|
||||
bool mIsChromeContent : 1;
|
||||
bool mWantsPreHandleEvent : 1;
|
||||
bool mPreHandleEventOnly : 1;
|
||||
bool mRootOfClosedTree : 1;
|
||||
bool mIsSlotInClosedTree : 1;
|
||||
bool mIsChromeHandler : 1;
|
||||
private:
|
||||
typedef uint32_t RawFlags;
|
||||
void SetRawFlags(RawFlags aRawFlags)
|
||||
{
|
||||
static_assert(sizeof(EventTargetChainFlags) <= sizeof(RawFlags),
|
||||
"EventTargetChainFlags must not be bigger than the RawFlags");
|
||||
memcpy(this, &aRawFlags, sizeof(EventTargetChainFlags));
|
||||
}
|
||||
} mFlags;
|
||||
|
||||
uint16_t mItemFlags;
|
||||
nsCOMPtr<nsISupports> mItemData;
|
||||
// Event retargeting must happen whenever mNewTarget is non-null.
|
||||
|
@ -298,36 +396,49 @@ private:
|
|||
|
||||
bool IsCurrentTargetChrome()
|
||||
{
|
||||
if (!(mFlags & NS_TARGET_CHAIN_CHECKED_IF_CHROME)) {
|
||||
mFlags |= NS_TARGET_CHAIN_CHECKED_IF_CHROME;
|
||||
if (!mFlags.mChechedIfChrome) {
|
||||
mFlags.mChechedIfChrome = true;
|
||||
if (IsEventTargetChrome(mTarget)) {
|
||||
mFlags |= NS_TARGET_CHAIN_IS_CHROME_CONTENT;
|
||||
mFlags.mIsChromeContent = true;
|
||||
}
|
||||
}
|
||||
return !!(mFlags & NS_TARGET_CHAIN_IS_CHROME_CONTENT);
|
||||
return mFlags.mIsChromeContent;
|
||||
}
|
||||
};
|
||||
|
||||
EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
|
||||
: mTarget(aTarget)
|
||||
, mFlags(0)
|
||||
, mItemFlags(0)
|
||||
{
|
||||
MOZ_ASSERT(!aTarget || mTarget == aTarget->GetTargetForEventTargetChain());
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
EventTargetChainItem::GetEventTargetParent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.Reset();
|
||||
Unused << mTarget->PreHandleEvent(aVisitor);
|
||||
Unused << mTarget->GetEventTargetParent(aVisitor);
|
||||
SetForceContentDispatch(aVisitor.mForceContentDispatch);
|
||||
SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
|
||||
SetMayHaveListenerManager(aVisitor.mMayHaveListenerManager);
|
||||
SetWantsPreHandleEvent(aVisitor.mWantsPreHandleEvent);
|
||||
SetPreHandleEventOnly(aVisitor.mWantsPreHandleEvent && !aVisitor.mCanHandle);
|
||||
SetRootOfClosedTree(aVisitor.mRootOfClosedTree);
|
||||
mItemFlags = aVisitor.mItemFlags;
|
||||
mItemData = aVisitor.mItemData;
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PreHandleEvent(EventChainVisitor& aVisitor)
|
||||
{
|
||||
if (!WantsPreHandleEvent()) {
|
||||
return;
|
||||
}
|
||||
aVisitor.mItemFlags = mItemFlags;
|
||||
aVisitor.mItemData = mItemData;
|
||||
Unused << mTarget->PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
void
|
||||
EventTargetChainItem::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
|
@ -346,12 +457,17 @@ EventTargetChainItem::HandleEventTargetChain(
|
|||
// Save the target so that it can be restored later.
|
||||
nsCOMPtr<EventTarget> firstTarget = aVisitor.mEvent->mTarget;
|
||||
uint32_t chainLength = aChain.Length();
|
||||
uint32_t firstCanHandleEventTargetIdx =
|
||||
EventTargetChainItem::GetFirstCanHandleEventTargetIdx(aChain);
|
||||
|
||||
// Capture
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = true;
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = false;
|
||||
for (uint32_t i = chainLength - 1; i > 0; --i) {
|
||||
for (uint32_t i = chainLength - 1; i > firstCanHandleEventTargetIdx; --i) {
|
||||
EventTargetChainItem& item = aChain[i];
|
||||
if (item.PreHandleEventOnly()) {
|
||||
continue;
|
||||
}
|
||||
if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
item.ForceContentDispatch()) &&
|
||||
!aVisitor.mEvent->PropagationStopped()) {
|
||||
|
@ -373,7 +489,7 @@ EventTargetChainItem::HandleEventTargetChain(
|
|||
|
||||
// Target
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase = true;
|
||||
EventTargetChainItem& targetItem = aChain[0];
|
||||
EventTargetChainItem& targetItem = aChain[firstCanHandleEventTargetIdx];
|
||||
if (!aVisitor.mEvent->PropagationStopped() &&
|
||||
(!aVisitor.mEvent->mFlags.mNoContentDispatch ||
|
||||
targetItem.ForceContentDispatch())) {
|
||||
|
@ -385,8 +501,11 @@ EventTargetChainItem::HandleEventTargetChain(
|
|||
|
||||
// Bubble
|
||||
aVisitor.mEvent->mFlags.mInCapturePhase = false;
|
||||
for (uint32_t i = 1; i < chainLength; ++i) {
|
||||
for (uint32_t i = firstCanHandleEventTargetIdx + 1; i < chainLength; ++i) {
|
||||
EventTargetChainItem& item = aChain[i];
|
||||
if (item.PreHandleEventOnly()) {
|
||||
continue;
|
||||
}
|
||||
EventTarget* newTarget = item.GetNewTarget();
|
||||
if (newTarget) {
|
||||
// Item is at anonymous boundary. Need to retarget for the current item
|
||||
|
@ -471,6 +590,28 @@ EventTargetChainItemForChromeTarget(nsTArray<EventTargetChainItem>& aChain,
|
|||
return etci;
|
||||
}
|
||||
|
||||
/* static */ EventTargetChainItem*
|
||||
MayRetargetToChromeIfCanNotHandleEvent(
|
||||
nsTArray<EventTargetChainItem>& aChain, EventChainPreVisitor& aPreVisitor,
|
||||
EventTargetChainItem* aTargetEtci, EventTargetChainItem* aChildEtci,
|
||||
nsINode* aContent)
|
||||
{
|
||||
if (!aPreVisitor.mWantsPreHandleEvent) {
|
||||
// Keep EventTargetChainItem if we need to call PreHandleEvent on it.
|
||||
EventTargetChainItem::DestroyLast(aChain, aTargetEtci);
|
||||
}
|
||||
if (aPreVisitor.mAutomaticChromeDispatch && aContent) {
|
||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||
EventTargetChainItem* chromeTargetEtci =
|
||||
EventTargetChainItemForChromeTarget(aChain, aContent, aChildEtci);
|
||||
if (chromeTargetEtci) {
|
||||
chromeTargetEtci->GetEventTargetParent(aPreVisitor);
|
||||
return chromeTargetEtci;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
nsPresContext* aPresContext,
|
||||
|
@ -593,7 +734,6 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
// Create the event target chain item for the event target.
|
||||
EventTargetChainItem* targetEtci =
|
||||
EventTargetChainItem::Create(chain, target->GetTargetForEventTargetChain());
|
||||
MOZ_ASSERT(&chain[0] == targetEtci);
|
||||
if (!targetEtci->IsValid()) {
|
||||
EventTargetChainItem::DestroyLast(chain, targetEtci);
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -631,37 +771,43 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
aEvent->mFlags.mIsBeingDispatched = true;
|
||||
|
||||
// Create visitor object and start event dispatching.
|
||||
// PreHandleEvent for the original target.
|
||||
// GetEventTargetParent for the original target.
|
||||
nsEventStatus status = aEventStatus ? *aEventStatus : nsEventStatus_eIgnore;
|
||||
EventChainPreVisitor preVisitor(aPresContext, aEvent, aDOMEvent, status,
|
||||
isInAnon);
|
||||
targetEtci->PreHandleEvent(preVisitor);
|
||||
targetEtci->GetEventTargetParent(preVisitor);
|
||||
|
||||
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Event target couldn't handle the event. Try to propagate to chrome.
|
||||
EventTargetChainItem::DestroyLast(chain, targetEtci);
|
||||
targetEtci = EventTargetChainItemForChromeTarget(chain, content);
|
||||
NS_ENSURE_STATE(targetEtci);
|
||||
MOZ_ASSERT(&chain[0] == targetEtci);
|
||||
targetEtci->PreHandleEvent(preVisitor);
|
||||
if (!preVisitor.mCanHandle) {
|
||||
targetEtci = MayRetargetToChromeIfCanNotHandleEvent(chain, preVisitor,
|
||||
targetEtci, nullptr,
|
||||
content);
|
||||
}
|
||||
if (preVisitor.mCanHandle) {
|
||||
if (!preVisitor.mCanHandle) {
|
||||
// The original target and chrome target (mAutomaticChromeDispatch=true)
|
||||
// can not handle the event but we still have to call their PreHandleEvent.
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
chain[i].PreHandleEvent(preVisitor);
|
||||
}
|
||||
} else {
|
||||
// At least the original target can handle the event.
|
||||
// Setting the retarget to the |target| simplifies retargeting code.
|
||||
nsCOMPtr<EventTarget> t = do_QueryInterface(aEvent->mTarget);
|
||||
targetEtci->SetNewTarget(t);
|
||||
EventTargetChainItem* topEtci = targetEtci;
|
||||
targetEtci = nullptr;
|
||||
while (preVisitor.mParentTarget) {
|
||||
EventTarget* parentTarget = preVisitor.mParentTarget;
|
||||
while (preVisitor.GetParentTarget()) {
|
||||
EventTarget* parentTarget = preVisitor.GetParentTarget();
|
||||
EventTargetChainItem* parentEtci =
|
||||
EventTargetChainItem::Create(chain, preVisitor.mParentTarget, topEtci);
|
||||
EventTargetChainItem::Create(chain, parentTarget, topEtci);
|
||||
if (!parentEtci->IsValid()) {
|
||||
EventTargetChainItem::DestroyLast(chain, parentEtci);
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
parentEtci->SetIsSlotInClosedTree(preVisitor.mParentIsSlotInClosedTree);
|
||||
parentEtci->SetIsChromeHandler(preVisitor.mParentIsChromeHandler);
|
||||
|
||||
// Item needs event retargetting.
|
||||
if (preVisitor.mEventTargetAtParent) {
|
||||
// Need to set the target of the event
|
||||
|
@ -670,29 +816,22 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
parentEtci->SetNewTarget(preVisitor.mEventTargetAtParent);
|
||||
}
|
||||
|
||||
parentEtci->PreHandleEvent(preVisitor);
|
||||
parentEtci->GetEventTargetParent(preVisitor);
|
||||
if (preVisitor.mCanHandle) {
|
||||
topEtci = parentEtci;
|
||||
} else {
|
||||
EventTargetChainItem::DestroyLast(chain, parentEtci);
|
||||
parentEtci = nullptr;
|
||||
if (preVisitor.mAutomaticChromeDispatch && content) {
|
||||
// Even if the current target can't handle the event, try to
|
||||
// propagate to chrome.
|
||||
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
||||
if (disabledTarget) {
|
||||
parentEtci = EventTargetChainItemForChromeTarget(chain,
|
||||
disabledTarget,
|
||||
topEtci);
|
||||
if (parentEtci) {
|
||||
parentEtci->PreHandleEvent(preVisitor);
|
||||
if (preVisitor.mCanHandle) {
|
||||
chain[0].SetNewTarget(parentTarget);
|
||||
topEtci = parentEtci;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
|
||||
parentEtci = MayRetargetToChromeIfCanNotHandleEvent(chain,
|
||||
preVisitor,
|
||||
parentEtci,
|
||||
topEtci,
|
||||
disabledTarget);
|
||||
if (parentEtci && preVisitor.mCanHandle) {
|
||||
EventTargetChainItem* item =
|
||||
EventTargetChainItem::GetFirstCanHandleEventTarget(chain);
|
||||
item->SetNewTarget(parentTarget);
|
||||
topEtci = parentEtci;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -706,11 +845,19 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
|||
targets[i] = chain[i].CurrentTarget()->GetTargetForDOMEvent();
|
||||
}
|
||||
} else {
|
||||
// Event target chain is created. Handle the chain.
|
||||
// Event target chain is created. PreHandle the chain.
|
||||
for (uint32_t i = 0; i < chain.Length(); ++i) {
|
||||
chain[i].PreHandleEvent(preVisitor);
|
||||
}
|
||||
// Handle the chain.
|
||||
EventChainPostVisitor postVisitor(preVisitor);
|
||||
MOZ_RELEASE_ASSERT(!aEvent->mPath);
|
||||
aEvent->mPath = &chain;
|
||||
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
|
||||
aCallback, cd);
|
||||
|
||||
aEvent->mPath = nullptr;
|
||||
|
||||
preVisitor.mEventStatus = postVisitor.mEventStatus;
|
||||
// If the DOM event was created during event flow.
|
||||
if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
|
||||
|
@ -1022,4 +1169,64 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
EventDispatcher::GetComposedPathFor(WidgetEvent* aEvent,
|
||||
nsTArray<RefPtr<EventTarget>>& aPath)
|
||||
{
|
||||
nsTArray<EventTargetChainItem>* path = aEvent->mPath;
|
||||
if (!path || path->IsEmpty() || !aEvent->mCurrentTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
EventTarget* currentTarget =
|
||||
aEvent->mCurrentTarget->GetTargetForEventTargetChain();
|
||||
if (!currentTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoTArray<EventTarget*, 128> reversedComposedPath;
|
||||
bool hasSeenCurrentTarget = false;
|
||||
uint32_t hiddenSubtreeLevel = 0;
|
||||
for (uint32_t i = path->Length(); i; ) {
|
||||
--i;
|
||||
|
||||
EventTargetChainItem& item = path->ElementAt(i);
|
||||
if (item.PreHandleEventOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasSeenCurrentTarget && currentTarget == item.CurrentTarget()) {
|
||||
hasSeenCurrentTarget = true;
|
||||
} else if (hasSeenCurrentTarget && item.IsRootOfClosedTree()) {
|
||||
++hiddenSubtreeLevel;
|
||||
}
|
||||
|
||||
if (hiddenSubtreeLevel == 0) {
|
||||
reversedComposedPath.AppendElement(item.CurrentTarget());
|
||||
}
|
||||
|
||||
if (item.IsSlotInClosedTree() && hiddenSubtreeLevel > 0) {
|
||||
--hiddenSubtreeLevel;
|
||||
}
|
||||
|
||||
if (item.IsChromeHandler()) {
|
||||
if (hasSeenCurrentTarget) {
|
||||
// The current behavior is to include only EventTargets from
|
||||
// either chrome side of event path or content side, not from both.
|
||||
break;
|
||||
}
|
||||
|
||||
// Need to start all over to collect the composed path on content side.
|
||||
reversedComposedPath.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
aPath.SetCapacity(reversedComposedPath.Length());
|
||||
for (uint32_t i = reversedComposedPath.Length(); i; ) {
|
||||
--i;
|
||||
aPath.AppendElement(reversedComposedPath[i]->GetTargetForDOMEvent());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -31,14 +31,14 @@ class EventTarget;
|
|||
* About event dispatching:
|
||||
* When either EventDispatcher::Dispatch or
|
||||
* EventDispatcher::DispatchDOMEvent is called an event target chain is
|
||||
* created. EventDispatcher creates the chain by calling PreHandleEvent
|
||||
* created. EventDispatcher creates the chain by calling GetEventTargetParent
|
||||
* on each event target and the creation continues until either the mCanHandle
|
||||
* member of the EventChainPreVisitor object is false or the mParentTarget
|
||||
* does not point to a new target. The event target chain is created in the
|
||||
* heap.
|
||||
*
|
||||
* If the event needs retargeting, mEventTargetAtParent must be set in
|
||||
* PreHandleEvent.
|
||||
* GetEventTargetParent.
|
||||
*
|
||||
* The capture, target and bubble phases of the event dispatch are handled
|
||||
* by iterating through the event target chain. Iteration happens twice,
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
|
||||
/**
|
||||
* Bits for items in the event target chain.
|
||||
* Set in PreHandleEvent() and used in PostHandleEvent().
|
||||
* Set in GetEventTargetParent() and used in PostHandleEvent().
|
||||
*
|
||||
* @note These bits are different for each item in the event target chain.
|
||||
* It is up to the Pre/PostHandleEvent implementation to decide how to
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
/**
|
||||
* Data for items in the event target chain.
|
||||
* Set in PreHandleEvent() and used in PostHandleEvent().
|
||||
* Set in GetEventTargetParent() and used in PostHandleEvent().
|
||||
*
|
||||
* @note This data is different for each item in the event target chain.
|
||||
* It is up to the Pre/PostHandleEvent implementation to decide how to
|
||||
|
@ -123,6 +123,10 @@ public:
|
|||
, mOriginalTargetIsInAnon(aIsInAnon)
|
||||
, mWantsWillHandleEvent(false)
|
||||
, mMayHaveListenerManager(true)
|
||||
, mWantsPreHandleEvent(false)
|
||||
, mRootOfClosedTree(false)
|
||||
, mParentIsSlotInClosedTree(false)
|
||||
, mParentIsChromeHandler(false)
|
||||
, mParentTarget(nullptr)
|
||||
, mEventTargetAtParent(nullptr)
|
||||
{
|
||||
|
@ -137,13 +141,30 @@ public:
|
|||
mForceContentDispatch = false;
|
||||
mWantsWillHandleEvent = false;
|
||||
mMayHaveListenerManager = true;
|
||||
mWantsPreHandleEvent = false;
|
||||
mRootOfClosedTree = false;
|
||||
mParentIsSlotInClosedTree = false;
|
||||
mParentIsChromeHandler = false;
|
||||
mParentTarget = nullptr;
|
||||
mEventTargetAtParent = nullptr;
|
||||
}
|
||||
|
||||
dom::EventTarget* GetParentTarget()
|
||||
{
|
||||
return mParentTarget;
|
||||
}
|
||||
|
||||
void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler)
|
||||
{
|
||||
mParentTarget = aParentTarget;
|
||||
if (mParentTarget) {
|
||||
mParentIsChromeHandler = aIsChromeHandler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Member that must be set in PreHandleEvent by event targets. If set to false,
|
||||
* indicates that this event target will not be handling the event and
|
||||
* Member that must be set in GetEventTargetParent by event targets. If set to
|
||||
* false, indicates that this event target will not be handling the event and
|
||||
* construction of the event target chain is complete. The target that sets
|
||||
* mCanHandle to false is NOT included in the event target chain.
|
||||
*/
|
||||
|
@ -170,7 +191,7 @@ public:
|
|||
|
||||
/**
|
||||
* true if the original target of the event is inside anonymous content.
|
||||
* This is set before calling PreHandleEvent on event targets.
|
||||
* This is set before calling GetEventTargetParent on event targets.
|
||||
*/
|
||||
bool mOriginalTargetIsInAnon;
|
||||
|
||||
|
@ -182,27 +203,45 @@ public:
|
|||
|
||||
/**
|
||||
* If it is known that the current target doesn't have a listener manager
|
||||
* when PreHandleEvent is called, set this to false.
|
||||
* when GetEventTargetParent is called, set this to false.
|
||||
*/
|
||||
bool mMayHaveListenerManager;
|
||||
|
||||
/**
|
||||
* Whether or not nsIDOMEventTarget::PreHandleEvent will be called. Default is
|
||||
* false;
|
||||
*/
|
||||
bool mWantsPreHandleEvent;
|
||||
|
||||
/**
|
||||
* True if the current target is either closed ShadowRoot or root of
|
||||
* chrome only access tree (for example native anonymous content).
|
||||
*/
|
||||
bool mRootOfClosedTree;
|
||||
|
||||
/**
|
||||
* True if mParentTarget is HTMLSlotElement in a closed shadow tree and the
|
||||
* current target is assigned to that slot.
|
||||
*/
|
||||
bool mParentIsSlotInClosedTree;
|
||||
|
||||
/**
|
||||
* True if mParentTarget is a chrome handler in the event path.
|
||||
*/
|
||||
bool mParentIsChromeHandler;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Parent item in the event target chain.
|
||||
*/
|
||||
dom::EventTarget* mParentTarget;
|
||||
|
||||
public:
|
||||
/**
|
||||
* If the event needs to be retargeted, this is the event target,
|
||||
* which should be used when the event is handled at mParentTarget.
|
||||
*/
|
||||
dom::EventTarget* mEventTargetAtParent;
|
||||
|
||||
/**
|
||||
* An array of destination insertion points that need to be inserted
|
||||
* into the event path of nodes that are distributed by the
|
||||
* web components distribution algorithm.
|
||||
*/
|
||||
nsTArray<nsIContent*> mDestInsertionPoints;
|
||||
};
|
||||
|
||||
class EventChainPostVisitor : public mozilla::EventChainVisitor
|
||||
|
@ -280,6 +319,9 @@ public:
|
|||
WidgetEvent* aEvent,
|
||||
const nsAString& aEventType);
|
||||
|
||||
static void GetComposedPathFor(WidgetEvent* aEvent,
|
||||
nsTArray<RefPtr<dom::EventTarget>>& aPath);
|
||||
|
||||
/**
|
||||
* Called at shutting down.
|
||||
*/
|
||||
|
|
|
@ -3484,6 +3484,12 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
|||
// make sure to fire the enter and exit_synth events after the
|
||||
// eDragExit event, otherwise we'll clean up too early
|
||||
GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
|
||||
if (ContentChild* child = ContentChild::GetSingleton()) {
|
||||
// SendUpdateDropEffect to prevent nsIDragService from waiting for
|
||||
// response of forwarded dragexit event.
|
||||
child->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
|
||||
nsIDragService::DRAGDROP_ACTION_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eBeforeKeyUp:
|
||||
|
@ -3900,13 +3906,13 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
|
|||
newPointerEvent->mWidth = sourcePointer->mWidth;
|
||||
newPointerEvent->mHeight = sourcePointer->mHeight;
|
||||
newPointerEvent->inputSource = sourcePointer->inputSource;
|
||||
newPointerEvent->relatedTarget = aRelatedContent;
|
||||
newPointerEvent->mRelatedTarget = aRelatedContent;
|
||||
aNewEvent = newPointerEvent.forget();
|
||||
} else {
|
||||
aNewEvent =
|
||||
new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
|
||||
aMouseEvent->mWidget, WidgetMouseEvent::eReal);
|
||||
aNewEvent->relatedTarget = aRelatedContent;
|
||||
aNewEvent->mRelatedTarget = aRelatedContent;
|
||||
}
|
||||
aNewEvent->mRefPoint = aMouseEvent->mRefPoint;
|
||||
aNewEvent->mModifiers = aMouseEvent->mModifiers;
|
||||
|
@ -4446,6 +4452,19 @@ EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
|
|||
FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
|
||||
aDragEvent, eDragExit,
|
||||
targetContent, lastContent, sLastDragOverFrame);
|
||||
nsIContent* target = sLastDragOverFrame ? sLastDragOverFrame.GetFrame()->GetContent() : nullptr;
|
||||
if (IsRemoteTarget(target)) {
|
||||
// Dragging something and moving from web content to chrome only
|
||||
// fires dragexit and dragleave to xul:browser. We have to forward
|
||||
// dragexit to sLastDragOverFrame when its content is a remote
|
||||
// target. We don't forward dragleave since it's generated from
|
||||
// dragexit.
|
||||
WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
|
||||
aDragEvent->mWidget);
|
||||
remoteEvent.AssignDragEventData(*aDragEvent, true);
|
||||
nsEventStatus remoteStatus = nsEventStatus_eIgnore;
|
||||
HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
|
||||
}
|
||||
}
|
||||
|
||||
FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter,
|
||||
|
@ -4502,14 +4521,11 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
|
|||
nsIContent* aTargetContent,
|
||||
nsWeakFrame& aTargetFrame)
|
||||
{
|
||||
MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||
|
||||
aMessage == eDragEnter);
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
|
||||
event.mRefPoint = aDragEvent->mRefPoint;
|
||||
event.mModifiers = aDragEvent->mModifiers;
|
||||
event.buttons = aDragEvent->buttons;
|
||||
event.relatedTarget = aRelatedTarget;
|
||||
event.inputSource = aDragEvent->inputSource;
|
||||
|
||||
event.AssignDragEventData(*aDragEvent, true);
|
||||
mCurrentTargetContent = aTargetContent;
|
||||
|
||||
if (aTargetContent != aRelatedTarget) {
|
||||
|
@ -4527,10 +4543,7 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
|
|||
|
||||
// collect any changes to moz cursor settings stored in the event's
|
||||
// data transfer.
|
||||
if (aMessage == eDragLeave || aMessage == eDragExit ||
|
||||
aMessage == eDragEnter) {
|
||||
UpdateDragDataTransfer(&event);
|
||||
}
|
||||
UpdateDragDataTransfer(&event);
|
||||
}
|
||||
|
||||
// Finally dispatch the event to the frame
|
||||
|
|
|
@ -292,14 +292,39 @@ private:
|
|||
#define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(43)
|
||||
// Element is highlighted (devtools inspector)
|
||||
#define NS_EVENT_STATE_DEVTOOLS_HIGHLIGHTED NS_DEFINE_EVENT_STATE_MACRO(45)
|
||||
// Element is an unresolved custom element candidate
|
||||
#define NS_EVENT_STATE_UNRESOLVED NS_DEFINE_EVENT_STATE_MACRO(46)
|
||||
// States for tracking the state of the "dir" attribute for HTML elements. We
|
||||
// use these to avoid having to get "dir" attributes all the time during
|
||||
// selector matching for some parts of the UA stylesheet.
|
||||
//
|
||||
// These states are externally managed, because we also don't want to keep
|
||||
// getting "dir" attributes in IntrinsicState.
|
||||
//
|
||||
// Element is HTML and has a "dir" attibute. This state might go away depending
|
||||
// on how https://github.com/whatwg/html/issues/2769 gets resolved. The value
|
||||
// could be anything.
|
||||
#define NS_EVENT_STATE_HAS_DIR_ATTR NS_DEFINE_EVENT_STATE_MACRO(46)
|
||||
// Element is HTML, has a "dir" attribute, and the attribute's value is
|
||||
// case-insensitively equal to "ltr".
|
||||
#define NS_EVENT_STATE_DIR_ATTR_LTR NS_DEFINE_EVENT_STATE_MACRO(47)
|
||||
// Element is HTML, has a "dir" attribute, and the attribute's value is
|
||||
// case-insensitively equal to "rtl".
|
||||
#define NS_EVENT_STATE_DIR_ATTR_RTL NS_DEFINE_EVENT_STATE_MACRO(48)
|
||||
// Element is HTML, and is either a <bdi> element with no valid-valued "dir"
|
||||
// attribute or any HTML element which has a "dir" attribute whose value is
|
||||
// "auto".
|
||||
#define NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO NS_DEFINE_EVENT_STATE_MACRO(49)
|
||||
// Free bit NS_DEFINE_EVENT_STATE_MACRO(50)
|
||||
// Element is transitioning for rules changed by style editor
|
||||
#define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(47)
|
||||
#define NS_EVENT_STATE_STYLEEDITOR_TRANSITIONING NS_DEFINE_EVENT_STATE_MACRO(51)
|
||||
// Content shows its placeholder
|
||||
#define NS_EVENT_STATE_PLACEHOLDERSHOWN NS_DEFINE_EVENT_STATE_MACRO(48)
|
||||
#define NS_EVENT_STATE_PLACEHOLDERSHOWN NS_DEFINE_EVENT_STATE_MACRO(52)
|
||||
// Element has focus-within.
|
||||
#define NS_EVENT_STATE_FOCUS_WITHIN NS_DEFINE_EVENT_STATE_MACRO(49)
|
||||
#define NS_EVENT_STATE_FOCUS_WITHIN NS_DEFINE_EVENT_STATE_MACRO(53)
|
||||
|
||||
#define DIR_ATTR_STATES (NS_EVENT_STATE_HAS_DIR_ATTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_LTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_RTL | \
|
||||
NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO)
|
||||
|
||||
// Event state that is used for values that need to be parsed but do nothing.
|
||||
#define NS_EVENT_STATE_IGNORE NS_DEFINE_EVENT_STATE_MACRO(63)
|
||||
|
@ -310,11 +335,10 @@ private:
|
|||
|
||||
#define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
|
||||
|
||||
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
|
||||
#define ESM_MANAGED_STATES (DIR_ATTR_STATES | NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
|
||||
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
|
||||
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
|
||||
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_UNRESOLVED | \
|
||||
NS_EVENT_STATE_FOCUS_WITHIN)
|
||||
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FOCUS_WITHIN)
|
||||
|
||||
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue