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

  // Initial position could be not set, in that case begin search from root.
  Accessible* root = GetActiveRoot();
  Accessible* accessible = (!aAccessible) ? root : aAccessible;

  RuleCache cache(aRule);

  uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
  accessible = AdjustStartPosition(accessible, cache, &filtered, aResult);
  NS_ENSURE_SUCCESS(*aResult, nullptr);
  if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH))
    return accessible;

  while (true) {
    Accessible* firstChild = nullptr;
    while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) &&
           (firstChild = accessible->FirstChild())) {
      accessible = firstChild;
      *aResult = cache.ApplyFilter(accessible, &filtered);
      NS_ENSURE_SUCCESS(*aResult, nullptr);

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

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

      sibling = temp->NextSibling();

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

    if (!sibling)
      break;

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

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

  return nullptr;
}
Example #2
0
void
TextRange::Text(nsAString& aText) const
{
  Accessible* current = mStartContainer->GetChildAtOffset(mStartOffset);
  uint32_t startIntlOffset =
    mStartOffset - mStartContainer->GetChildOffset(current);

  while (current && TextInternal(aText, current, startIntlOffset)) {
    current = current->Parent();
    if (!current)
      break;

    current = current->NextSibling();
  }
}
Example #3
0
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;
}
Example #4
0
NS_IMETHODIMP
nsAccessiblePivot::MoveNextByText(TextBoundaryType aBoundary, bool* aResult)
{
  NS_ENSURE_ARG(aResult);

  *aResult = false;

  int32_t tempStart = mStartOffset, tempEnd = mEndOffset;
  Accessible* tempPosition = mPosition;
  Accessible* root = GetActiveRoot();
  while (true) {
    Accessible* curPosition = tempPosition;
    HyperTextAccessible* text = nullptr;
    // Find the nearest text node using a preorder traversal starting from
    // the current node.
    if (!(text = tempPosition->AsHyperText())) {
      text = SearchForText(tempPosition, false);
      if (!text)
        return NS_OK;
      if (text != curPosition)
        tempStart = tempEnd = -1;
      tempPosition = text;
    }

    // If the search led to the parent of the node we started on (e.g. when
    // starting on a text leaf), start the text movement from the end of that
    // node, otherwise we just default to 0.
    if (tempEnd == -1)
      tempEnd = text == curPosition->Parent() ?
                text->GetChildOffset(curPosition) : 0;

    // If there's no more text on the current node, try to find the next text
    // node; if there isn't one, bail out.
    if (tempEnd == static_cast<int32_t>(text->CharacterCount())) {
      if (tempPosition == root)
        return NS_OK;

      // If we're currently sitting on a link, try move to either the next
      // sibling or the parent, whichever is closer to the current end
      // offset. Otherwise, do a forward search for the next node to land on
      // (we don't do this in the first case because we don't want to go to the
      // subtree).
      Accessible* sibling = tempPosition->NextSibling();
      if (tempPosition->IsLink()) {
        if (sibling && sibling->IsLink()) {
          tempStart = tempEnd = -1;
          tempPosition = sibling;
        } else {
          tempStart = tempPosition->StartOffset();
          tempEnd = tempPosition->EndOffset();
          tempPosition = tempPosition->Parent();
        }
      } else {
        tempPosition = SearchForText(tempPosition, false);
        if (!tempPosition)
          return NS_OK;
        tempStart = tempEnd = -1;
      }
      continue;
    }

    AccessibleTextBoundary startBoundary, endBoundary;
    switch (aBoundary) {
      case CHAR_BOUNDARY:
        startBoundary = nsIAccessibleText::BOUNDARY_CHAR;
        endBoundary = nsIAccessibleText::BOUNDARY_CHAR;
        break;
      case WORD_BOUNDARY:
        startBoundary = nsIAccessibleText::BOUNDARY_WORD_START;
        endBoundary = nsIAccessibleText::BOUNDARY_WORD_END;
        break;
      default:
        return NS_ERROR_INVALID_ARG;
    }

    nsAutoString unusedText;
    int32_t newStart = 0, newEnd = 0, currentEnd = tempEnd;
    text->TextAtOffset(tempEnd, endBoundary, &newStart, &tempEnd, unusedText);
    text->TextBeforeOffset(tempEnd, startBoundary, &newStart, &newEnd, unusedText);
    int32_t potentialStart = newEnd == tempEnd ? newStart : newEnd;
    tempStart = potentialStart > tempStart ? potentialStart : currentEnd;

    // The offset range we've obtained might have embedded characters in it,
    // limit the range to the start of the first occurrence of an embedded
    // character.
    Accessible* childAtOffset = nullptr;
    for (int32_t i = tempStart; i < tempEnd; i++) {
      childAtOffset = text->GetChildAtOffset(i);
      if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset)) {
        tempEnd = i;
        break;
      }
    }
    // If there's an embedded character at the very start of the range, we
    // instead want to traverse into it. So restart the movement with
    // the child as the starting point.
    if (childAtOffset && nsAccUtils::IsEmbeddedObject(childAtOffset) &&
        tempStart == static_cast<int32_t>(childAtOffset->StartOffset())) {
      tempPosition = childAtOffset;
      tempStart = tempEnd = -1;
      continue;
    }

    *aResult = true;

    Accessible* startPosition = mPosition;
    int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
    mPosition = tempPosition;
    mStartOffset = tempStart;
    mEndOffset = tempEnd;
    NotifyOfPivotChange(startPosition, oldStart, oldEnd,
                        nsIAccessiblePivot::REASON_TEXT);
    return NS_OK;
  }
}
Example #5
0
uint32_t AccGroupInfo::TotalItemCount(Accessible* aContainer,
                                      bool* aIsHierarchical) {
  uint32_t itemCount = 0;
  switch (aContainer->Role()) {
    case roles::TABLE:
      if (nsCoreUtils::GetUIntAttr(aContainer->GetContent(),
                                   nsGkAtoms::aria_rowcount,
                                   (int32_t*)&itemCount)) {
        break;
      }

      if (TableAccessible* tableAcc = aContainer->AsTable()) {
        return tableAcc->RowCount();
      }

      break;
    case roles::ROW:
      if (Accessible* table = nsAccUtils::TableFor(aContainer)) {
        if (nsCoreUtils::GetUIntAttr(table->GetContent(),
                                     nsGkAtoms::aria_colcount,
                                     (int32_t*)&itemCount)) {
          break;
        }

        if (TableAccessible* tableAcc = table->AsTable()) {
          return tableAcc->ColCount();
        }
      }

      break;
    case roles::OUTLINE:
    case roles::LIST:
    case roles::MENUBAR:
    case roles::MENUPOPUP:
    case roles::COMBOBOX:
    case roles::GROUPING:
    case roles::TREE_TABLE:
    case roles::COMBOBOX_LIST:
    case roles::LISTBOX:
    case roles::DEFINITION_LIST:
    case roles::EDITCOMBOBOX:
    case roles::RADIO_GROUP:
    case roles::PAGETABLIST: {
      Accessible* childItem = AccGroupInfo::FirstItemOf(aContainer);
      if (!childItem) {
        childItem = aContainer->FirstChild();
        if (childItem && childItem->IsTextLeaf()) {
          // First child can be a text leaf, check its sibling for an item.
          childItem = childItem->NextSibling();
        }
      }

      if (childItem) {
        GroupPos groupPos = childItem->GroupPosition();
        itemCount = groupPos.setSize;
        if (groupPos.level && aIsHierarchical) {
          *aIsHierarchical = true;
        }
      }
      break;
    }
    default:
      break;
  }

  return itemCount;
}