style: Add a Document::elements_with_id API. draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 27 Oct 2017 11:45:34 +0200
changeset 690477 6b97923790f04e48b9c4e7d6eb2fa7229328c96f
parent 690476 f893dff589cbc67625109afce0a3b39ccc0be836
child 690478 d925490a884bedba8c81459914c679a20bc3a7b7
push id87308
push userbmo:emilio@crisal.io
push dateThu, 02 Nov 2017 01:16:37 +0000
milestone58.0a1
style: Add a Document::elements_with_id API. MozReview-Commit-ID: BNtbJp0RI68
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
servo/components/style/dom.rs
servo/components/style/gecko/wrapper.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2866,8 +2866,17 @@ Gecko_ContentList_AppendAll(
   MOZ_ASSERT(aList);
 
   aList->SetCapacity(aLength);
 
   for (size_t i = 0; i < aLength; ++i) {
     aList->AppendElement(const_cast<Element*>(aElements[i]));
   }
 }
+
+const nsTArray<Element*>*
+Gecko_GetElementsWithId(const nsIDocument* aDocument, nsAtom* aId)
+{
+  MOZ_ASSERT(aDocument);
+  MOZ_ASSERT(aId);
+
+  return aDocument->GetAllElementsForId(nsDependentAtomString(aId));
+}
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -712,11 +712,15 @@ void Gecko_ReportUnexpectedCSSError(mozi
                                     uint32_t lineNumber,
                                     uint32_t colNumber);
 
 // DOM APIs.
 void Gecko_ContentList_AppendAll(nsSimpleContentList* aContentList,
                                  const RawGeckoElement** aElements,
                                  size_t aLength);
 
+const nsTArray<mozilla::dom::Element*>* Gecko_GetElementsWithId(
+    const nsIDocument* aDocument,
+    nsAtom* aId);
+
 } // extern "C"
 
 #endif // mozilla_ServoBindings_h
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -470,16 +470,17 @@ structs-types = [
     "nsIDocument",
     "nsIDocument_DocumentTheme",
     "nsSimpleContentList",
     "RawGeckoAnimationPropertySegment",
     "RawGeckoComputedTiming",
     "RawGeckoCSSPropertyIDList",
     "RawGeckoDocument",
     "RawGeckoElement",
+    "Element",
     "RawGeckoKeyframeList",
     "RawGeckoPropertyValuePairList",
     "RawGeckoComputedKeyframeValuesList",
     "RawGeckoFontFaceRuleList",
     "RawGeckoNode",
     "RawServoAnimationValue",
     "RawGeckoServoAnimationValueList",
     "RawServoMediaList",
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -141,16 +141,27 @@ pub trait TDocument : Sized + Copy + Clo
     /// Get this document as a `TNode`.
     fn as_node(&self) -> Self::ConcreteNode;
 
     /// Returns whether this document is an HTML document.
     fn is_html_document(&self) -> bool;
 
     /// Returns the quirks mode of this document.
     fn quirks_mode(&self) -> QuirksMode;
+
+    /// Get a list of elements with a given ID in this document.
+    ///
+    /// Can return an error to signal that this list is not available, or also
+    /// return an empty slice.
+    fn elements_with_id(
+        &self,
+        _id: &Atom,
+    ) -> Result<&[<Self::ConcreteNode as TNode>::ConcreteElement], ()> {
+        Err(())
+    }
 }
 
 /// The `TNode` trait. This is the main generic trait over which the style
 /// system can be implemented.
 pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
     /// The concrete `TElement` type.
     type ConcreteElement: TElement<ConcreteNode = Self>;
 
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -105,16 +105,31 @@ impl<'ld> TDocument for GeckoDocument<'l
 
     fn is_html_document(&self) -> bool {
         self.0.mType == structs::root::nsIDocument_Type::eHTML
     }
 
     fn quirks_mode(&self) -> QuirksMode {
         self.0.mCompatMode.into()
     }
+
+    fn elements_with_id(&self, id: &Atom) -> Result<&[GeckoElement<'ld>], ()> {
+        unsafe {
+            let array = bindings::Gecko_GetElementsWithId(self.0, id.as_ptr());
+            if array.is_null() {
+                return Ok(&[]);
+            }
+
+            let elements: &[*mut RawGeckoElement] = &**array;
+
+            // NOTE(emilio): We rely on the in-memory representation of
+            // GeckoElement<'ld> and *mut RawGeckoElement being the same.
+            Ok(mem::transmute(elements))
+        }
+    }
 }
 
 /// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
 ///
 /// Important: We don't currently refcount the DOM, because the wrapper lifetime
 /// magic guarantees that our LayoutFoo references won't outlive the root, and
 /// we don't mutate any of the references on the Gecko side during restyle.
 ///