void
OnSetDirAttr(Element* aElement, const nsAttrValue* aNewValue,
             bool hadValidDir, bool aNotify)
{
  if (aElement->IsHTML() && aElement->NodeInfo()->Equals(nsGkAtoms::input)) {
    return;
  }

  if (aElement->AncestorHasDirAuto()) {
    if (!hadValidDir) {
      // The element is a descendant of an element with dir = auto, is
      // having its dir attribute set, and previously didn't have a valid dir
      // attribute.
      // Check whether any of its text node descendants determine the
      // direction of any of its ancestors, and redetermine their direction
      WalkDescendantsResetAutoDirection(aElement);
    } else if (!aElement->HasValidDir()) {
      // The element is a descendant of an element with dir = auto and is
      // having its dir attribute removed or set to an invalid value.
      // Reset the direction of any of its ancestors whose direction is
      // determined by a text node descendant
      WalkAncestorsResetAutoDirection(aElement, aNotify);
    }
  }

  if (aElement->HasDirAuto()) {
    WalkDescendantsSetDirAuto(aElement, aNotify);
  } else {
    SetDirectionalityOnDescendants(aElement,
                                   RecomputeDirectionality(aElement, aNotify),
                                   aNotify);
  }
}
void ResetDir(mozilla::dom::Element* aElement)
{
  if (aElement->HasDirAutoSet()) {
    nsINode* setByNode =
      static_cast<nsINode*>(aElement->GetProperty(nsGkAtoms::dirAutoSetBy));
    nsTextNodeDirectionalityMap::RemoveElementFromMap(setByNode, aElement);
  }

  if (!aElement->HasDirAuto()) {
    RecomputeDirectionality(aElement, false);
  }
}
void
SetDirOnBind(mozilla::dom::Element* aElement, nsIContent* aParent)
{
  // Set the AncestorHasDirAuto flag, unless this element shouldn't affect
  // ancestors that have dir=auto
  if (!DoesNotParticipateInAutoDirection(aElement) &&
      !aElement->IsHTML(nsGkAtoms::bdi) &&
      aParent && aParent->NodeOrAncestorHasDirAuto()) {
    aElement->SetAncestorHasDirAuto();

    nsIContent* child = aElement->GetFirstChild();
    if (child) {
      // If we are binding an element to the tree that already has descendants,
      // and the parent has NodeHasDirAuto or NodeAncestorHasDirAuto, we need
      // to set NodeAncestorHasDirAuto on all the element's descendants, except
      // for nodes that don't affect the direction of their ancestors.
      do {
        if (child->IsElement() &&
            DoesNotAffectDirectionOfAncestors(child->AsElement())) {
          child = child->GetNextNonChildNode(aElement);
          continue;
        }

        child->SetAncestorHasDirAuto();
        child = child->GetNextNode(aElement);
      } while (child);

      // We may also need to reset the direction of an ancestor with dir=auto
      WalkAncestorsResetAutoDirection(aElement, true);
    }
  }

  if (!aElement->HasDirAuto()) {
    // if the element doesn't have dir=auto, set its own directionality from
    // the dir attribute or by inheriting from its ancestors.
    RecomputeDirectionality(aElement, false);
  }
}