summaryrefslogtreecommitdiffstats
path: root/dom/base
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base')
-rw-r--r--dom/base/Element.cpp5
-rw-r--r--dom/base/Element.h18
-rw-r--r--dom/base/FragmentOrElement.cpp7
-rw-r--r--dom/base/FragmentOrElement.h6
-rw-r--r--dom/base/nsContentList.cpp143
-rw-r--r--dom/base/nsContentList.h40
-rw-r--r--dom/base/nsContentListDeclarations.h8
-rw-r--r--dom/base/nsContentUtils.cpp4
-rw-r--r--dom/base/nsContentUtils.h3
-rw-r--r--dom/base/nsGkAtomList.h3
-rw-r--r--dom/base/nsIContent.h19
-rw-r--r--dom/base/test/test_bug1375050.html33
12 files changed, 245 insertions, 44 deletions
diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp
index 886acc670..9ced64c0d 100644
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -165,10 +165,9 @@ nsIContent::DoGetID() const
}
const nsAttrValue*
-nsIContent::DoGetClasses() const
+Element::DoGetClasses() const
{
MOZ_ASSERT(HasFlag(NODE_MAY_HAVE_CLASS), "Unexpected call");
- MOZ_ASSERT(IsElement(), "Only elements can have classes");
if (IsSVGElement()) {
const nsAttrValue* animClass =
@@ -178,7 +177,7 @@ nsIContent::DoGetClasses() const
}
}
- return AsElement()->GetParsedAttr(nsGkAtoms::_class);
+ return GetParsedAttr(nsGkAtoms::_class);
}
NS_IMETHODIMP
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 5d878df60..cf1d197e2 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -544,6 +544,18 @@ public:
virtual uint32_t GetAttrCount() const override;
virtual bool IsNodeOfType(uint32_t aFlags) const override;
+ /**
+ * Get the class list of this element (this corresponds to the value of the
+ * class attribute). This may be null if there are no classes, but that's not
+ * guaranteed (e.g. we could have class="").
+ */
+ const nsAttrValue* GetClasses() const {
+ if (HasFlag(NODE_MAY_HAVE_CLASS)) {
+ return DoGetClasses();
+ }
+ return nullptr;
+ }
+
#ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override
{
@@ -1372,6 +1384,12 @@ protected:
private:
/**
+ * Hook for implementing GetClasses. This is guaranteed to only be
+ * called if the NODE_MAY_HAVE_CLASS flag is set.
+ */
+ const nsAttrValue* DoGetClasses() const;
+
+ /**
* Get this element's client area rect in app units.
* @return the frame's client area
*/
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index 293177ce7..79f6cff51 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -574,6 +574,9 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb,
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildrenList");
cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mChildrenList));
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mLabelsList");
+ cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMNodeList*, mLabelsList));
+
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mClassList");
cb.NoteXPCOMChild(mClassList.get());
@@ -602,6 +605,7 @@ FragmentOrElement::nsDOMSlots::Unlink(bool aIsXUL)
mShadowRoot = nullptr;
mContainingShadow = nullptr;
mChildrenList = nullptr;
+ mLabelsList = nullptr;
mCustomElementData = nullptr;
mClassList = nullptr;
}
@@ -1827,7 +1831,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(FragmentOrElement)
}
nsAutoString classes;
- const nsAttrValue* classAttrValue = tmp->GetClasses();
+ const nsAttrValue* classAttrValue = tmp->IsElement() ?
+ tmp->AsElement()->GetClasses() : nullptr;
if (classAttrValue) {
classes.AppendLiteral(" class='");
nsAutoString classString;
diff --git a/dom/base/FragmentOrElement.h b/dom/base/FragmentOrElement.h
index 3cb5575fe..1cd8033bb 100644
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -24,6 +24,7 @@
class ContentUnbinder;
class nsContentList;
+class nsLabelsNodeList;
class nsDOMAttributeMap;
class nsDOMTokenList;
class nsIControllers;
@@ -313,6 +314,11 @@ public:
*/
RefPtr<nsDOMTokenList> mClassList;
+ /*
+ * An object implementing the .labels property for this element.
+ */
+ RefPtr<nsLabelsNodeList> mLabelsList;
+
/**
* ShadowRoot bound to the element.
*/
diff --git a/dom/base/nsContentList.cpp b/dom/base/nsContentList.cpp
index 09e949009..43e65777d 100644
--- a/dom/base/nsContentList.cpp
+++ b/dom/base/nsContentList.cpp
@@ -254,19 +254,6 @@ const nsCacheableFuncStringContentList::ContentListType
nsCacheableFuncStringHTMLCollection::sType = nsCacheableFuncStringContentList::eHTMLCollection;
#endif
-JSObject*
-nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
- return NodeListBinding::Wrap(cx, this, aGivenProto);
-}
-
-
-JSObject*
-nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
- return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
-}
-
// Hashtable for storing nsCacheableFuncStringContentList
static PLDHashTable* gFuncStringContentListHashTable;
@@ -379,6 +366,7 @@ NS_GetFuncStringHTMLCollection(nsINode* aRootNode,
aString);
}
+//-----------------------------------------------------
// nsContentList implementation
nsContentList::nsContentList(nsINode* aRootNode,
@@ -660,7 +648,7 @@ nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
const nsAttrValue* aOldValue)
{
NS_PRECONDITION(aElement, "Must have a content node to work with");
-
+
if (!mFunc || !mFuncMayDependOnAttr || mState == LIST_DIRTY ||
!MayContainRelevantNodes(aElement->GetParentNode()) ||
!nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
@@ -806,7 +794,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
ASSERT_IN_SYNC;
}
-
+
void
nsContentList::ContentRemoved(nsIDocument *aDocument,
nsIContent* aContainer,
@@ -1075,3 +1063,128 @@ nsContentList::AssertInSync()
NS_ASSERTION(cnt == mElements.Length(), "Too few elements");
}
#endif
+
+//-----------------------------------------------------
+// nsCacheableFuncStringNodeList
+
+JSObject*
+nsCacheableFuncStringNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return NodeListBinding::Wrap(cx, this, aGivenProto);
+}
+
+//-----------------------------------------------------
+// nsCacheableFuncStringHTMLCollection
+
+JSObject*
+nsCacheableFuncStringHTMLCollection::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return HTMLCollectionBinding::Wrap(cx, this, aGivenProto);
+}
+
+//-----------------------------------------------------
+// nsLabelsNodeList
+
+JSObject*
+nsLabelsNodeList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
+{
+ return NodeListBinding::Wrap(cx, this, aGivenProto);
+}
+
+void
+nsLabelsNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
+ int32_t aNameSpaceID, nsIAtom* aAttribute,
+ int32_t aModType,
+ const nsAttrValue* aOldValue)
+{
+ MOZ_ASSERT(aElement, "Must have a content node to work with");
+ if (mState == LIST_DIRTY ||
+ !nsContentUtils::IsInSameAnonymousTree(mRootNode, aElement)) {
+ return;
+ }
+
+ // We need to handle input type changes to or from "hidden".
+ if (aElement->IsHTMLElement(nsGkAtoms::input) &&
+ aAttribute == nsGkAtoms::type && aNameSpaceID == kNameSpaceID_None) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentAppended(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aFirstNewContent,
+ int32_t aNewIndexInContainer)
+{
+ // If a labelable element is moved to outside or inside of
+ // nested associated labels, we're gonna have to modify
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aContainer)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentInserted(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aChild,
+ int32_t aIndexInContainer)
+{
+ // If a labelable element is moved to outside or inside of
+ // nested associated labels, we're gonna have to modify
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::ContentRemoved(nsIDocument* aDocument,
+ nsIContent* aContainer,
+ nsIContent* aChild,
+ int32_t aIndexInContainer,
+ nsIContent* aPreviousSibling)
+{
+ // If a labelable element is removed, we're gonna have to clean
+ // the content list.
+ if (mState != LIST_DIRTY ||
+ nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild)) {
+ SetDirty();
+ return;
+ }
+}
+
+void
+nsLabelsNodeList::MaybeResetRoot(nsINode* aRootNode)
+{
+ MOZ_ASSERT(aRootNode, "Must have root");
+ if (mRootNode == aRootNode) {
+ return;
+ }
+
+ if (mRootNode) {
+ mRootNode->RemoveMutationObserver(this);
+ }
+ mRootNode = aRootNode;
+ mRootNode->AddMutationObserver(this);
+ SetDirty();
+}
+
+void
+nsLabelsNodeList::PopulateSelf(uint32_t aNeededLength)
+{
+ MOZ_ASSERT(mRootNode, "Must have root");
+
+ // Start searching at the root.
+ nsINode* cur = mRootNode;
+ if (mElements.IsEmpty() && cur->IsElement() && Match(cur->AsElement())) {
+ mElements.AppendElement(cur->AsElement());
+ }
+
+ nsContentList::PopulateSelf(aNeededLength);
+}
diff --git a/dom/base/nsContentList.h b/dom/base/nsContentList.h
index 3878074b2..83d27da95 100644
--- a/dom/base/nsContentList.h
+++ b/dom/base/nsContentList.h
@@ -371,9 +371,9 @@ protected:
* traversed the whole document (or both).
*
* @param aNeededLength the length the list should have when we are
- * done (unless it exhausts the document)
+ * done (unless it exhausts the document)
*/
- void PopulateSelf(uint32_t aNeededLength);
+ virtual void PopulateSelf(uint32_t aNeededLength);
/**
* @param aContainer a content node which must be a descendant of
@@ -584,4 +584,40 @@ public:
#endif
};
+class nsLabelsNodeList final : public nsContentList
+{
+public:
+ nsLabelsNodeList(nsINode* aRootNode,
+ nsContentListMatchFunc aFunc,
+ nsContentListDestroyFunc aDestroyFunc,
+ void* aData)
+ : nsContentList(aRootNode, aFunc, aDestroyFunc, aData)
+ {
+ }
+
+ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
+ NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
+
+ virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
+
+ /**
+ * Reset root, mutation observer, and clear content list
+ * if the root has been changed.
+ *
+ * @param aRootNode The node under which to limit our search.
+ */
+ void MaybeResetRoot(nsINode* aRootNode);
+
+private:
+ /**
+ * Start searching at the last one if we already have nodes, otherwise
+ * start searching at the root.
+ *
+ * @param aNeededLength The list of length should have when we are
+ * done (unless it exhausts the document).
+ */
+ void PopulateSelf(uint32_t aNeededLength) override;
+};
#endif // nsContentList_h___
diff --git a/dom/base/nsContentListDeclarations.h b/dom/base/nsContentListDeclarations.h
index db3a09036..a5e0e3691 100644
--- a/dom/base/nsContentListDeclarations.h
+++ b/dom/base/nsContentListDeclarations.h
@@ -18,6 +18,12 @@ class nsINode;
class nsString;
class nsAString;
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+} // namespace mozilla
+
// Magic namespace id that means "match all namespaces". This is
// negative so it won't collide with actual namespace constants.
#define kNameSpaceID_Wildcard INT32_MIN
@@ -26,7 +32,7 @@ class nsAString;
// arbitrary matching algorithm. aContent is the content that may
// match the list, while aNamespaceID, aAtom, and aData are whatever
// was passed to the list's constructor.
-typedef bool (*nsContentListMatchFunc)(nsIContent* aContent,
+typedef bool (*nsContentListMatchFunc)(mozilla::dom::Element* aElement,
int32_t aNamespaceID,
nsIAtom* aAtom,
void* aData);
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 1cc352685..02c6bf1de 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6287,11 +6287,11 @@ struct ClassMatchingInfo {
// static
bool
-nsContentUtils::MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
+nsContentUtils::MatchClassNames(Element* aElement, int32_t aNamespaceID,
nsIAtom* aAtom, void* aData)
{
// We can't match if there are no class names
- const nsAttrValue* classAttr = aContent->GetClasses();
+ const nsAttrValue* classAttr = aElement->GetClasses();
if (!classAttr) {
return false;
}
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index f688eeecf..0a293d73e 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2753,7 +2753,8 @@ private:
static void DropFragmentParsers();
- static bool MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
+ static bool MatchClassNames(mozilla::dom::Element* aElement,
+ int32_t aNamespaceID,
nsIAtom* aAtom, void* aData);
static void DestroyClassNameArray(void* aData);
static void* AllocClassMatchingInfo(nsINode* aRootNode,
diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index 0b76b2bea..e4ae7ede8 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -526,6 +526,7 @@ GK_ATOM(keytext, "keytext")
GK_ATOM(keyup, "keyup")
GK_ATOM(kind, "kind")
GK_ATOM(label, "label")
+GK_ATOM(labels, "labels")
GK_ATOM(lang, "lang")
GK_ATOM(language, "language")
GK_ATOM(last, "last")
@@ -950,6 +951,7 @@ GK_ATOM(onupdateready, "onupdateready")
GK_ATOM(onupgradeneeded, "onupgradeneeded")
GK_ATOM(onussdreceived, "onussdreceived")
GK_ATOM(onversionchange, "onversionchange")
+GK_ATOM(onvisibilitychange, "onvisibilitychange")
GK_ATOM(onvoicechange, "onvoicechange")
GK_ATOM(onvoiceschanged, "onvoiceschanged")
GK_ATOM(onvrdisplayconnect, "onvrdisplayconnect")
@@ -1449,6 +1451,7 @@ GK_ATOM(font_style, "font-style")
GK_ATOM(font_variant, "font-variant")
GK_ATOM(foreignObject, "foreignObject")
GK_ATOM(fractalNoise, "fractalNoise")
+GK_ATOM(fr, "fr")
GK_ATOM(fx, "fx")
GK_ATOM(fy, "fy")
GK_ATOM(G, "G")
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index f05c47a61..405090865 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -862,18 +862,6 @@ public:
}
/**
- * Get the class list of this content node (this corresponds to the
- * value of the class attribute). This may be null if there are no
- * classes, but that's not guaranteed.
- */
- const nsAttrValue* GetClasses() const {
- if (HasFlag(NODE_MAY_HAVE_CLASS)) {
- return DoGetClasses();
- }
- return nullptr;
- }
-
- /**
* Walk aRuleWalker over the content style rules (presentational
* hint rules) for this content node.
*/
@@ -990,13 +978,6 @@ protected:
*/
nsIAtom* DoGetID() const;
-private:
- /**
- * Hook for implementing GetClasses. This is guaranteed to only be
- * called if the NODE_MAY_HAVE_CLASS flag is set.
- */
- const nsAttrValue* DoGetClasses() const;
-
public:
#ifdef DEBUG
/**
diff --git a/dom/base/test/test_bug1375050.html b/dom/base/test/test_bug1375050.html
new file mode 100644
index 000000000..b91b859d0
--- /dev/null
+++ b/dom/base/test/test_bug1375050.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1375050
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1375050</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+ try { o1 = document.createElement('input'); } catch(e) { console.log(e); };
+ try { o2 = document.createElement('col'); } catch(e) { console.log(e); };
+ try { o4 = document.createRange(); } catch(e) { console.log(e); };
+ try { document.documentElement.appendChild(o1); } catch(e) { console.log(e); };
+ try { for (let p in o1) { let x = o1[p] }; } catch(e) { console.log(e); };
+ try { o4.selectNode(o1); } catch(e) { console.log(e); };
+ try { o6 = document.createComment(" x"); } catch(e) { console.log(e); }
+ try { o4.surroundContents(o6); } catch(e) { console.log(e); }
+ try { o7 = document.implementation.createDocument('', '', null).adoptNode(o1); } catch(e) { console.log(e);};
+ try { o2.appendChild(o1); } catch(e) { console.log(e); };
+ ok(true, "Didn't crash.");
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1375050">Mozilla Bug 1375050</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>