forked from mirrors/gecko-dev
		
	MozReview-Commit-ID: GrBSyR9bABT --HG-- extra : rebase_source : 4d5dab803751cde3f0943ca4649f5820eef1753a
		
			
				
	
	
		
			610 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			610 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* 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 "HTMLSelectAccessible.h"
 | 
						|
 | 
						|
#include "Accessible-inl.h"
 | 
						|
#include "nsAccessibilityService.h"
 | 
						|
#include "nsAccUtils.h"
 | 
						|
#include "DocAccessible.h"
 | 
						|
#include "nsEventShell.h"
 | 
						|
#include "nsTextEquivUtils.h"
 | 
						|
#include "Role.h"
 | 
						|
#include "States.h"
 | 
						|
 | 
						|
#include "nsCOMPtr.h"
 | 
						|
#include "mozilla/dom/HTMLOptionElement.h"
 | 
						|
#include "mozilla/dom/HTMLSelectElement.h"
 | 
						|
#include "nsIComboboxControlFrame.h"
 | 
						|
#include "nsContainerFrame.h"
 | 
						|
#include "nsIListControlFrame.h"
 | 
						|
 | 
						|
using namespace mozilla::a11y;
 | 
						|
using namespace mozilla::dom;
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectListAccessible
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
HTMLSelectListAccessible::
 | 
						|
  HTMLSelectListAccessible(nsIContent* aContent, DocAccessible* aDoc) :
 | 
						|
  AccessibleWrap(aContent, aDoc)
 | 
						|
{
 | 
						|
  mGenericTypes |= eListControl | eSelect;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectListAccessible: Accessible public
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLSelectListAccessible::NativeState()
 | 
						|
{
 | 
						|
  uint64_t state = AccessibleWrap::NativeState();
 | 
						|
  if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple))
 | 
						|
    state |= states::MULTISELECTABLE | states::EXTSELECTABLE;
 | 
						|
 | 
						|
  return state;
 | 
						|
}
 | 
						|
 | 
						|
role
 | 
						|
