Bug 1275766 - Implement Gecko_GetElementId and Gecko_GetClassOrClassList. r=heycam
authorBobby Holley <bobbyholley@gmail.com>
Wed, 25 May 2016 11:16:26 -0700
changeset 338139 fe87fe3e36a93ef95ba922fcfaea60736f992e4b
parent 338138 53c8478b70c0bac9019babd23f1d5076feb1762b
child 338140 f5442ff12b331819dbcc1121053e68231763cb6c
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1275766
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1275766 - Implement Gecko_GetElementId and Gecko_GetClassOrClassList. r=heycam
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1,18 +1,20 @@
 /* -*- 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 "mozilla/ServoBindings.h"
 
+#include "nsAttrValueInlines.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsContentUtils.h"
+#include "nsDOMTokenList.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsINode.h"
 #include "nsIPrincipal.h"
 #include "nsNameSpaceManager.h"
 #include "nsString.h"
 #include "nsStyleStruct.h"
 #include "StyleStructContext.h"
@@ -148,16 +150,77 @@ Gecko_LocalName(RawGeckoElement* aElemen
 
 nsIAtom*
 Gecko_Namespace(RawGeckoElement* aElement)
 {
   int32_t id = aElement->NodeInfo()->NamespaceID();
   return nsContentUtils::NameSpaceManager()->NameSpaceURIAtom(id);
 }
 
+nsIAtom*
+Gecko_GetElementId(RawGeckoElement* aElement)
+{
+  const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::id);
+  return attr ? attr->GetAtomValue() : nullptr;
+}
+
+uint32_t
+Gecko_ClassOrClassList(RawGeckoElement* aElement,
+                       nsIAtom** aClass, nsIAtom*** aClassList)
+{
+  const nsAttrValue* attr = aElement->GetParsedAttr(nsGkAtoms::_class);
+  if (!attr) {
+    return 0;
+  }
+
+  // For class values with only whitespace, Gecko just stores a string. For the
+  // purposes of the style system, there is no class in this case.
+  if (attr->Type() == nsAttrValue::eString) {
+    MOZ_ASSERT(nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+                 attr->GetStringValue()).IsEmpty());
+    return 0;
+  }
+
+  // Single tokens are generally stored as an atom. Check that case.
+  if (attr->Type() == nsAttrValue::eAtom) {
+    *aClass = attr->GetAtomValue();
+    return 1;
+  }
+
+  // At this point we should have an atom array. It is likely, but not
+  // guaranteed, that we have two or more elements in the array.
+  MOZ_ASSERT(attr->Type() == nsAttrValue::eAtomArray);
+  nsTArray<nsCOMPtr<nsIAtom>>* atomArray = attr->GetAtomArrayValue();
+  uint32_t length = atomArray->Length();
+
+  // Special case: zero elements.
+  if (length == 0) {
+    return 0;
+  }
+
+  // Special case: one element.
+  if (length == 1) {
+    *aClass = atomArray->ElementAt(0);
+    return 1;
+  }
+
+  // General case: Two or more elements.
+  //
+  // Note: We could also expose this array as an array of nsCOMPtrs, since
+  // bindgen knows what those look like, and eliminate the reinterpret_cast.
+  // But it's not obvious that that would be preferable.
+  static_assert(sizeof(nsCOMPtr<nsIAtom>) == sizeof(nsIAtom*), "Bad simplification");
+  static_assert(alignof(nsCOMPtr<nsIAtom>) == alignof(nsIAtom*), "Bad simplification");
+
+  nsCOMPtr<nsIAtom>* elements = atomArray->Elements();
+  nsIAtom** rawElements = reinterpret_cast<nsIAtom**>(elements);
+  *aClassList = rawElements;
+  return atomArray->Length();
+}
+
 ServoNodeData*
 Gecko_GetNodeData(RawGeckoNode* aNode)
 {
   return aNode->GetServoNodeData();
 }
 
 void
 Gecko_SetNodeData(RawGeckoNode* aNode, ServoNodeData* aData)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -78,16 +78,32 @@ uint8_t Gecko_ElementState(RawGeckoEleme
 bool Gecko_IsHTMLElementInHTMLDocument(RawGeckoElement* element);
 bool Gecko_IsLink(RawGeckoElement* element);
 bool Gecko_IsTextNode(RawGeckoNode* node);
 bool Gecko_IsVisitedLink(RawGeckoElement* element);
 bool Gecko_IsUnvisitedLink(RawGeckoElement* element);
 bool Gecko_IsRootElement(RawGeckoElement* element);
 nsIAtom* Gecko_LocalName(RawGeckoElement* element);
 nsIAtom* Gecko_Namespace(RawGeckoElement* element);
+nsIAtom* Gecko_GetElementId(RawGeckoElement* element);
+
+// Gets the class or class list (if any) of the Element.
+//
+// The calling convention here is rather hairy, and is optimized for getting
+// Servo the information it needs for hot calls.
+//
+// The return value indicates the number of classes. If zero, neither outparam
+// is valid. If one, the class_ outparam is filled with the atom of the class.
+// If two or more, the classList outparam is set to point to an array of atoms
+// representing the class list.
+//
+// The array is borrowed and the atoms are not addrefed. These values can be
+// invalidated by any DOM mutation. Use them in a tight scope.
+uint32_t Gecko_ClassOrClassList(RawGeckoElement* element,
+                                nsIAtom** class_, nsIAtom*** classList);
 
 // Node data.
 ServoNodeData* Gecko_GetNodeData(RawGeckoNode* node);
 void Gecko_SetNodeData(RawGeckoNode* node, ServoNodeData* data);
 void Servo_DropNodeData(ServoNodeData* data);
 
 // Atoms.
 nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);