NS_IMETHODIMP
nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule,
                            bool* aResult)
{
  NS_ENSURE_ARG(aResult);
  NS_ENSURE_ARG(aRule);

  Accessible* root = GetActiveRoot();
  NS_ENSURE_TRUE(root && !root->IsDefunct(), NS_ERROR_NOT_IN_TREE);

  *aResult = false;
  nsresult rv = NS_OK;
  Accessible* lastAccessible = root;
  Accessible* accessible = nullptr;

  // First go to the last accessible in pre-order
  while (lastAccessible->HasChildren())
    lastAccessible = lastAccessible->LastChild();

  // Search backwards from last accessible and find the last occurrence in the doc
  accessible = SearchBackward(lastAccessible, aRule, true, &rv);
  NS_ENSURE_SUCCESS(rv, rv);

  if (accessible)
    *aResult = MovePivotInternal(accessible, nsAccessiblePivot::REASON_LAST);

  return NS_OK;
}
Accessible*
nsAccessiblePivot::SearchBackward(Accessible* aAccessible,
                                  nsIAccessibleTraversalRule* aRule,
                                  bool aSearchCurrent,
                                  nsresult* aResult)
{
  *aResult = NS_OK;

  // Initial position could be unset, in that case return null.
  if (!aAccessible)
    return nullptr;

  RuleCache cache(aRule);
  uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
  Accessible* accessible = AdjustStartPosition(aAccessible, cache,
                                               &filtered, aResult);
  NS_ENSURE_SUCCESS(*aResult, nullptr);

  if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) {
    return accessible;
  }

  Accessible* root = GetActiveRoot();
  while (accessible != root) {
    Accessible* parent = accessible->Parent();
    int32_t idxInParent = accessible->IndexInParent();
    while (idxInParent > 0) {
      if (!(accessible = parent->GetChildAt(--idxInParent)))
        continue;

      *aResult = cache.ApplyFilter(accessible, &filtered);
      NS_ENSURE_SUCCESS(*aResult, nullptr);

      Accessible* lastChild = nullptr;
      while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) &&
             (lastChild = accessible->LastChild())) {
        parent = accessible;
        accessible = lastChild;
        idxInParent = accessible->IndexInParent();
        *aResult = cache.ApplyFilter(accessible, &filtered);
        NS_ENSURE_SUCCESS(*aResult, nullptr);
      }

      if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)
        return accessible;
    }

    if (!(accessible = parent))
      break;

    *aResult = cache.ApplyFilter(accessible, &filtered);
    NS_ENSURE_SUCCESS(*aResult, nullptr);

    if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)
      return accessible;
  }

  return nullptr;
}
HyperTextAccessible*
nsAccessiblePivot::SearchForText(Accessible* aAccessible, bool aBackward)
{
  Accessible* root = GetActiveRoot();
  Accessible* accessible = aAccessible;
  while (true) {
    Accessible* child = nullptr;

    while ((child = (aBackward ? accessible->LastChild() :
                                 accessible->FirstChild()))) {
      accessible = child;
      if (child->IsHyperText())
        return child->AsHyperText();
    }

    Accessible* sibling = nullptr;
    Accessible* temp = accessible;
    do {
      if (temp == root)
        break;

      if (temp != aAccessible && temp->IsHyperText())
        return temp->AsHyperText();

      sibling = aBackward ? temp->PrevSibling() : temp->NextSibling();

      if (sibling)
        break;
    } while ((temp = temp->Parent()));

    if (!sibling)
      break;

    accessible = sibling;
    if (accessible->IsHyperText())
      return accessible->AsHyperText();
  }

  return nullptr;
}