HTMLSelectListAccessible::NativeRole()
 | 
						|
{
 | 
						|
  return roles::LISTBOX;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectListAccessible: SelectAccessible
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::SelectAll()
 | 
						|
{
 | 
						|
  return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ?
 | 
						|
    AccessibleWrap::SelectAll() : false;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::UnselectAll()
 | 
						|
{
 | 
						|
  return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ?
 | 
						|
    AccessibleWrap::UnselectAll() : false;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectListAccessible: Widgets
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::IsWidget() const
 | 
						|
{
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::IsActiveWidget() const
 | 
						|
{
 | 
						|
  return FocusMgr()->HasDOMFocus(mContent);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::AreItemsOperable() const
 | 
						|
{
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
Accessible*
 | 
						|
HTMLSelectListAccessible::CurrentItem()
 | 
						|
{
 | 
						|
  nsIListControlFrame* listControlFrame = do_QueryFrame(GetFrame());
 | 
						|
  if (listControlFrame) {
 | 
						|
    nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption();
 | 
						|
    if (activeOptionNode) {
 | 
						|
      DocAccessible* document = Document();
 | 
						|
      if (document)
 | 
						|
        return document->GetAccessible(activeOptionNode);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem)
 | 
						|
{
 | 
						|
  aItem->GetContent()->SetAttr(kNameSpaceID_None,
 | 
						|
                               nsGkAtoms::selected, NS_LITERAL_STRING("true"),
 | 
						|
                               true);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectListAccessible::IsAcceptableChild(nsIContent* aEl) const
 | 
						|
{
 | 
						|
  return aEl->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup);
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectOptionAccessible
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
HTMLSelectOptionAccessible::
 | 
						|
  HTMLSelectOptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
 | 
						|
  HyperTextAccessibleWrap(aContent, aDoc)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectOptionAccessible: Accessible public
 | 
						|
 | 
						|
role
 | 
						|
HTMLSelectOptionAccessible::NativeRole()
 | 
						|
{
 | 
						|
  if (GetCombobox())
 | 
						|
    return roles::COMBOBOX_OPTION;
 | 
						|
 | 
						|
  return roles::OPTION;
 | 
						|
}
 | 
						|
 | 
						|
ENameValueFlag
 | 
						|
HTMLSelectOptionAccessible::NativeName(nsString& aName)
 | 
						|
{
 | 
						|
  // CASE #1 -- great majority of the cases
 | 
						|
  // find the label attribute - this is what the W3C says we should use
 | 
						|
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
 | 
						|
  if (!aName.IsEmpty())
 | 
						|
    return eNameOK;
 | 
						|
 | 
						|
  // CASE #2 -- no label parameter, get the first child, 
 | 
						|
  // use it if it is a text node
 | 
						|
  nsIContent* text = mContent->GetFirstChild();
 | 
						|
  if (text && text->IsNodeOfType(nsINode::eTEXT)) {
 | 
						|
    nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName);
 | 
						|
    aName.CompressWhitespace();
 | 
						|
    return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
 | 
						|
  }
 | 
						|
 | 
						|
  return eNameOK;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLSelectOptionAccessible::NativeState()
 | 
						|
{
 | 
						|
  // As a HTMLSelectOptionAccessible we can have the following states:
 | 
						|
  // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN
 | 
						|
  // Upcall to Accessible, but skip HyperTextAccessible impl
 | 
						|
  // because we don't want EDITABLE or SELECTABLE_TEXT
 | 
						|
  uint64_t state = Accessible::NativeState();
 | 
						|
 | 
						|
  Accessible* select = GetSelect();
 | 
						|
  if (!select)
 | 
						|
    return state;
 | 
						|
 | 
						|
  uint64_t selectState = select->State();
 | 
						|
  if (selectState & states::INVISIBLE)
 | 
						|
    return state;
 | 
						|
 | 
						|
  // Are we selected?
 | 
						|
  HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent);
 | 
						|
  bool selected = option && option->Selected();
 | 
						|
  if (selected)
 | 
						|
    state |= states::SELECTED;
 | 
						|
 | 
						|
  if (selectState & states::OFFSCREEN) {
 | 
						|
    state |= states::OFFSCREEN;
 | 
						|
  } else if (selectState & states::COLLAPSED) {
 | 
						|
    // <select> is COLLAPSED: add OFFSCREEN, if not the currently
 | 
						|
    // visible option
 | 
						|
    if (!selected) {
 | 
						|
      state |= states::OFFSCREEN;
 | 
						|
      state ^= states::INVISIBLE;
 | 
						|
    } else {
 | 
						|
      // Clear offscreen and invisible for currently showing option
 | 
						|
      state &= ~(states::OFFSCREEN | states::INVISIBLE);
 | 
						|
      state |= selectState & states::OPAQUE1;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    // XXX list frames are weird, don't rely on Accessible's general
 | 
						|
    // visibility implementation unless they get reimplemented in layout
 | 
						|
    state &= ~states::OFFSCREEN;
 | 
						|
    // <select> is not collapsed: compare bounds to calculate OFFSCREEN
 | 
						|
    Accessible* listAcc = Parent();
 | 
						|
    if (listAcc) {
 | 
						|
      nsIntRect optionRect = Bounds();
 | 
						|
      nsIntRect listRect = listAcc->Bounds();
 | 
						|
      if (optionRect.y < listRect.y ||
 | 
						|
          optionRect.y + optionRect.height > listRect.y + listRect.height) {
 | 
						|
        state |= states::OFFSCREEN;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return state;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLSelectOptionAccessible::NativeInteractiveState() const
 | 
						|
{
 | 
						|
  return NativelyUnavailable() ?
 | 
						|
    states::UNAVAILABLE : states::FOCUSABLE | states::SELECTABLE;
 | 
						|
}
 | 
						|
 | 
						|
int32_t
 | 
						|
HTMLSelectOptionAccessible::GetLevelInternal()
 | 
						|
{
 | 
						|
  nsIContent* parentContent = mContent->GetParent();
 | 
						|
 | 
						|
  int32_t level =
 | 
						|
    parentContent->NodeInfo()->Equals(nsGkAtoms::optgroup) ? 2 : 1;
 | 
						|
 | 
						|
  if (level == 1 && Role() != roles::HEADING)
 | 
						|
    level = 0; // In a single level list, the level is irrelevant
 | 
						|
 | 
						|
  return level;
 | 
						|
}
 | 
						|
 | 
						|
nsRect
 | 
						|
HTMLSelectOptionAccessible::RelativeBounds(nsIFrame** aBoundingFrame) const
 | 
						|
{
 | 
						|
  Accessible* combobox = GetCombobox();
 | 
						|
  if (combobox && (combobox->State() & states::COLLAPSED))
 | 
						|
    return combobox->RelativeBounds(aBoundingFrame);
 | 
						|
 | 
						|
  return HyperTextAccessibleWrap::RelativeBounds(aBoundingFrame);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLSelectOptionAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 | 
						|
{
 | 
						|
  if (aIndex == eAction_Select)
 | 
						|
    aName.AssignLiteral("select");
 | 
						|
}
 | 
						|
 | 
						|
uint8_t
 | 
						|
HTMLSelectOptionAccessible::ActionCount()
 | 
						|
{
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectOptionAccessible::DoAction(uint8_t aIndex)
 | 
						|
{
 | 
						|
  if (aIndex != eAction_Select)
 | 
						|
    return false;
 | 
						|
 | 
						|
  DoCommand();
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLSelectOptionAccessible::SetSelected(bool aSelect)
 | 
						|
{
 | 
						|
  HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent);
 | 
						|
  if (option)
 | 
						|
    option->SetSelected(aSelect);
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectOptionAccessible: Widgets
 | 
						|
 | 
						|
Accessible*
 | 
						|
HTMLSelectOptionAccessible::ContainerWidget() const
 | 
						|
{
 | 
						|
  Accessible* parent = Parent();
 | 
						|
  if (parent && parent->IsHTMLOptGroup())
 | 
						|
    parent = parent->Parent();
 | 
						|
 | 
						|
  return parent && parent->IsListControl() ? parent : nullptr;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLSelectOptGroupAccessible
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
role
 | 
						|
HTMLSelectOptGroupAccessible::NativeRole()
 | 
						|
{
 | 
						|
  return roles::GROUPING;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLSelectOptGroupAccessible::NativeInteractiveState() const
 | 
						|
{
 | 
						|
  return NativelyUnavailable() ? states::UNAVAILABLE : 0;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t
 | 
						|
HTMLSelectOptGroupAccessible::ActionCount()
 | 
						|
{
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLSelectOptGroupAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 | 
						|
{
 | 
						|
  aName.Truncate();
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLSelectOptGroupAccessible::DoAction(uint8_t aIndex)
 | 
						|
{
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxAccessible
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
HTMLComboboxAccessible::
 | 
						|
  HTMLComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
 | 
						|
  AccessibleWrap(aContent, aDoc)
 | 
						|
{
 | 
						|
  mType = eHTMLComboboxType;
 | 
						|
  mGenericTypes |= eCombobox;
 | 
						|
  mStateFlags |= eNoKidsFromDOM;
 | 
						|
 | 
						|
  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
 | 
						|
  if (comboFrame) {
 | 
						|
    nsIFrame* listFrame = comboFrame->GetDropDown();
 | 
						|
    if (listFrame) {
 | 
						|
      mListAccessible = new HTMLComboboxListAccessible(mParent, mContent, mDoc);
 | 
						|
      Document()->BindToDocument(mListAccessible, nullptr);
 | 
						|
      AppendChild(mListAccessible);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxAccessible: Accessible
 | 
						|
 | 
						|
role
 | 
						|
HTMLComboboxAccessible::NativeRole()
 | 
						|
{
 | 
						|
  return roles::COMBOBOX;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxAccessible::RemoveChild(Accessible* aChild)
 | 
						|
{
 | 
						|
  MOZ_ASSERT(aChild == mListAccessible);
 | 
						|
  if (AccessibleWrap::RemoveChild(aChild)) {
 | 
						|
    mListAccessible = nullptr;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLComboboxAccessible::Shutdown()
 | 
						|
{
 | 
						|
  MOZ_ASSERT(mDoc->IsDefunct() || !mListAccessible);
 | 
						|
  if (mListAccessible) {
 | 
						|
    mListAccessible->Shutdown();
 | 
						|
    mListAccessible = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  AccessibleWrap::Shutdown();
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLComboboxAccessible::NativeState()
 | 
						|
{
 | 
						|
  // As a HTMLComboboxAccessible we can have the following states:
 | 
						|
  // FOCUSED, FOCUSABLE, HASPOPUP, EXPANDED, COLLAPSED
 | 
						|
  // Get focus status from base class
 | 
						|
  uint64_t state = Accessible::NativeState();
 | 
						|
 | 
						|
  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
 | 
						|
  if (comboFrame && comboFrame->IsDroppedDown())
 | 
						|
    state |= states::EXPANDED;
 | 
						|
  else
 | 
						|
    state |= states::COLLAPSED;
 | 
						|
 | 
						|
  state |= states::HASPOPUP;
 | 
						|
  return state;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLComboboxAccessible::Description(nsString& aDescription)
 | 
						|
{
 | 
						|
  aDescription.Truncate();
 | 
						|
  // First check to see if combo box itself has a description, perhaps through
 | 
						|
  // tooltip (title attribute) or via aria-describedby
 | 
						|
  Accessible::Description(aDescription);
 | 
						|
  if (!aDescription.IsEmpty())
 | 
						|
    return;
 | 
						|
 | 
						|
  // Otherwise use description of selected option.
 | 
						|
  Accessible* option = SelectedOption();
 | 
						|
  if (option)
 | 
						|
    option->Description(aDescription);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLComboboxAccessible::Value(nsString& aValue)
 | 
						|
{
 | 
						|
  // Use accessible name of selected option.
 | 
						|
  Accessible* option = SelectedOption();
 | 
						|
  if (option)
 | 
						|
    option->Name(aValue);
 | 
						|
}
 | 
						|
 | 
						|
uint8_t
 | 
						|
HTMLComboboxAccessible::ActionCount()
 | 
						|
{
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxAccessible::DoAction(uint8_t aIndex)
 | 
						|
{
 | 
						|
  if (aIndex != eAction_Click)
 | 
						|
    return false;
 | 
						|
 | 
						|
  DoCommand();
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLComboboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
 | 
						|
{
 | 
						|
  if (aIndex != HTMLComboboxAccessible::eAction_Click)
 | 
						|
    return;
 | 
						|
 | 
						|
  nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
 | 
						|
  if (!comboFrame)
 | 
						|
    return;
 | 
						|
 | 
						|
  if (comboFrame->IsDroppedDown())
 | 
						|
    aName.AssignLiteral("close");
 | 
						|
  else
 | 
						|
    aName.AssignLiteral("open");
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxAccessible: Widgets
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxAccessible::IsWidget() const
 | 
						|
{
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxAccessible::IsActiveWidget() const
 | 
						|
{
 | 
						|
  return FocusMgr()->HasDOMFocus(mContent);
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxAccessible::AreItemsOperable() const
 | 
						|
{
 | 
						|
  nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(GetFrame());
 | 
						|
  return comboboxFrame && comboboxFrame->IsDroppedDown();
 | 
						|
}
 | 
						|
 | 
						|
Accessible*
 | 
						|
HTMLComboboxAccessible::CurrentItem()
 | 
						|
{
 | 
						|
  return AreItemsOperable() ? mListAccessible->CurrentItem() : nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
HTMLComboboxAccessible::SetCurrentItem(Accessible* aItem)
 | 
						|
{
 | 
						|
  if (AreItemsOperable())
 | 
						|
    mListAccessible->SetCurrentItem(aItem);
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxAccessible: protected
 | 
						|
 | 
						|
Accessible*
 | 
						|
HTMLComboboxAccessible::SelectedOption() const
 | 
						|
{
 | 
						|
  HTMLSelectElement* select = HTMLSelectElement::FromContent(mContent);
 | 
						|
  int32_t selectedIndex = select->SelectedIndex();
 | 
						|
 | 
						|
  if (selectedIndex >= 0) {
 | 
						|
    HTMLOptionElement* option = select->Item(selectedIndex);
 | 
						|
    if (option) {
 | 
						|
      DocAccessible* document = Document();
 | 
						|
      if (document)
 | 
						|
        return document->GetAccessible(option);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxListAccessible
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
HTMLComboboxListAccessible::
 | 
						|
  HTMLComboboxListAccessible(Accessible* aParent, nsIContent* aContent,
 | 
						|
                             DocAccessible* aDoc) :
 | 
						|
  HTMLSelectListAccessible(aContent, aDoc)
 | 
						|
{
 | 
						|
  mStateFlags |= eSharedNode;
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxAccessible: Accessible
 | 
						|
 | 
						|
nsIFrame*
 | 
						|
HTMLComboboxListAccessible::GetFrame() const
 | 
						|
{
 | 
						|
  nsIFrame* frame = HTMLSelectListAccessible::GetFrame();
 | 
						|
  nsIComboboxControlFrame* comboBox = do_QueryFrame(frame);
 | 
						|
  if (comboBox) {
 | 
						|
    return comboBox->GetDropDown();
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
role
 | 
						|
HTMLComboboxListAccessible::NativeRole()
 | 
						|
{
 | 
						|
  return roles::COMBOBOX_LIST;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t
 | 
						|
HTMLComboboxListAccessible::NativeState()
 | 
						|
{
 | 
						|
  // As a HTMLComboboxListAccessible we can have the following states:
 | 
						|
  // FOCUSED, FOCUSABLE, FLOATING, INVISIBLE
 | 
						|
  // Get focus status from base class
 | 
						|
  uint64_t state = Accessible::NativeState();
 | 
						|
 | 
						|
  nsIComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame());
 | 
						|
  if (comboFrame && comboFrame->IsDroppedDown())
 | 
						|
    state |= states::FLOATING;
 | 
						|
  else
 | 
						|
    state |= states::INVISIBLE;
 | 
						|
 | 
						|
  return state;
 | 
						|
}
 | 
						|
 | 
						|
nsRect
 | 
						|
HTMLComboboxListAccessible::RelativeBounds(nsIFrame** aBoundingFrame) const
 | 
						|
{
 | 
						|
  *aBoundingFrame = nullptr;
 | 
						|
 | 
						|
  Accessible* comboAcc = Parent();
 | 
						|
  if (!comboAcc)
 | 
						|
    return nsRect();
 | 
						|
 | 
						|
  if (0 == (comboAcc->State() & states::COLLAPSED)) {
 | 
						|
    return HTMLSelectListAccessible::RelativeBounds(aBoundingFrame);
 | 
						|
  }
 | 
						|
 | 
						|
  // Get the first option.
 | 
						|
  nsIContent* content = mContent->GetFirstChild();
 | 
						|
  if (!content)
 | 
						|
    return nsRect();
 | 
						|
 | 
						|
  nsIFrame* frame = content->GetPrimaryFrame();
 | 
						|
  if (!frame) {
 | 
						|
    *aBoundingFrame = nullptr;
 | 
						|
    return nsRect();
 | 
						|
  }
 | 
						|
 | 
						|
  *aBoundingFrame = frame->GetParent();
 | 
						|
  return (*aBoundingFrame)->GetRect();
 | 
						|
}
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
// HTMLComboboxListAccessible: Widgets
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxListAccessible::IsActiveWidget() const
 | 
						|
{
 | 
						|
  return mParent && mParent->IsActiveWidget();
 | 
						|
}
 | 
						|
 | 
						|
bool
 | 
						|
HTMLComboboxListAccessible::AreItemsOperable() const
 | 
						|
{
 | 
						|
  return mParent && mParent->AreItemsOperable();
 | 
						|
}
 | 
						|
 |