Bug 1403871 Part 1: Add getElementsWithFlex and getElementsWithGrid to Element. draft
authorBrad Werth <bwerth@mozilla.com>
Tue, 31 Oct 2017 12:05:02 -0700
changeset 693051 1174659276cf848873c649919b82e0535a4e3d3d
parent 692714 4ada8f0d5cc011af4bc0f4fadbb25ea3e1e62bfc
child 693052 10f0492e7c273c80b1bc421906ede16cd248e89f
push id87688
push userbwerth@mozilla.com
push dateFri, 03 Nov 2017 23:53:08 +0000
bugs1403871
milestone58.0a1
Bug 1403871 Part 1: Add getElementsWithFlex and getElementsWithGrid to Element. MozReview-Commit-ID: L44Q95wEqDA
dom/base/Element.cpp
dom/base/Element.h
dom/webidl/Element.webidl
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1572,16 +1572,74 @@ Element::HasAttributeNS(const nsAString&
 }
 
 already_AddRefed<nsIHTMLCollection>
 Element::GetElementsByClassName(const nsAString& aClassNames)
 {
   return nsContentUtils::GetElementsByClassName(this, aClassNames);
 }
 
+void
+Element::GetElementsWithFlex(nsTArray<RefPtr<Element>>& aElements)
+{
+  // This helper function is passed to GetElementsByMatching()
+  // to identify elements with styling which will cause them to
+  // generate a nsFlexContainerFrame during layout.
+  auto IsDisplayFlex = [](Element* aElement) -> bool
+  {
+    // Check the display style for something that will resolve to flex.
+    RefPtr<nsStyleContext> styleContext =
+      nsComputedDOMStyle::GetStyleContext(aElement, nullptr, nullptr);
+    if (styleContext) {
+      const nsStyleDisplay* display = styleContext->StyleDisplay();
+      return (display->mDisplay == StyleDisplay::Flex ||
+              display->mDisplay == StyleDisplay::InlineFlex ||
+              display->mDisplay == StyleDisplay::WebkitBox ||
+              display->mDisplay == StyleDisplay::WebkitInlineBox);
+    }
+    return false;
+  };
+
+  GetElementsByMatching(IsDisplayFlex, aElements);
+}
+
+void
+Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements)
+{
+  // This helper function is passed to GetElementsByMatching()
+  // to identify elements with styling which will cause them to
+  // generate a nsGridContainerFrame during layout.
+  auto IsDisplayGrid = [](Element* aElement) -> bool
+  {
+    // Check the display style for something that will resolve to grid.
+    RefPtr<nsStyleContext> styleContext =
+      nsComputedDOMStyle::GetStyleContext(aElement, nullptr, nullptr);
+    if (styleContext) {
+      const nsStyleDisplay* display = styleContext->StyleDisplay();
+      return (display->mDisplay == StyleDisplay::Grid ||
+              display->mDisplay == StyleDisplay::InlineGrid);
+    }
+    return false;
+  };
+
+  GetElementsByMatching(IsDisplayGrid, aElements);
+}
+
+void
+Element::GetElementsByMatching(nsElementMatchFunc aFunc,
+                               nsTArray<RefPtr<Element>>& aElements)
+{
+  for (nsINode* cur = this; cur; cur = cur->GetNextNode(this)) {
+    if (cur->IsElement() && aFunc(cur->AsElement())) {
+      aElements.AppendElement(cur->AsElement());
+    }
+  }
+}
+
+
 /**
  * Returns the count of descendants (inclusive of aContent) in
  * the uncomposed document that are explicitly set as editable.
  */
 static uint32_t
 EditableInclusiveDescendantCount(nsIContent* aContent)
 {
   auto htmlElem = nsGenericHTMLElement::FromContent(aContent);
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -979,18 +979,44 @@ public:
 
   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));
   }
 
+  /**
+   * Return an array of all elements and descendants, starting with
+   * this, that have styling which will cause them to generate
+   * a nsFlexContainerFrame during layout. This covers elements
+   * that are not visible, but does not include pseudo-elements.
+   */
+   void GetElementsWithFlex(nsTArray<RefPtr<Element>>& aElements);
+
+  /**
+   * Return an array of all elements and descendants, starting with
+   * this, that have styling which will cause them to generate
+   * a nsGridContainerFrame during layout. This covers elements
+   * that are not visible, but does not include pseudo-elements.
+   */
+  void GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements);
+
 private:
   /**
+   * Define a general matching function that can be passed to
+   * GetElementsByMatching(). Each Element being considered is
+   * passed in.
+   */
+  typedef bool (*nsElementMatchFunc)(Element* aElement);
+
+  void GetElementsByMatching(nsElementMatchFunc aFunc,
+                             nsTArray<RefPtr<Element>>& aElements);
+
+  /**
    * Implement the algorithm specified at
    * https://dom.spec.whatwg.org/#insert-adjacent for both
    * |insertAdjacentElement()| and |insertAdjacentText()| APIs.
    */
   nsINode* InsertAdjacent(const nsAString& aWhere,
                           nsINode* aNode,
                           ErrorResult& aError);
 
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -64,16 +64,20 @@ interface Element : Node {
   boolean webkitMatchesSelector(DOMString selector);
 
   [Pure]
   HTMLCollection getElementsByTagName(DOMString localName);
   [Throws, Pure]
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   [Pure]
   HTMLCollection getElementsByClassName(DOMString classNames);
+  [ChromeOnly, Pure]
+  sequence<Element> getElementsWithFlex();
+  [ChromeOnly, Pure]
+  sequence<Element> getElementsWithGrid();
 
   [CEReactions, Throws, Pure]
   Element? insertAdjacentElement(DOMString where, Element element); // historical
 
   [Throws]
   void insertAdjacentText(DOMString where, DOMString data); // historical
 
   /**