Bug 1373798 part 3. Rewrite our existing checks for the state of the "dir" attr on top of the new event state flags. r=mystor draft
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 19 Jun 2017 14:42:01 -0400
changeset 596743 2771f8fb377b051b8dc8d93d08a2360817331f21
parent 596742 b2e588d6aab951eeb46b5b1e9321c82c83e0afa4
child 596744 4b2b63c228af4b22f5bc998ee0f2ac4445f618f8
push id64748
push userbzbarsky@mozilla.com
push dateMon, 19 Jun 2017 18:45:34 +0000
reviewersmystor
bugs1373798
milestone56.0a1
Bug 1373798 part 3. Rewrite our existing checks for the state of the "dir" attr on top of the new event state flags. r=mystor MozReview-Commit-ID: LpCYABK5ZRN
dom/base/DirectionalityUtils.cpp
dom/base/Element.h
dom/base/nsIContentInlines.h
dom/base/nsINode.h
dom/html/HTMLUnknownElement.h
dom/html/nsGenericHTMLElement.cpp
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -668,17 +668,17 @@ WalkAncestorsResetAutoDirection(Element*
   }
 }
 
 void
 WalkDescendantsResetAutoDirection(Element* aElement)
 {
   nsIContent* child = aElement->GetFirstChild();
   while (child) {
-    if (child->HasDirAuto()) {
+    if (child->IsElement() && child->AsElement()->HasDirAuto()) {
       child = child->GetNextNonChildNode(aElement);
       continue;
     }
 
     if (child->NodeType() == nsIDOMNode::TEXT_NODE &&
         child->HasTextNodeDirectionalityMap()) {
       nsTextNodeDirectionalityMap::ResetTextNodeDirection(static_cast<nsTextNode*>(child), nullptr);
       // Don't call nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child)
@@ -731,17 +731,17 @@ WalkDescendantsSetDirAuto(Element* aElem
   }
 }
 
 void
 WalkDescendantsClearAncestorDirAuto(Element* aElement)
 {
   nsIContent* child = aElement->GetFirstChild();
   while (child) {
-    if (child->HasDirAuto()) {
+    if (child->IsElement() && child->AsElement()->HasDirAuto()) {
       child = child->GetNextNonChildNode(aElement);
       continue;
     }
 
     child->ClearAncestorHasDirAuto();
     child = child->GetNextNode(aElement);
   }
 }
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -300,16 +300,33 @@ public:
   void UnlockStyleStates(EventStates aStates);
 
   /**
    * Clear all style state locks on this element.
    */
   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.
    */
   DeclarationBlock* GetInlineStyleDeclaration() const;
 
   /**
    * Get the mapped attributes, if any, for this element.
    */
   const nsMappedAttributes* GetMappedAttributes() const;
@@ -442,25 +459,16 @@ public:
      */
     if (aNotify) {
       UpdateState(true);
     }
   }
 
   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* GetFlattenedTreeParentElement() const;
   inline Element* GetFlattenedTreeParentElementForStyle() const;
 
   bool HasDirtyDescendantsForServo() const
   {
     MOZ_ASSERT(IsStyledByServo());
--- a/dom/base/nsIContentInlines.h
+++ b/dom/base/nsIContentInlines.h
@@ -95,9 +95,15 @@ nsIContent::GetFlattenedTreeParent() con
 }
 
 inline nsINode*
 nsINode::GetFlattenedTreeParentNodeForStyle() const
 {
   return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
 }
 
+inline bool
+nsINode::NodeOrAncestorHasDirAuto() const
+{
+  return AncestorHasDirAuto() || (IsElement() && AsElement()->HasDirAuto());
+}
+
 #endif // nsIContentInlines_h
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -1525,29 +1525,28 @@ private:
     // Set if element has pointer locked
     ElementHasPointerLock,
     // Set if the node may have DOMMutationObserver attached to it.
     NodeMayHaveDOMMutationObserver,
     // Set if node is Content
     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,
     // Set if the node is a text node descendant of a node with dir=auto
     // 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
     // only accurate for elements bound to a document
     ElementIsInStyleScope,
     // Set if the element is a scoped style sheet root
     ElementIsScopedStyleRoot,
     // Set if the node is handling a click.
@@ -1632,27 +1631,16 @@ public:
   bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
   void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
   void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
   bool MayHaveAnimations() const { return GetBoolFlag(ElementHasAnimations); }
   void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
   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");
     SetBoolFlag(NodeHasDirAutoSet);
   }
   void ClearHasDirAutoSet() {
     MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
                "ClearHasDirAutoSet on text node");
@@ -1671,26 +1659,22 @@ public:
     ClearBoolFlag(NodeHasTextNodeDirectionalityMap);
   }
   bool HasTextNodeDirectionalityMap() const {
     MOZ_ASSERT(NodeType() == nsIDOMNode::TEXT_NODE,
                "HasTextNodeDirectionalityMap on non-text node");
     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");
     SetBoolFlag(ElementIsInStyleScope, aValue);
   }
   void SetIsElementInStyleScope() {
     MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
     SetBoolFlag(ElementIsInStyleScope);
--- a/dom/html/HTMLUnknownElement.h
+++ b/dom/html/HTMLUnknownElement.h
@@ -24,17 +24,16 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   explicit HTMLUnknownElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
     if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
       AddStatesSilently(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
-      SetHasDirAuto();
     }
   }
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
 
 protected:
   virtual ~HTMLUnknownElement() {}
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -734,43 +734,36 @@ nsGenericHTMLElement::AfterSetAttr(int32
       // IntrinsicState, so we manually recompute our dir-related event states
       // here and send the relevant update notifications.
       EventStates dirStates;
       if (aValue && aValue->Type() == nsAttrValue::eEnum) {
         SetHasValidDir();
         dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
         Directionality dirValue = (Directionality)aValue->GetEnumValue();
         if (dirValue == eDir_Auto) {
-          SetHasDirAuto();
           dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
-          ClearHasFixedDir();
         } else {
           dir = dirValue;
           SetDirectionality(dir, aNotify);
-          ClearHasDirAuto();
-          SetHasFixedDir();
           if (dirValue == eDir_LTR) {
             dirStates |= NS_EVENT_STATE_DIR_ATTR_LTR;
           } else {
             MOZ_ASSERT(dirValue == eDir_RTL);
             dirStates |= NS_EVENT_STATE_DIR_ATTR_RTL;
           }
         }
       } else {
         if (aValue) {
           // We have a value, just not a valid one.
           dirStates |= NS_EVENT_STATE_HAS_DIR_ATTR;
         }
         ClearHasValidDir();
-        ClearHasFixedDir();
         if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
-          SetHasDirAuto();
           dirStates |= NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;
         } else {
-          ClearHasDirAuto();
           recomputeDirectionality = true;
         }
       }
       // Now figure out what's changed about our dir states.
       EventStates oldDirStates = State() & DIR_ATTR_STATES;
       EventStates changedStates = dirStates ^ oldDirStates;
       ToggleStates(changedStates, aNotify);
       if (recomputeDirectionality) {