accessible/src/generic/Accessible.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/accessible/src/generic/Accessible.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3337 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "Accessible-inl.h"
    1.10 +
    1.11 +#include "nsIXBLAccessible.h"
    1.12 +
    1.13 +#include "AccCollector.h"
    1.14 +#include "AccGroupInfo.h"
    1.15 +#include "AccIterator.h"
    1.16 +#include "nsAccUtils.h"
    1.17 +#include "nsAccessibleRelation.h"
    1.18 +#include "nsAccessibilityService.h"
    1.19 +#include "ApplicationAccessible.h"
    1.20 +#include "nsCoreUtils.h"
    1.21 +#include "nsIAccessibleRelation.h"
    1.22 +#include "nsIAccessibleRole.h"
    1.23 +#include "nsEventShell.h"
    1.24 +#include "nsTextEquivUtils.h"
    1.25 +#include "Relation.h"
    1.26 +#include "Role.h"
    1.27 +#include "RootAccessible.h"
    1.28 +#include "States.h"
    1.29 +#include "StyleInfo.h"
    1.30 +#include "TableAccessible.h"
    1.31 +#include "TableCellAccessible.h"
    1.32 +#include "TreeWalker.h"
    1.33 +
    1.34 +#include "nsIDOMElement.h"
    1.35 +#include "nsIDOMNodeFilter.h"
    1.36 +#include "nsIDOMHTMLElement.h"
    1.37 +#include "nsIDOMKeyEvent.h"
    1.38 +#include "nsIDOMTreeWalker.h"
    1.39 +#include "nsIDOMXULButtonElement.h"
    1.40 +#include "nsIDOMXULDocument.h"
    1.41 +#include "nsIDOMXULElement.h"
    1.42 +#include "nsIDOMXULLabelElement.h"
    1.43 +#include "nsIDOMXULSelectCntrlEl.h"
    1.44 +#include "nsIDOMXULSelectCntrlItemEl.h"
    1.45 +#include "nsPIDOMWindow.h"
    1.46 +
    1.47 +#include "nsIDocument.h"
    1.48 +#include "nsIContent.h"
    1.49 +#include "nsIForm.h"
    1.50 +#include "nsIFormControl.h"
    1.51 +
    1.52 +#include "nsDeckFrame.h"
    1.53 +#include "nsLayoutUtils.h"
    1.54 +#include "nsIPresShell.h"
    1.55 +#include "nsIStringBundle.h"
    1.56 +#include "nsPresContext.h"
    1.57 +#include "nsIFrame.h"
    1.58 +#include "nsView.h"
    1.59 +#include "nsIDocShellTreeItem.h"
    1.60 +#include "nsIScrollableFrame.h"
    1.61 +#include "nsFocusManager.h"
    1.62 +
    1.63 +#include "nsXPIDLString.h"
    1.64 +#include "nsUnicharUtils.h"
    1.65 +#include "nsReadableUtils.h"
    1.66 +#include "prdtoa.h"
    1.67 +#include "nsIAtom.h"
    1.68 +#include "nsIURI.h"
    1.69 +#include "nsArrayUtils.h"
    1.70 +#include "nsIMutableArray.h"
    1.71 +#include "nsIObserverService.h"
    1.72 +#include "nsIServiceManager.h"
    1.73 +#include "nsWhitespaceTokenizer.h"
    1.74 +#include "nsAttrName.h"
    1.75 +#include "nsNetUtil.h"
    1.76 +
    1.77 +#ifdef DEBUG
    1.78 +#include "nsIDOMCharacterData.h"
    1.79 +#endif
    1.80 +
    1.81 +#include "mozilla/Assertions.h"
    1.82 +#include "mozilla/EventStates.h"
    1.83 +#include "mozilla/FloatingPoint.h"
    1.84 +#include "mozilla/MouseEvents.h"
    1.85 +#include "mozilla/unused.h"
    1.86 +#include "mozilla/Preferences.h"
    1.87 +#include "mozilla/dom/Element.h"
    1.88 +#include "mozilla/dom/TreeWalker.h"
    1.89 +
    1.90 +using namespace mozilla;
    1.91 +using namespace mozilla::a11y;
    1.92 +
    1.93 +
    1.94 +////////////////////////////////////////////////////////////////////////////////
    1.95 +// Accessible: nsISupports and cycle collection
    1.96 +
    1.97 +NS_IMPL_CYCLE_COLLECTION(Accessible,
    1.98 +                         mContent, mParent, mChildren)
    1.99 +
   1.100 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible)
   1.101 +  NS_INTERFACE_MAP_ENTRY(nsIAccessible)
   1.102 +  if (aIID.Equals(NS_GET_IID(Accessible)))
   1.103 +    foundInterface = static_cast<nsIAccessible*>(this);
   1.104 +  else
   1.105 +  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleSelectable, IsSelect())
   1.106 +  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleValue, HasNumericValue())
   1.107 +  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleHyperLink, IsLink())
   1.108 +  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessible)
   1.109 +NS_INTERFACE_MAP_END
   1.110 +
   1.111 +NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible)
   1.112 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
   1.113 +
   1.114 +Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
   1.115 +  mContent(aContent), mDoc(aDoc),
   1.116 +  mParent(nullptr), mIndexInParent(-1), mChildrenFlags(eChildrenUninitialized),
   1.117 +  mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
   1.118 +  mIndexOfEmbeddedChild(-1), mRoleMapEntry(nullptr)
   1.119 +{
   1.120 +#ifdef NS_DEBUG_X
   1.121 +   {
   1.122 +     nsCOMPtr<nsIPresShell> shell(do_QueryReferent(aShell));
   1.123 +     printf(">>> %p Created Acc - DOM: %p  PS: %p", 
   1.124 +            (void*)static_cast<nsIAccessible*>(this), (void*)aNode,
   1.125 +            (void*)shell.get());
   1.126 +    nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
   1.127 +    if (content) {
   1.128 +      printf(" Con: %s@%p",
   1.129 +             NS_ConvertUTF16toUTF8(content->NodeInfo()->QualifiedName()).get(),
   1.130 +             (void *)content.get());
   1.131 +      nsAutoString buf;
   1.132 +      Name(buf);
   1.133 +      printf(" Name:[%s]", NS_ConvertUTF16toUTF8(buf).get());
   1.134 +     }
   1.135 +     printf("\n");
   1.136 +   }
   1.137 +#endif
   1.138 +}
   1.139 +
   1.140 +Accessible::~Accessible()
   1.141 +{
   1.142 +  NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
   1.143 +}
   1.144 +
   1.145 +NS_IMETHODIMP
   1.146 +Accessible::GetDocument(nsIAccessibleDocument** aDocument)
   1.147 +{
   1.148 +  NS_ENSURE_ARG_POINTER(aDocument);
   1.149 +
   1.150 +  NS_IF_ADDREF(*aDocument = Document());
   1.151 +  return NS_OK;
   1.152 +}
   1.153 +
   1.154 +NS_IMETHODIMP
   1.155 +Accessible::GetDOMNode(nsIDOMNode** aDOMNode)
   1.156 +{
   1.157 +  NS_ENSURE_ARG_POINTER(aDOMNode);
   1.158 +  *aDOMNode = nullptr;
   1.159 +
   1.160 +  nsINode *node = GetNode();
   1.161 +  if (node)
   1.162 +    CallQueryInterface(node, aDOMNode);
   1.163 +
   1.164 +  return NS_OK;
   1.165 +}
   1.166 +
   1.167 +NS_IMETHODIMP
   1.168 +Accessible::GetRootDocument(nsIAccessibleDocument** aRootDocument)
   1.169 +{
   1.170 +  NS_ENSURE_ARG_POINTER(aRootDocument);
   1.171 +
   1.172 +  NS_IF_ADDREF(*aRootDocument = RootAccessible());
   1.173 +  return NS_OK;
   1.174 +}
   1.175 +
   1.176 +NS_IMETHODIMP
   1.177 +Accessible::GetLanguage(nsAString& aLanguage)
   1.178 +{
   1.179 +  Language(aLanguage);
   1.180 +  return NS_OK;
   1.181 +}
   1.182 +
   1.183 +NS_IMETHODIMP
   1.184 +Accessible::GetName(nsAString& aName)
   1.185 +{
   1.186 +  aName.Truncate();
   1.187 +
   1.188 +  if (IsDefunct())
   1.189 +    return NS_ERROR_FAILURE;
   1.190 +
   1.191 +  nsAutoString name;
   1.192 +  Name(name);
   1.193 +  aName.Assign(name);
   1.194 +
   1.195 +  return NS_OK;
   1.196 +}
   1.197 +
   1.198 +ENameValueFlag
   1.199 +Accessible::Name(nsString& aName)
   1.200 +{
   1.201 +  aName.Truncate();
   1.202 +
   1.203 +  if (!HasOwnContent())
   1.204 +    return eNameOK;
   1.205 +
   1.206 +  ARIAName(aName);
   1.207 +  if (!aName.IsEmpty())
   1.208 +    return eNameOK;
   1.209 +
   1.210 +  nsCOMPtr<nsIXBLAccessible> xblAccessible(do_QueryInterface(mContent));
   1.211 +  if (xblAccessible) {
   1.212 +    xblAccessible->GetAccessibleName(aName);
   1.213 +    if (!aName.IsEmpty())
   1.214 +      return eNameOK;
   1.215 +  }
   1.216 +
   1.217 +  ENameValueFlag nameFlag = NativeName(aName);
   1.218 +  if (!aName.IsEmpty())
   1.219 +    return nameFlag;
   1.220 +
   1.221 +  // In the end get the name from tooltip.
   1.222 +  if (mContent->IsHTML()) {
   1.223 +    if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
   1.224 +      aName.CompressWhitespace();
   1.225 +      return eNameFromTooltip;
   1.226 +    }
   1.227 +  } else if (mContent->IsXUL()) {
   1.228 +    if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
   1.229 +      aName.CompressWhitespace();
   1.230 +      return eNameFromTooltip;
   1.231 +    }
   1.232 +  } else if (mContent->IsSVG()) {
   1.233 +    // If user agents need to choose among multiple ‘desc’ or ‘title’ elements
   1.234 +    // for processing, the user agent shall choose the first one.
   1.235 +    for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
   1.236 +         childElm = childElm->GetNextSibling()) {
   1.237 +      if (childElm->IsSVG(nsGkAtoms::desc)) {
   1.238 +        nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
   1.239 +        return eNameFromTooltip;
   1.240 +      }
   1.241 +    }
   1.242 +  }
   1.243 +
   1.244 +  if (nameFlag != eNoNameOnPurpose)
   1.245 +    aName.SetIsVoid(true);
   1.246 +
   1.247 +  return nameFlag;
   1.248 +}
   1.249 +
   1.250 +NS_IMETHODIMP
   1.251 +Accessible::GetDescription(nsAString& aDescription)
   1.252 +{
   1.253 +  if (IsDefunct())
   1.254 +    return NS_ERROR_FAILURE;
   1.255 +
   1.256 +  nsAutoString desc;
   1.257 +  Description(desc);
   1.258 +  aDescription.Assign(desc);
   1.259 +
   1.260 +  return NS_OK;
   1.261 +}
   1.262 +
   1.263 +void
   1.264 +Accessible::Description(nsString& aDescription)
   1.265 +{
   1.266 +  // There are 4 conditions that make an accessible have no accDescription:
   1.267 +  // 1. it's a text node; or
   1.268 +  // 2. It has no DHTML describedby property
   1.269 +  // 3. it doesn't have an accName; or
   1.270 +  // 4. its title attribute already equals to its accName nsAutoString name; 
   1.271 +
   1.272 +  if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT))
   1.273 +    return;
   1.274 +
   1.275 +  nsTextEquivUtils::
   1.276 +    GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
   1.277 +                           aDescription);
   1.278 +
   1.279 +  if (aDescription.IsEmpty()) {
   1.280 +    bool isXUL = mContent->IsXUL();
   1.281 +    if (isXUL) {
   1.282 +      // Try XUL <description control="[id]">description text</description>
   1.283 +      XULDescriptionIterator iter(Document(), mContent);
   1.284 +      Accessible* descr = nullptr;
   1.285 +      while ((descr = iter.Next())) {
   1.286 +        nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
   1.287 +                                                     &aDescription);
   1.288 +      }
   1.289 +    }
   1.290 +
   1.291 +    if (aDescription.IsEmpty()) {
   1.292 +      // Keep the Name() method logic.
   1.293 +      if (mContent->IsHTML()) {
   1.294 +        mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription);
   1.295 +      } else if (mContent->IsXUL()) {
   1.296 +        mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription);
   1.297 +      } else if (mContent->IsSVG()) {
   1.298 +        for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
   1.299 +             childElm = childElm->GetNextSibling()) {
   1.300 +          if (childElm->IsSVG(nsGkAtoms::desc)) {
   1.301 +            nsTextEquivUtils::AppendTextEquivFromContent(this, childElm,
   1.302 +                                                         &aDescription);
   1.303 +            break;
   1.304 +          }
   1.305 +        }
   1.306 +      }
   1.307 +
   1.308 +      if (!aDescription.IsEmpty()) {
   1.309 +        nsAutoString name;
   1.310 +        ENameValueFlag nameFlag = Name(name);
   1.311 +
   1.312 +        // Don't use tooltip for a description if it was used for a name.
   1.313 +        if (nameFlag == eNameFromTooltip)
   1.314 +          aDescription.Truncate();
   1.315 +      }
   1.316 +    }
   1.317 +  }
   1.318 +  aDescription.CompressWhitespace();
   1.319 +}
   1.320 +
   1.321 +NS_IMETHODIMP
   1.322 +Accessible::GetAccessKey(nsAString& aAccessKey)
   1.323 +{
   1.324 +  aAccessKey.Truncate();
   1.325 +
   1.326 +  if (IsDefunct())
   1.327 +    return NS_ERROR_FAILURE;
   1.328 +
   1.329 +  AccessKey().ToString(aAccessKey);
   1.330 +  return NS_OK;
   1.331 +}
   1.332 +
   1.333 +KeyBinding
   1.334 +Accessible::AccessKey() const
   1.335 +{
   1.336 +  if (!HasOwnContent())
   1.337 +    return KeyBinding();
   1.338 +
   1.339 +  uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent);
   1.340 +  if (!key && mContent->IsElement()) {
   1.341 +    Accessible* label = nullptr;
   1.342 +
   1.343 +    // Copy access key from label node.
   1.344 +    if (mContent->IsHTML()) {
   1.345 +      // Unless it is labeled via an ancestor <label>, in which case that would
   1.346 +      // be redundant.
   1.347 +      HTMLLabelIterator iter(Document(), this,
   1.348 +                             HTMLLabelIterator::eSkipAncestorLabel);
   1.349 +      label = iter.Next();
   1.350 +
   1.351 +    } else if (mContent->IsXUL()) {
   1.352 +      XULLabelIterator iter(Document(), mContent);
   1.353 +      label = iter.Next();
   1.354 +    }
   1.355 +
   1.356 +    if (label)
   1.357 +      key = nsCoreUtils::GetAccessKeyFor(label->GetContent());
   1.358 +  }
   1.359 +
   1.360 +  if (!key)
   1.361 +    return KeyBinding();
   1.362 +
   1.363 +  // Get modifier mask. Use ui.key.generalAccessKey (unless it is -1).
   1.364 +  switch (Preferences::GetInt("ui.key.generalAccessKey", -1)) {
   1.365 +  case -1:
   1.366 +    break;
   1.367 +  case nsIDOMKeyEvent::DOM_VK_SHIFT:
   1.368 +    return KeyBinding(key, KeyBinding::kShift);
   1.369 +  case nsIDOMKeyEvent::DOM_VK_CONTROL:
   1.370 +    return KeyBinding(key, KeyBinding::kControl);
   1.371 +  case nsIDOMKeyEvent::DOM_VK_ALT:
   1.372 +    return KeyBinding(key, KeyBinding::kAlt);
   1.373 +  case nsIDOMKeyEvent::DOM_VK_META:
   1.374 +    return KeyBinding(key, KeyBinding::kMeta);
   1.375 +  default:
   1.376 +    return KeyBinding();
   1.377 +  }
   1.378 +
   1.379 +  // Determine the access modifier used in this context.
   1.380 +  nsIDocument* document = mContent->GetCurrentDoc();
   1.381 +  if (!document)
   1.382 +    return KeyBinding();
   1.383 +
   1.384 +  nsCOMPtr<nsIDocShellTreeItem> treeItem(document->GetDocShell());
   1.385 +  if (!treeItem)
   1.386 +    return KeyBinding();
   1.387 +
   1.388 +  nsresult rv = NS_ERROR_FAILURE;
   1.389 +  int32_t modifierMask = 0;
   1.390 +  switch (treeItem->ItemType()) {
   1.391 +    case nsIDocShellTreeItem::typeChrome:
   1.392 +      rv = Preferences::GetInt("ui.key.chromeAccess", &modifierMask);
   1.393 +      break;
   1.394 +    case nsIDocShellTreeItem::typeContent:
   1.395 +      rv = Preferences::GetInt("ui.key.contentAccess", &modifierMask);
   1.396 +      break;
   1.397 +  }
   1.398 +
   1.399 +  return NS_SUCCEEDED(rv) ? KeyBinding(key, modifierMask) : KeyBinding();
   1.400 +}
   1.401 +
   1.402 +KeyBinding
   1.403 +Accessible::KeyboardShortcut() const
   1.404 +{
   1.405 +  return KeyBinding();
   1.406 +}
   1.407 +
   1.408 +NS_IMETHODIMP
   1.409 +Accessible::GetParent(nsIAccessible** aParent)
   1.410 +{
   1.411 +  NS_ENSURE_ARG_POINTER(aParent);
   1.412 +  if (IsDefunct())
   1.413 +    return NS_ERROR_FAILURE;
   1.414 +
   1.415 +  NS_IF_ADDREF(*aParent = Parent());
   1.416 +  return *aParent ? NS_OK : NS_ERROR_FAILURE;
   1.417 +}
   1.418 +
   1.419 +  /* readonly attribute nsIAccessible nextSibling; */
   1.420 +NS_IMETHODIMP
   1.421 +Accessible::GetNextSibling(nsIAccessible** aNextSibling)
   1.422 +{
   1.423 +  NS_ENSURE_ARG_POINTER(aNextSibling);
   1.424 +  *aNextSibling = nullptr;
   1.425 +
   1.426 +  if (IsDefunct())
   1.427 +    return NS_ERROR_FAILURE;
   1.428 +
   1.429 +  nsresult rv = NS_OK;
   1.430 +  NS_IF_ADDREF(*aNextSibling = GetSiblingAtOffset(1, &rv));
   1.431 +  return rv;
   1.432 +}
   1.433 +
   1.434 +  /* readonly attribute nsIAccessible previousSibling; */
   1.435 +NS_IMETHODIMP
   1.436 +Accessible::GetPreviousSibling(nsIAccessible ** aPreviousSibling)
   1.437 +{
   1.438 +  NS_ENSURE_ARG_POINTER(aPreviousSibling);
   1.439 +  *aPreviousSibling = nullptr;
   1.440 +
   1.441 +  if (IsDefunct())
   1.442 +    return NS_ERROR_FAILURE;
   1.443 +
   1.444 +  nsresult rv = NS_OK;
   1.445 +  NS_IF_ADDREF(*aPreviousSibling = GetSiblingAtOffset(-1, &rv));
   1.446 +  return rv;
   1.447 +}
   1.448 +
   1.449 +  /* readonly attribute nsIAccessible firstChild; */
   1.450 +NS_IMETHODIMP
   1.451 +Accessible::GetFirstChild(nsIAccessible** aFirstChild)
   1.452 +{
   1.453 +  NS_ENSURE_ARG_POINTER(aFirstChild);
   1.454 +  *aFirstChild = nullptr;
   1.455 +
   1.456 +  if (IsDefunct())
   1.457 +    return NS_ERROR_FAILURE;
   1.458 +
   1.459 +  NS_IF_ADDREF(*aFirstChild = FirstChild());
   1.460 +  return NS_OK;
   1.461 +}
   1.462 +
   1.463 +  /* readonly attribute nsIAccessible lastChild; */
   1.464 +NS_IMETHODIMP
   1.465 +Accessible::GetLastChild(nsIAccessible** aLastChild)
   1.466 +{
   1.467 +  NS_ENSURE_ARG_POINTER(aLastChild);
   1.468 +  *aLastChild = nullptr;
   1.469 +
   1.470 +  if (IsDefunct())
   1.471 +    return NS_ERROR_FAILURE;
   1.472 +
   1.473 +  NS_IF_ADDREF(*aLastChild = LastChild());
   1.474 +  return NS_OK;
   1.475 +}
   1.476 +
   1.477 +NS_IMETHODIMP
   1.478 +Accessible::GetChildAt(int32_t aChildIndex, nsIAccessible** aChild)
   1.479 +{
   1.480 +  NS_ENSURE_ARG_POINTER(aChild);
   1.481 +  *aChild = nullptr;
   1.482 +
   1.483 +  if (IsDefunct())
   1.484 +    return NS_ERROR_FAILURE;
   1.485 +
   1.486 +  // If child index is negative, then return last child.
   1.487 +  // XXX: do we really need this?
   1.488 +  if (aChildIndex < 0)
   1.489 +    aChildIndex = ChildCount() - 1;
   1.490 +
   1.491 +  Accessible* child = GetChildAt(aChildIndex);
   1.492 +  if (!child)
   1.493 +    return NS_ERROR_INVALID_ARG;
   1.494 +
   1.495 +  NS_ADDREF(*aChild = child);
   1.496 +  return NS_OK;
   1.497 +}
   1.498 +
   1.499 +// readonly attribute nsIArray children;
   1.500 +NS_IMETHODIMP
   1.501 +Accessible::GetChildren(nsIArray** aOutChildren)
   1.502 +{
   1.503 +  NS_ENSURE_ARG_POINTER(aOutChildren);
   1.504 +  *aOutChildren = nullptr;
   1.505 +
   1.506 +  if (IsDefunct())
   1.507 +    return NS_ERROR_FAILURE;
   1.508 +
   1.509 +  nsresult rv = NS_OK;
   1.510 +  nsCOMPtr<nsIMutableArray> children =
   1.511 +    do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
   1.512 +  NS_ENSURE_SUCCESS(rv, rv);
   1.513 +
   1.514 +  uint32_t childCount = ChildCount();
   1.515 +  for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
   1.516 +    nsIAccessible* child = GetChildAt(childIdx);
   1.517 +    children->AppendElement(child, false);
   1.518 +  }
   1.519 +
   1.520 +  NS_ADDREF(*aOutChildren = children);
   1.521 +  return NS_OK;
   1.522 +}
   1.523 +
   1.524 +bool
   1.525 +Accessible::CanHaveAnonChildren()
   1.526 +{
   1.527 +  return true;
   1.528 +}
   1.529 +
   1.530 +/* readonly attribute long childCount; */
   1.531 +NS_IMETHODIMP
   1.532 +Accessible::GetChildCount(int32_t* aChildCount)
   1.533 +{
   1.534 +  NS_ENSURE_ARG_POINTER(aChildCount);
   1.535 +
   1.536 +  if (IsDefunct())
   1.537 +    return NS_ERROR_FAILURE;
   1.538 +
   1.539 +  *aChildCount = ChildCount();
   1.540 +  return NS_OK;
   1.541 +}
   1.542 +
   1.543 +/* readonly attribute long indexInParent; */
   1.544 +NS_IMETHODIMP
   1.545 +Accessible::GetIndexInParent(int32_t* aIndexInParent)
   1.546 +{
   1.547 +  NS_ENSURE_ARG_POINTER(aIndexInParent);
   1.548 +
   1.549 +  *aIndexInParent = IndexInParent();
   1.550 +  return *aIndexInParent != -1 ? NS_OK : NS_ERROR_FAILURE;
   1.551 +}
   1.552 +
   1.553 +void 
   1.554 +Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
   1.555 +{
   1.556 +  nsCOMPtr<nsIStringBundleService> stringBundleService =
   1.557 +    services::GetStringBundleService();
   1.558 +  if (!stringBundleService)
   1.559 +    return;
   1.560 +
   1.561 +  nsCOMPtr<nsIStringBundle> stringBundle;
   1.562 +  stringBundleService->CreateBundle(
   1.563 +    "chrome://global-platform/locale/accessible.properties", 
   1.564 +    getter_AddRefs(stringBundle));
   1.565 +  if (!stringBundle)
   1.566 +    return;
   1.567 +
   1.568 +  nsXPIDLString xsValue;
   1.569 +  nsresult rv = stringBundle->GetStringFromName(aKey.get(), getter_Copies(xsValue));
   1.570 +  if (NS_SUCCEEDED(rv))
   1.571 +    aStringOut.Assign(xsValue);
   1.572 +}
   1.573 +
   1.574 +uint64_t
   1.575 +Accessible::VisibilityState()
   1.576 +{
   1.577 +  nsIFrame* frame = GetFrame();
   1.578 +  if (!frame)
   1.579 +    return states::INVISIBLE;
   1.580 +
   1.581 +  // Walk the parent frame chain to see if there's invisible parent or the frame
   1.582 +  // is in background tab.
   1.583 +  if (!frame->StyleVisibility()->IsVisible())
   1.584 +    return states::INVISIBLE;
   1.585 +
   1.586 +  nsIFrame* curFrame = frame;
   1.587 +  do {
   1.588 +    nsView* view = curFrame->GetView();
   1.589 +    if (view && view->GetVisibility() == nsViewVisibility_kHide)
   1.590 +      return states::INVISIBLE;
   1.591 +
   1.592 +    if (nsLayoutUtils::IsPopup(curFrame))
   1.593 +      return 0;
   1.594 +
   1.595 +    // Offscreen state for background tab content and invisible for not selected
   1.596 +    // deck panel.
   1.597 +    nsIFrame* parentFrame = curFrame->GetParent();
   1.598 +    nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
   1.599 +    if (deckFrame && deckFrame->GetSelectedBox() != curFrame) {
   1.600 +      if (deckFrame->GetContent()->IsXUL() &&
   1.601 +          deckFrame->GetContent()->Tag() == nsGkAtoms::tabpanels)
   1.602 +        return states::OFFSCREEN;
   1.603 +
   1.604 +      NS_NOTREACHED("Children of not selected deck panel are not accessible.");
   1.605 +      return states::INVISIBLE;
   1.606 +    }
   1.607 +
   1.608 +    // If contained by scrollable frame then check that at least 12 pixels
   1.609 +    // around the object is visible, otherwise the object is offscreen.
   1.610 +    nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);
   1.611 +    if (scrollableFrame) {
   1.612 +      nsRect scrollPortRect = scrollableFrame->GetScrollPortRect();
   1.613 +      nsRect frameRect = nsLayoutUtils::TransformFrameRectToAncestor(
   1.614 +        frame, frame->GetRectRelativeToSelf(), parentFrame);
   1.615 +      if (!scrollPortRect.Contains(frameRect)) {
   1.616 +        const nscoord kMinPixels = nsPresContext::CSSPixelsToAppUnits(12);
   1.617 +        scrollPortRect.Deflate(kMinPixels, kMinPixels);
   1.618 +        if (!scrollPortRect.Intersects(frameRect))
   1.619 +          return states::OFFSCREEN;
   1.620 +      }
   1.621 +    }
   1.622 +
   1.623 +    if (!parentFrame) {
   1.624 +      parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
   1.625 +      if (parentFrame && !parentFrame->StyleVisibility()->IsVisible())
   1.626 +        return states::INVISIBLE;
   1.627 +    }
   1.628 +
   1.629 +    curFrame = parentFrame;
   1.630 +  } while (curFrame);
   1.631 +
   1.632 +  // Zero area rects can occur in the first frame of a multi-frame text flow,
   1.633 +  // in which case the rendered text is not empty and the frame should not be
   1.634 +  // marked invisible.
   1.635 +  // XXX Can we just remove this check? Why do we need to mark empty
   1.636 +  // text invisible?
   1.637 +  if (frame->GetType() == nsGkAtoms::textFrame &&
   1.638 +      !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
   1.639 +      frame->GetRect().IsEmpty()) {
   1.640 +    nsAutoString renderedText;
   1.641 +    frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
   1.642 +    if (renderedText.IsEmpty())
   1.643 +      return states::INVISIBLE;
   1.644 +  }
   1.645 +
   1.646 +  return 0;
   1.647 +}
   1.648 +
   1.649 +uint64_t
   1.650 +Accessible::NativeState()
   1.651 +{
   1.652 +  uint64_t state = 0;
   1.653 +
   1.654 +  if (!IsInDocument())
   1.655 +    state |= states::STALE;
   1.656 +
   1.657 +  if (HasOwnContent() && mContent->IsElement()) {
   1.658 +    EventStates elementState = mContent->AsElement()->State();
   1.659 +
   1.660 +    if (elementState.HasState(NS_EVENT_STATE_INVALID))
   1.661 +      state |= states::INVALID;
   1.662 +
   1.663 +    if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
   1.664 +      state |= states::REQUIRED;
   1.665 +
   1.666 +    state |= NativeInteractiveState();
   1.667 +    if (FocusMgr()->IsFocused(this))
   1.668 +      state |= states::FOCUSED;
   1.669 +  }
   1.670 +
   1.671 +  // Gather states::INVISIBLE and states::OFFSCREEN flags for this object.
   1.672 +  state |= VisibilityState();
   1.673 +
   1.674 +  nsIFrame *frame = GetFrame();
   1.675 +  if (frame) {
   1.676 +    if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
   1.677 +      state |= states::FLOATING;
   1.678 +
   1.679 +    // XXX we should look at layout for non XUL box frames, but need to decide
   1.680 +    // how that interacts with ARIA.
   1.681 +    if (HasOwnContent() && mContent->IsXUL() && frame->IsBoxFrame()) {
   1.682 +      const nsStyleXUL* xulStyle = frame->StyleXUL();
   1.683 +      if (xulStyle && frame->IsBoxFrame()) {
   1.684 +        // In XUL all boxes are either vertical or horizontal
   1.685 +        if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL)
   1.686 +          state |= states::VERTICAL;
   1.687 +        else
   1.688 +          state |= states::HORIZONTAL;
   1.689 +      }
   1.690 +    }
   1.691 +  }
   1.692 +
   1.693 +  // Check if a XUL element has the popup attribute (an attached popup menu).
   1.694 +  if (HasOwnContent() && mContent->IsXUL() &&
   1.695 +      mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
   1.696 +    state |= states::HASPOPUP;
   1.697 +
   1.698 +  // Bypass the link states specialization for non links.
   1.699 +  if (!mRoleMapEntry || mRoleMapEntry->roleRule == kUseNativeRole ||
   1.700 +      mRoleMapEntry->role == roles::LINK)
   1.701 +    state |= NativeLinkState();
   1.702 +
   1.703 +  return state;
   1.704 +}
   1.705 +
   1.706 +uint64_t
   1.707 +Accessible::NativeInteractiveState() const
   1.708 +{
   1.709 +  if (!mContent->IsElement())
   1.710 +    return 0;
   1.711 +
   1.712 +  if (NativelyUnavailable())
   1.713 +    return states::UNAVAILABLE;
   1.714 +
   1.715 +  nsIFrame* frame = GetFrame();
   1.716 +  if (frame && frame->IsFocusable())
   1.717 +    return states::FOCUSABLE;
   1.718 +
   1.719 +  return 0;
   1.720 +}
   1.721 +
   1.722 +uint64_t
   1.723 +Accessible::NativeLinkState() const
   1.724 +{
   1.725 +  return 0;
   1.726 +}
   1.727 +
   1.728 +bool
   1.729 +Accessible::NativelyUnavailable() const
   1.730 +{
   1.731 +  if (mContent->IsHTML())
   1.732 +    return mContent->AsElement()->State().HasState(NS_EVENT_STATE_DISABLED);
   1.733 +
   1.734 +  return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
   1.735 +                               nsGkAtoms::_true, eCaseMatters);
   1.736 +}
   1.737 +
   1.738 +  /* readonly attribute boolean focusedChild; */
   1.739 +NS_IMETHODIMP
   1.740 +Accessible::GetFocusedChild(nsIAccessible** aChild)
   1.741 +{
   1.742 +  NS_ENSURE_ARG_POINTER(aChild);
   1.743 +  *aChild = nullptr;
   1.744 +
   1.745 +  if (IsDefunct())
   1.746 +    return NS_ERROR_FAILURE;
   1.747 +
   1.748 +  NS_IF_ADDREF(*aChild = FocusedChild());
   1.749 +  return NS_OK;
   1.750 +}
   1.751 +
   1.752 +Accessible*
   1.753 +Accessible::FocusedChild()
   1.754 +{
   1.755 +  Accessible* focus = FocusMgr()->FocusedAccessible();
   1.756 +  if (focus && (focus == this || focus->Parent() == this))
   1.757 +    return focus;
   1.758 +
   1.759 +  return nullptr;
   1.760 +}
   1.761 +
   1.762 +Accessible*
   1.763 +Accessible::ChildAtPoint(int32_t aX, int32_t aY,
   1.764 +                         EWhichChildAtPoint aWhichChild)
   1.765 +{
   1.766 +  // If we can't find the point in a child, we will return the fallback answer:
   1.767 +  // we return |this| if the point is within it, otherwise nullptr.
   1.768 +  int32_t x = 0, y = 0, width = 0, height = 0;
   1.769 +  nsresult rv = GetBounds(&x, &y, &width, &height);
   1.770 +  NS_ENSURE_SUCCESS(rv, nullptr);
   1.771 +
   1.772 +  Accessible* fallbackAnswer = nullptr;
   1.773 +  if (aX >= x && aX < x + width && aY >= y && aY < y + height)
   1.774 +    fallbackAnswer = this;
   1.775 +
   1.776 +  if (nsAccUtils::MustPrune(this))  // Do not dig any further
   1.777 +    return fallbackAnswer;
   1.778 +
   1.779 +  // Search an accessible at the given point starting from accessible document
   1.780 +  // because containing block (see CSS2) for out of flow element (for example,
   1.781 +  // absolutely positioned element) may be different from its DOM parent and
   1.782 +  // therefore accessible for containing block may be different from accessible
   1.783 +  // for DOM parent but GetFrameForPoint() should be called for containing block
   1.784 +  // to get an out of flow element.
   1.785 +  DocAccessible* accDocument = Document();
   1.786 +  NS_ENSURE_TRUE(accDocument, nullptr);
   1.787 +
   1.788 +  nsIFrame* rootFrame = accDocument->GetFrame();
   1.789 +  NS_ENSURE_TRUE(rootFrame, nullptr);
   1.790 +
   1.791 +  nsIFrame* startFrame = rootFrame;
   1.792 +
   1.793 +  // Check whether the point is at popup content.
   1.794 +  nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
   1.795 +  NS_ENSURE_TRUE(rootWidget, nullptr);
   1.796 +
   1.797 +  nsIntRect rootRect;
   1.798 +  rootWidget->GetScreenBounds(rootRect);
   1.799 +
   1.800 +  WidgetMouseEvent dummyEvent(true, NS_MOUSE_MOVE, rootWidget,
   1.801 +                              WidgetMouseEvent::eSynthesized);
   1.802 +  dummyEvent.refPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
   1.803 +
   1.804 +  nsIFrame* popupFrame = nsLayoutUtils::
   1.805 +    GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
   1.806 +                                     &dummyEvent);
   1.807 +  if (popupFrame) {
   1.808 +    // If 'this' accessible is not inside the popup then ignore the popup when
   1.809 +    // searching an accessible at point.
   1.810 +    DocAccessible* popupDoc =
   1.811 +      GetAccService()->GetDocAccessible(popupFrame->GetContent()->OwnerDoc());
   1.812 +    Accessible* popupAcc =
   1.813 +      popupDoc->GetAccessibleOrContainer(popupFrame->GetContent());
   1.814 +    Accessible* popupChild = this;
   1.815 +    while (popupChild && !popupChild->IsDoc() && popupChild != popupAcc)
   1.816 +      popupChild = popupChild->Parent();
   1.817 +
   1.818 +    if (popupChild == popupAcc)
   1.819 +      startFrame = popupFrame;
   1.820 +  }
   1.821 +
   1.822 +  nsPresContext* presContext = startFrame->PresContext();
   1.823 +  nsRect screenRect = startFrame->GetScreenRectInAppUnits();
   1.824 +    nsPoint offset(presContext->DevPixelsToAppUnits(aX) - screenRect.x,
   1.825 +                   presContext->DevPixelsToAppUnits(aY) - screenRect.y);
   1.826 +  nsIFrame* foundFrame = nsLayoutUtils::GetFrameForPoint(startFrame, offset);
   1.827 +
   1.828 +  nsIContent* content = nullptr;
   1.829 +  if (!foundFrame || !(content = foundFrame->GetContent()))
   1.830 +    return fallbackAnswer;
   1.831 +
   1.832 +  // Get accessible for the node with the point or the first accessible in
   1.833 +  // the DOM parent chain.
   1.834 +  DocAccessible* contentDocAcc = GetAccService()->
   1.835 +    GetDocAccessible(content->OwnerDoc());
   1.836 +
   1.837 +  // contentDocAcc in some circumstances can be nullptr. See bug 729861
   1.838 +  NS_ASSERTION(contentDocAcc, "could not get the document accessible");
   1.839 +  if (!contentDocAcc)
   1.840 +    return fallbackAnswer;
   1.841 +
   1.842 +  Accessible* accessible = contentDocAcc->GetAccessibleOrContainer(content);
   1.843 +  if (!accessible)
   1.844 +    return fallbackAnswer;
   1.845 +
   1.846 +  // Hurray! We have an accessible for the frame that layout gave us.
   1.847 +  // Since DOM node of obtained accessible may be out of flow then we should
   1.848 +  // ensure obtained accessible is a child of this accessible.
   1.849 +  Accessible* child = accessible;
   1.850 +  while (child != this) {
   1.851 +    Accessible* parent = child->Parent();
   1.852 +    if (!parent) {
   1.853 +      // Reached the top of the hierarchy. These bounds were inside an
   1.854 +      // accessible that is not a descendant of this one.
   1.855 +      return fallbackAnswer;
   1.856 +    }
   1.857 +
   1.858 +    // If we landed on a legitimate child of |this|, and we want the direct
   1.859 +    // child, return it here.
   1.860 +    if (parent == this && aWhichChild == eDirectChild)
   1.861 +        return child;
   1.862 +
   1.863 +    child = parent;
   1.864 +  }
   1.865 +
   1.866 +  // Manually walk through accessible children and see if the are within this
   1.867 +  // point. Skip offscreen or invisible accessibles. This takes care of cases
   1.868 +  // where layout won't walk into things for us, such as image map areas and
   1.869 +  // sub documents (XXX: subdocuments should be handled by methods of
   1.870 +  // OuterDocAccessibles).
   1.871 +  uint32_t childCount = accessible->ChildCount();
   1.872 +  for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
   1.873 +    Accessible* child = accessible->GetChildAt(childIdx);
   1.874 +
   1.875 +    int32_t childX, childY, childWidth, childHeight;
   1.876 +    child->GetBounds(&childX, &childY, &childWidth, &childHeight);
   1.877 +    if (aX >= childX && aX < childX + childWidth &&
   1.878 +        aY >= childY && aY < childY + childHeight &&
   1.879 +        (child->State() & states::INVISIBLE) == 0) {
   1.880 +
   1.881 +      if (aWhichChild == eDeepestChild)
   1.882 +        return child->ChildAtPoint(aX, aY, eDeepestChild);
   1.883 +
   1.884 +      return child;
   1.885 +    }
   1.886 +  }
   1.887 +
   1.888 +  return accessible;
   1.889 +}
   1.890 +
   1.891 +// nsIAccessible getChildAtPoint(in long x, in long y)
   1.892 +NS_IMETHODIMP
   1.893 +Accessible::GetChildAtPoint(int32_t aX, int32_t aY,
   1.894 +                            nsIAccessible** aAccessible)
   1.895 +{
   1.896 +  NS_ENSURE_ARG_POINTER(aAccessible);
   1.897 +  *aAccessible = nullptr;
   1.898 +
   1.899 +  if (IsDefunct())
   1.900 +    return NS_ERROR_FAILURE;
   1.901 +
   1.902 +  NS_IF_ADDREF(*aAccessible = ChildAtPoint(aX, aY, eDirectChild));
   1.903 +  return NS_OK;
   1.904 +}
   1.905 +
   1.906 +// nsIAccessible getDeepestChildAtPoint(in long x, in long y)
   1.907 +NS_IMETHODIMP
   1.908 +Accessible::GetDeepestChildAtPoint(int32_t aX, int32_t aY,
   1.909 +                                   nsIAccessible** aAccessible)
   1.910 +{
   1.911 +  NS_ENSURE_ARG_POINTER(aAccessible);
   1.912 +  *aAccessible = nullptr;
   1.913 +
   1.914 +  if (IsDefunct())
   1.915 +    return NS_ERROR_FAILURE;
   1.916 +
   1.917 +  NS_IF_ADDREF(*aAccessible = ChildAtPoint(aX, aY, eDeepestChild));
   1.918 +  return NS_OK;
   1.919 +}
   1.920 +
   1.921 +void
   1.922 +Accessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame)
   1.923 +{
   1.924 +  nsIFrame* frame = GetFrame();
   1.925 +  if (frame && mContent) {
   1.926 +    nsRect* hitRegionRect = static_cast<nsRect*>(mContent->GetProperty(nsGkAtoms::hitregion));
   1.927 +
   1.928 +    if (hitRegionRect) {
   1.929 +      // This is for canvas fallback content
   1.930 +      // Find a canvas frame the found hit region is relative to.
   1.931 +      nsIFrame* canvasFrame = frame->GetParent();
   1.932 +      while (canvasFrame && (canvasFrame->GetType() != nsGkAtoms::HTMLCanvasFrame))
   1.933 +        canvasFrame = canvasFrame->GetParent();
   1.934 +
   1.935 +      // make the canvas the bounding frame
   1.936 +      if (canvasFrame) {
   1.937 +        *aBoundingFrame = canvasFrame;
   1.938 +
   1.939 +        aTotalBounds = *hitRegionRect;
   1.940 +
   1.941 +        return;
   1.942 +      }
   1.943 +    }
   1.944 +
   1.945 +    *aBoundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
   1.946 +    aTotalBounds = nsLayoutUtils::
   1.947 +      GetAllInFlowRectsUnion(frame, *aBoundingFrame,
   1.948 +                             nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
   1.949 +  }
   1.950 +}
   1.951 +
   1.952 +/* void getBounds (out long x, out long y, out long width, out long height); */
   1.953 +NS_IMETHODIMP
   1.954 +Accessible::GetBounds(int32_t* aX, int32_t* aY,
   1.955 +                      int32_t* aWidth, int32_t* aHeight)
   1.956 +{
   1.957 +  NS_ENSURE_ARG_POINTER(aX);
   1.958 +  *aX = 0;
   1.959 +  NS_ENSURE_ARG_POINTER(aY);
   1.960 +  *aY = 0;
   1.961 +  NS_ENSURE_ARG_POINTER(aWidth);
   1.962 +  *aWidth = 0;
   1.963 +  NS_ENSURE_ARG_POINTER(aHeight);
   1.964 +  *aHeight = 0;
   1.965 +
   1.966 +  if (IsDefunct())
   1.967 +    return NS_ERROR_FAILURE;
   1.968 +
   1.969 +  // This routine will get the entire rectangle for all the frames in this node.
   1.970 +  // -------------------------------------------------------------------------
   1.971 +  //      Primary Frame for node
   1.972 +  //  Another frame, same node                <- Example
   1.973 +  //  Another frame, same node
   1.974 +
   1.975 +  nsRect unionRectTwips;
   1.976 +  nsIFrame* boundingFrame = nullptr;
   1.977 +  GetBoundsRect(unionRectTwips, &boundingFrame);   // Unions up all primary frames for this node and all siblings after it
   1.978 +  NS_ENSURE_STATE(boundingFrame);
   1.979 +
   1.980 +  nsPresContext* presContext = mDoc->PresContext();
   1.981 +  *aX = presContext->AppUnitsToDevPixels(unionRectTwips.x);
   1.982 +  *aY = presContext->AppUnitsToDevPixels(unionRectTwips.y);
   1.983 +  *aWidth = presContext->AppUnitsToDevPixels(unionRectTwips.width);
   1.984 +  *aHeight = presContext->AppUnitsToDevPixels(unionRectTwips.height);
   1.985 +
   1.986 +  // We have the union of the rectangle, now we need to put it in absolute screen coords
   1.987 +  nsIntRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits().
   1.988 +    ToNearestPixels(presContext->AppUnitsPerDevPixel());
   1.989 +  *aX += orgRectPixels.x;
   1.990 +  *aY += orgRectPixels.y;
   1.991 +
   1.992 +  return NS_OK;
   1.993 +}
   1.994 +
   1.995 +NS_IMETHODIMP
   1.996 +Accessible::SetSelected(bool aSelect)
   1.997 +{
   1.998 +  if (IsDefunct())
   1.999 +    return NS_ERROR_FAILURE;
  1.1000 +
  1.1001 +  if (!HasOwnContent())
  1.1002 +    return NS_OK;
  1.1003 +
  1.1004 +  Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
  1.1005 +  if (select) {
  1.1006 +    if (select->State() & states::MULTISELECTABLE) {
  1.1007 +      if (mRoleMapEntry) {
  1.1008 +        if (aSelect) {
  1.1009 +          return mContent->SetAttr(kNameSpaceID_None,
  1.1010 +                                   nsGkAtoms::aria_selected,
  1.1011 +                                   NS_LITERAL_STRING("true"), true);
  1.1012 +        }
  1.1013 +        return mContent->UnsetAttr(kNameSpaceID_None,
  1.1014 +                                   nsGkAtoms::aria_selected, true);
  1.1015 +      }
  1.1016 +
  1.1017 +      return NS_OK;
  1.1018 +    }
  1.1019 +
  1.1020 +    return aSelect ? TakeFocus() : NS_ERROR_FAILURE;
  1.1021 +  }
  1.1022 +
  1.1023 +  return NS_OK;
  1.1024 +}
  1.1025 +
  1.1026 +NS_IMETHODIMP
  1.1027 +Accessible::TakeSelection()
  1.1028 +{
  1.1029 +  if (IsDefunct())
  1.1030 +    return NS_ERROR_FAILURE;
  1.1031 +
  1.1032 +  Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
  1.1033 +  if (select) {
  1.1034 +    if (select->State() & states::MULTISELECTABLE)
  1.1035 +      select->UnselectAll();
  1.1036 +    return SetSelected(true);
  1.1037 +  }
  1.1038 +
  1.1039 +  return NS_ERROR_FAILURE;
  1.1040 +}
  1.1041 +
  1.1042 +NS_IMETHODIMP
  1.1043 +Accessible::TakeFocus()
  1.1044 +{
  1.1045 +  if (IsDefunct())
  1.1046 +    return NS_ERROR_FAILURE;
  1.1047 +
  1.1048 +  nsIFrame *frame = GetFrame();
  1.1049 +  NS_ENSURE_STATE(frame);
  1.1050 +
  1.1051 +  nsIContent* focusContent = mContent;
  1.1052 +
  1.1053 +  // If the accessible focus is managed by container widget then focus the
  1.1054 +  // widget and set the accessible as its current item.
  1.1055 +  if (!frame->IsFocusable()) {
  1.1056 +    Accessible* widget = ContainerWidget();
  1.1057 +    if (widget && widget->AreItemsOperable()) {
  1.1058 +      nsIContent* widgetElm = widget->GetContent();
  1.1059 +      nsIFrame* widgetFrame = widgetElm->GetPrimaryFrame();
  1.1060 +      if (widgetFrame && widgetFrame->IsFocusable()) {
  1.1061 +        focusContent = widgetElm;
  1.1062 +        widget->SetCurrentItem(this);
  1.1063 +      }
  1.1064 +    }
  1.1065 +  }
  1.1066 +
  1.1067 +  nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
  1.1068 +  nsFocusManager* fm = nsFocusManager::GetFocusManager();
  1.1069 +  if (fm)
  1.1070 +    fm->SetFocus(element, 0);
  1.1071 +
  1.1072 +  return NS_OK;
  1.1073 +}
  1.1074 +
  1.1075 +void
  1.1076 +Accessible::XULElmName(DocAccessible* aDocument,
  1.1077 +                       nsIContent* aElm, nsString& aName)
  1.1078 +{
  1.1079 +  /**
  1.1080 +   * 3 main cases for XUL Controls to be labeled
  1.1081 +   *   1 - control contains label="foo"
  1.1082 +   *   2 - control has, as a child, a label element
  1.1083 +   *        - label has either value="foo" or children
  1.1084 +   *   3 - non-child label contains control="controlID"
  1.1085 +   *        - label has either value="foo" or children
  1.1086 +   * Once a label is found, the search is discontinued, so a control
  1.1087 +   *  that has a label child as well as having a label external to
  1.1088 +   *  the control that uses the control="controlID" syntax will use
  1.1089 +   *  the child label for its Name.
  1.1090 +   */
  1.1091 +
  1.1092 +  // CASE #1 (via label attribute) -- great majority of the cases
  1.1093 +  nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl = do_QueryInterface(aElm);
  1.1094 +  if (labeledEl) {
  1.1095 +    labeledEl->GetLabel(aName);
  1.1096 +  } else {
  1.1097 +    nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm);
  1.1098 +    if (itemEl) {
  1.1099 +      itemEl->GetLabel(aName);
  1.1100 +    } else {
  1.1101 +      nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm);
  1.1102 +      // Use label if this is not a select control element which 
  1.1103 +      // uses label attribute to indicate which option is selected
  1.1104 +      if (!select) {
  1.1105 +        nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm));
  1.1106 +        if (xulEl)
  1.1107 +          xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
  1.1108 +      }
  1.1109 +    }
  1.1110 +  }
  1.1111 +
  1.1112 +  // CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
  1.1113 +  if (aName.IsEmpty()) {
  1.1114 +    Accessible* labelAcc = nullptr;
  1.1115 +    XULLabelIterator iter(aDocument, aElm);
  1.1116 +    while ((labelAcc = iter.Next())) {
  1.1117 +      nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
  1.1118 +        do_QueryInterface(labelAcc->GetContent());
  1.1119 +      // Check if label's value attribute is used
  1.1120 +      if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(aName)) && aName.IsEmpty()) {
  1.1121 +        // If no value attribute, a non-empty label must contain
  1.1122 +        // children that define its text -- possibly using HTML
  1.1123 +        nsTextEquivUtils::
  1.1124 +          AppendTextEquivFromContent(labelAcc, labelAcc->GetContent(), &aName);
  1.1125 +      }
  1.1126 +    }
  1.1127 +  }
  1.1128 +
  1.1129 +  aName.CompressWhitespace();
  1.1130 +  if (!aName.IsEmpty())
  1.1131 +    return;
  1.1132 +
  1.1133 +  // Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
  1.1134 +  nsIContent *bindingParent = aElm->GetBindingParent();
  1.1135 +  nsIContent* parent =
  1.1136 +    bindingParent? bindingParent->GetParent() : aElm->GetParent();
  1.1137 +  while (parent) {
  1.1138 +    if (parent->Tag() == nsGkAtoms::toolbaritem &&
  1.1139 +        parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
  1.1140 +      aName.CompressWhitespace();
  1.1141 +      return;
  1.1142 +    }
  1.1143 +    parent = parent->GetParent();
  1.1144 +  }
  1.1145 +}
  1.1146 +
  1.1147 +nsresult
  1.1148 +Accessible::HandleAccEvent(AccEvent* aEvent)
  1.1149 +{
  1.1150 +  NS_ENSURE_ARG_POINTER(aEvent);
  1.1151 +
  1.1152 +  nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
  1.1153 +  NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE);
  1.1154 +
  1.1155 +  nsCOMPtr<nsISimpleEnumerator> observers;
  1.1156 +  obsService->EnumerateObservers(NS_ACCESSIBLE_EVENT_TOPIC,
  1.1157 +                                 getter_AddRefs(observers));
  1.1158 +
  1.1159 +  NS_ENSURE_STATE(observers);
  1.1160 +
  1.1161 +  bool hasObservers = false;
  1.1162 +  observers->HasMoreElements(&hasObservers);
  1.1163 +  if (hasObservers) {
  1.1164 +    nsCOMPtr<nsIAccessibleEvent> event = MakeXPCEvent(aEvent);
  1.1165 +    return obsService->NotifyObservers(event, NS_ACCESSIBLE_EVENT_TOPIC, nullptr);
  1.1166 +  }
  1.1167 +
  1.1168 +  return NS_OK;
  1.1169 +}
  1.1170 +
  1.1171 +NS_IMETHODIMP
  1.1172 +Accessible::GetRole(uint32_t *aRole)
  1.1173 +{
  1.1174 +  NS_ENSURE_ARG_POINTER(aRole);
  1.1175 +  *aRole = nsIAccessibleRole::ROLE_NOTHING;
  1.1176 +
  1.1177 +  if (IsDefunct())
  1.1178 +    return NS_ERROR_FAILURE;
  1.1179 +
  1.1180 +  *aRole = Role();
  1.1181 +  return NS_OK;
  1.1182 +}
  1.1183 +
  1.1184 +NS_IMETHODIMP
  1.1185 +Accessible::GetAttributes(nsIPersistentProperties** aAttributes)
  1.1186 +{
  1.1187 +  NS_ENSURE_ARG_POINTER(aAttributes);
  1.1188 +  *aAttributes = nullptr;
  1.1189 +
  1.1190 +  if (IsDefunct())
  1.1191 +    return NS_ERROR_FAILURE;
  1.1192 +
  1.1193 +  nsCOMPtr<nsIPersistentProperties> attributes = Attributes();
  1.1194 +  attributes.swap(*aAttributes);
  1.1195 +
  1.1196 +  return NS_OK;
  1.1197 +}
  1.1198 +
  1.1199 +already_AddRefed<nsIPersistentProperties>
  1.1200 +Accessible::Attributes()
  1.1201 +{
  1.1202 +  nsCOMPtr<nsIPersistentProperties> attributes = NativeAttributes();
  1.1203 +  if (!HasOwnContent() || !mContent->IsElement())
  1.1204 +    return attributes.forget();
  1.1205 +
  1.1206 +  // 'xml-roles' attribute coming from ARIA.
  1.1207 +  nsAutoString xmlRoles, unused;
  1.1208 +  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::role, xmlRoles)) {
  1.1209 +    attributes->SetStringProperty(NS_LITERAL_CSTRING("xml-roles"),
  1.1210 +                                  xmlRoles, unused);
  1.1211 +  }
  1.1212 +
  1.1213 +  // Expose object attributes from ARIA attributes.
  1.1214 +  aria::AttrIterator attribIter(mContent);
  1.1215 +  nsAutoString name, value;
  1.1216 +  while(attribIter.Next(name, value))
  1.1217 +    attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, unused);
  1.1218 +
  1.1219 +  // If there is no aria-live attribute then expose default value of 'live'
  1.1220 +  // object attribute used for ARIA role of this accessible.
  1.1221 +  if (mRoleMapEntry) {
  1.1222 +    nsAutoString live;
  1.1223 +    nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
  1.1224 +    if (live.IsEmpty()) {
  1.1225 +      if (nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live))
  1.1226 +        nsAccUtils::SetAccAttr(attributes, nsGkAtoms::live, live);
  1.1227 +    }
  1.1228 +  }
  1.1229 +
  1.1230 +  return attributes.forget();
  1.1231 +}
  1.1232 +
  1.1233 +already_AddRefed<nsIPersistentProperties>
  1.1234 +Accessible::NativeAttributes()
  1.1235 +{
  1.1236 +  nsCOMPtr<nsIPersistentProperties> attributes =
  1.1237 +    do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
  1.1238 +
  1.1239 +  nsAutoString unused;
  1.1240 +
  1.1241 +  // We support values, so expose the string value as well, via the valuetext
  1.1242 +  // object attribute. We test for the value interface because we don't want
  1.1243 +  // to expose traditional Value() information such as URL's on links and
  1.1244 +  // documents, or text in an input.
  1.1245 +  if (HasNumericValue()) {
  1.1246 +    nsAutoString valuetext;
  1.1247 +    GetValue(valuetext);
  1.1248 +    attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext,
  1.1249 +                                  unused);
  1.1250 +  }
  1.1251 +
  1.1252 +  // Expose checkable object attribute if the accessible has checkable state
  1.1253 +  if (State() & states::CHECKABLE) {
  1.1254 +    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::checkable,
  1.1255 +                           NS_LITERAL_STRING("true"));
  1.1256 +  }
  1.1257 +
  1.1258 +  // Expose 'explicit-name' attribute.
  1.1259 +  nsAutoString name;
  1.1260 +  if (Name(name) != eNameFromSubtree && !name.IsVoid()) {
  1.1261 +    attributes->SetStringProperty(NS_LITERAL_CSTRING("explicit-name"),
  1.1262 +                                  NS_LITERAL_STRING("true"), unused);
  1.1263 +  }
  1.1264 +
  1.1265 +  // Group attributes (level/setsize/posinset)
  1.1266 +  GroupPos groupPos = GroupPosition();
  1.1267 +  nsAccUtils::SetAccGroupAttrs(attributes, groupPos.level,
  1.1268 +                               groupPos.setSize, groupPos.posInSet);
  1.1269 +
  1.1270 +  // If the accessible doesn't have own content (such as list item bullet or
  1.1271 +  // xul tree item) then don't calculate content based attributes.
  1.1272 +  if (!HasOwnContent())
  1.1273 +    return attributes.forget();
  1.1274 +
  1.1275 +  nsEventShell::GetEventAttributes(GetNode(), attributes);
  1.1276 +
  1.1277 +  // Get container-foo computed live region properties based on the closest
  1.1278 +  // container with the live region attribute. Inner nodes override outer nodes
  1.1279 +  // within the same document. The inner nodes can be used to override live
  1.1280 +  // region behavior on more general outer nodes. However, nodes in outer
  1.1281 +  // documents override nodes in inner documents: outer doc author may want to
  1.1282 +  // override properties on a widget they used in an iframe.
  1.1283 +  nsIContent* startContent = mContent;
  1.1284 +  while (startContent) {
  1.1285 +    nsIDocument* doc = startContent->GetDocument();
  1.1286 +    if (!doc)
  1.1287 +      break;
  1.1288 +
  1.1289 +    nsAccUtils::SetLiveContainerAttributes(attributes, startContent,
  1.1290 +                                           nsCoreUtils::GetRoleContent(doc));
  1.1291 +
  1.1292 +    // Allow ARIA live region markup from outer documents to override
  1.1293 +    nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
  1.1294 +    if (!docShellTreeItem)
  1.1295 +      break;
  1.1296 +
  1.1297 +    nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
  1.1298 +    docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
  1.1299 +    if (!sameTypeParent || sameTypeParent == docShellTreeItem)
  1.1300 +      break;
  1.1301 +
  1.1302 +    nsIDocument* parentDoc = doc->GetParentDocument();
  1.1303 +    if (!parentDoc)
  1.1304 +      break;
  1.1305 +
  1.1306 +    startContent = parentDoc->FindContentForSubDocument(doc);
  1.1307 +  }
  1.1308 +
  1.1309 +  if (!mContent->IsElement())
  1.1310 +    return attributes.forget();
  1.1311 +
  1.1312 +  nsAutoString id;
  1.1313 +  if (nsCoreUtils::GetID(mContent, id))
  1.1314 +    attributes->SetStringProperty(NS_LITERAL_CSTRING("id"), id, unused);
  1.1315 +
  1.1316 +  // Expose class because it may have useful microformat information.
  1.1317 +  nsAutoString _class;
  1.1318 +  if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, _class))
  1.1319 +    nsAccUtils::SetAccAttr(attributes, nsGkAtoms::_class, _class);
  1.1320 +
  1.1321 +  // Expose tag.
  1.1322 +  nsAutoString tagName;
  1.1323 +  mContent->NodeInfo()->GetName(tagName);
  1.1324 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tag, tagName);
  1.1325 +
  1.1326 +  // Expose draggable object attribute.
  1.1327 +  nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mContent);
  1.1328 +  if (htmlElement) {
  1.1329 +    bool draggable = false;
  1.1330 +    htmlElement->GetDraggable(&draggable);
  1.1331 +    if (draggable) {
  1.1332 +      nsAccUtils::SetAccAttr(attributes, nsGkAtoms::draggable,
  1.1333 +                             NS_LITERAL_STRING("true"));
  1.1334 +    }
  1.1335 +  }
  1.1336 +
  1.1337 +  // Don't calculate CSS-based object attributes when no frame (i.e.
  1.1338 +  // the accessible is unattached from the tree).
  1.1339 +  if (!mContent->GetPrimaryFrame())
  1.1340 +    return attributes.forget();
  1.1341 +
  1.1342 +  // CSS style based object attributes.
  1.1343 +  nsAutoString value;
  1.1344 +  StyleInfo styleInfo(mContent->AsElement(), mDoc->PresShell());
  1.1345 +
  1.1346 +  // Expose 'display' attribute.
  1.1347 +  styleInfo.Display(value);
  1.1348 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::display, value);
  1.1349 +
  1.1350 +  // Expose 'text-align' attribute.
  1.1351 +  styleInfo.TextAlign(value);
  1.1352 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textAlign, value);
  1.1353 +
  1.1354 +  // Expose 'text-indent' attribute.
  1.1355 +  styleInfo.TextIndent(value);
  1.1356 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textIndent, value);
  1.1357 +
  1.1358 +  // Expose 'margin-left' attribute.
  1.1359 +  styleInfo.MarginLeft(value);
  1.1360 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginLeft, value);
  1.1361 +
  1.1362 +  // Expose 'margin-right' attribute.
  1.1363 +  styleInfo.MarginRight(value);
  1.1364 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginRight, value);
  1.1365 +
  1.1366 +  // Expose 'margin-top' attribute.
  1.1367 +  styleInfo.MarginTop(value);
  1.1368 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginTop, value);
  1.1369 +
  1.1370 +  // Expose 'margin-bottom' attribute.
  1.1371 +  styleInfo.MarginBottom(value);
  1.1372 +  nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginBottom, value);
  1.1373 +
  1.1374 +  return attributes.forget();
  1.1375 +}
  1.1376 +
  1.1377 +GroupPos
  1.1378 +Accessible::GroupPosition()
  1.1379 +{
  1.1380 +  GroupPos groupPos;
  1.1381 +  if (!HasOwnContent())
  1.1382 +    return groupPos;
  1.1383 +
  1.1384 +  // Get group position from ARIA attributes.
  1.1385 +  nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_level, &groupPos.level);
  1.1386 +  nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_setsize, &groupPos.setSize);
  1.1387 +  nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_posinset, &groupPos.posInSet);
  1.1388 +
  1.1389 +  // If ARIA is missed and the accessible is visible then calculate group
  1.1390 +  // position from hierarchy.
  1.1391 +  if (State() & states::INVISIBLE)
  1.1392 +    return groupPos;
  1.1393 +
  1.1394 +  // Calculate group level if ARIA is missed.
  1.1395 +  if (groupPos.level == 0) {
  1.1396 +    int32_t level = GetLevelInternal();
  1.1397 +    if (level != 0)
  1.1398 +      groupPos.level = level;
  1.1399 +  }
  1.1400 +
  1.1401 +  // Calculate position in group and group size if ARIA is missed.
  1.1402 +  if (groupPos.posInSet == 0 || groupPos.setSize == 0) {
  1.1403 +    int32_t posInSet = 0, setSize = 0;
  1.1404 +    GetPositionAndSizeInternal(&posInSet, &setSize);
  1.1405 +    if (posInSet != 0 && setSize != 0) {
  1.1406 +      if (groupPos.posInSet == 0)
  1.1407 +        groupPos.posInSet = posInSet;
  1.1408 +
  1.1409 +      if (groupPos.setSize == 0)
  1.1410 +        groupPos.setSize = setSize;
  1.1411 +    }
  1.1412 +  }
  1.1413 +
  1.1414 +  return groupPos;
  1.1415 +}
  1.1416 +
  1.1417 +NS_IMETHODIMP
  1.1418 +Accessible::ScriptableGroupPosition(int32_t* aGroupLevel,
  1.1419 +                                    int32_t* aSimilarItemsInGroup,
  1.1420 +                                    int32_t* aPositionInGroup)
  1.1421 +{
  1.1422 +  NS_ENSURE_ARG_POINTER(aGroupLevel);
  1.1423 +  *aGroupLevel = 0;
  1.1424 +
  1.1425 +  NS_ENSURE_ARG_POINTER(aSimilarItemsInGroup);
  1.1426 +  *aSimilarItemsInGroup = 0;
  1.1427 +
  1.1428 +  NS_ENSURE_ARG_POINTER(aPositionInGroup);
  1.1429 +  *aPositionInGroup = 0;
  1.1430 +
  1.1431 +  if (IsDefunct())
  1.1432 +    return NS_ERROR_FAILURE;
  1.1433 +
  1.1434 +  GroupPos groupPos = GroupPosition();
  1.1435 +
  1.1436 +  *aGroupLevel = groupPos.level;
  1.1437 +  *aSimilarItemsInGroup = groupPos.setSize;
  1.1438 +  *aPositionInGroup = groupPos.posInSet;
  1.1439 +
  1.1440 +  return NS_OK;
  1.1441 +}
  1.1442 +
  1.1443 +NS_IMETHODIMP
  1.1444 +Accessible::GetState(uint32_t* aState, uint32_t* aExtraState)
  1.1445 +{
  1.1446 +  NS_ENSURE_ARG_POINTER(aState);
  1.1447 +
  1.1448 +  nsAccUtils::To32States(State(), aState, aExtraState);
  1.1449 +  return NS_OK;
  1.1450 +}
  1.1451 +
  1.1452 +uint64_t
  1.1453 +Accessible::State()
  1.1454 +{
  1.1455 +  if (IsDefunct())
  1.1456 +    return states::DEFUNCT;
  1.1457 +
  1.1458 +  uint64_t state = NativeState();
  1.1459 +  // Apply ARIA states to be sure accessible states will be overridden.
  1.1460 +  ApplyARIAState(&state);
  1.1461 +
  1.1462 +  // If this is an ARIA item of the selectable widget and if it's focused and
  1.1463 +  // not marked unselected explicitly (i.e. aria-selected="false") then expose
  1.1464 +  // it as selected to make ARIA widget authors life easier.
  1.1465 +  if (mRoleMapEntry && !(state & states::SELECTED) &&
  1.1466 +      !mContent->AttrValueIs(kNameSpaceID_None,
  1.1467 +                             nsGkAtoms::aria_selected,
  1.1468 +                             nsGkAtoms::_false, eCaseMatters)) {
  1.1469 +    // Special case for tabs: focused tab or focus inside related tab panel
  1.1470 +    // implies selected state.
  1.1471 +    if (mRoleMapEntry->role == roles::PAGETAB) {
  1.1472 +      if (state & states::FOCUSED) {
  1.1473 +        state |= states::SELECTED;
  1.1474 +      } else {
  1.1475 +        // If focus is in a child of the tab panel surely the tab is selected!
  1.1476 +        Relation rel = RelationByType(RelationType::LABEL_FOR);
  1.1477 +        Accessible* relTarget = nullptr;
  1.1478 +        while ((relTarget = rel.Next())) {
  1.1479 +          if (relTarget->Role() == roles::PROPERTYPAGE &&
  1.1480 +              FocusMgr()->IsFocusWithin(relTarget))
  1.1481 +            state |= states::SELECTED;
  1.1482 +        }
  1.1483 +      }
  1.1484 +    } else if (state & states::FOCUSED) {
  1.1485 +      Accessible* container = nsAccUtils::GetSelectableContainer(this, state);
  1.1486 +      if (container &&
  1.1487 +          !nsAccUtils::HasDefinedARIAToken(container->GetContent(),
  1.1488 +                                           nsGkAtoms::aria_multiselectable)) {
  1.1489 +        state |= states::SELECTED;
  1.1490 +      }
  1.1491 +    }
  1.1492 +  }
  1.1493 +
  1.1494 +  const uint32_t kExpandCollapseStates = states::COLLAPSED | states::EXPANDED;
  1.1495 +  if ((state & kExpandCollapseStates) == kExpandCollapseStates) {
  1.1496 +    // Cannot be both expanded and collapsed -- this happens in ARIA expanded
  1.1497 +    // combobox because of limitation of ARIAMap.
  1.1498 +    // XXX: Perhaps we will be able to make this less hacky if we support
  1.1499 +    // extended states in ARIAMap, e.g. derive COLLAPSED from
  1.1500 +    // EXPANDABLE && !EXPANDED.
  1.1501 +    state &= ~states::COLLAPSED;
  1.1502 +  }
  1.1503 +
  1.1504 +  if (!(state & states::UNAVAILABLE)) {
  1.1505 +    state |= states::ENABLED | states::SENSITIVE;
  1.1506 +
  1.1507 +    // If the object is a current item of container widget then mark it as
  1.1508 +    // ACTIVE. This allows screen reader virtual buffer modes to know which
  1.1509 +    // descendant is the current one that would get focus if the user navigates
  1.1510 +    // to the container widget.
  1.1511 +    Accessible* widget = ContainerWidget();
  1.1512 +    if (widget && widget->CurrentItem() == this)
  1.1513 +      state |= states::ACTIVE;
  1.1514 +  }
  1.1515 +
  1.1516 +  if ((state & states::COLLAPSED) || (state & states::EXPANDED))
  1.1517 +    state |= states::EXPANDABLE;
  1.1518 +
  1.1519 +  // For some reasons DOM node may have not a frame. We tract such accessibles
  1.1520 +  // as invisible.
  1.1521 +  nsIFrame *frame = GetFrame();
  1.1522 +  if (!frame)
  1.1523 +    return state;
  1.1524 +
  1.1525 +  const nsStyleDisplay* display = frame->StyleDisplay();
  1.1526 +  if (display && display->mOpacity == 1.0f &&
  1.1527 +      !(state & states::INVISIBLE)) {
  1.1528 +    state |= states::OPAQUE1;
  1.1529 +  }
  1.1530 +
  1.1531 +  return state;
  1.1532 +}
  1.1533 +
  1.1534 +void
  1.1535 +Accessible::ApplyARIAState(uint64_t* aState) const
  1.1536 +{
  1.1537 +  if (!mContent->IsElement())
  1.1538 +    return;
  1.1539 +
  1.1540 +  dom::Element* element = mContent->AsElement();
  1.1541 +
  1.1542 +  // Test for universal states first
  1.1543 +  *aState |= aria::UniversalStatesFor(element);
  1.1544 +
  1.1545 +  if (mRoleMapEntry) {
  1.1546 +
  1.1547 +    // We only force the readonly bit off if we have a real mapping for the aria
  1.1548 +    // role. This preserves the ability for screen readers to use readonly
  1.1549 +    // (primarily on the document) as the hint for creating a virtual buffer.
  1.1550 +    if (mRoleMapEntry->role != roles::NOTHING)
  1.1551 +      *aState &= ~states::READONLY;
  1.1552 +
  1.1553 +    if (mContent->HasAttr(kNameSpaceID_None, mContent->GetIDAttributeName())) {
  1.1554 +      // If has a role & ID and aria-activedescendant on the container, assume focusable
  1.1555 +      nsIContent *ancestorContent = mContent;
  1.1556 +      while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
  1.1557 +        if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
  1.1558 +            // ancestor has activedescendant property, this content could be active
  1.1559 +          *aState |= states::FOCUSABLE;
  1.1560 +          break;
  1.1561 +        }
  1.1562 +      }
  1.1563 +    }
  1.1564 +  }
  1.1565 +
  1.1566 +  if (*aState & states::FOCUSABLE) {
  1.1567 +    // Special case: aria-disabled propagates from ancestors down to any focusable descendant
  1.1568 +    nsIContent *ancestorContent = mContent;
  1.1569 +    while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
  1.1570 +      if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
  1.1571 +                                       nsGkAtoms::_true, eCaseMatters)) {
  1.1572 +          // ancestor has aria-disabled property, this is disabled
  1.1573 +        *aState |= states::UNAVAILABLE;
  1.1574 +        break;
  1.1575 +      }
  1.1576 +    }    
  1.1577 +  }
  1.1578 +
  1.1579 +  // special case: A native button element whose role got transformed by ARIA to a toggle button
  1.1580 +  if (IsButton())
  1.1581 +    aria::MapToState(aria::eARIAPressed, element, aState);
  1.1582 +
  1.1583 +  if (!mRoleMapEntry)
  1.1584 +    return;
  1.1585 +
  1.1586 +  *aState |= mRoleMapEntry->state;
  1.1587 +
  1.1588 +  if (aria::MapToState(mRoleMapEntry->attributeMap1, element, aState) &&
  1.1589 +      aria::MapToState(mRoleMapEntry->attributeMap2, element, aState))
  1.1590 +    aria::MapToState(mRoleMapEntry->attributeMap3, element, aState);
  1.1591 +
  1.1592 +  // ARIA gridcell inherits editable/readonly states from the grid until it's
  1.1593 +  // overridden.
  1.1594 +  if ((mRoleMapEntry->Is(nsGkAtoms::gridcell) ||
  1.1595 +       mRoleMapEntry->Is(nsGkAtoms::columnheader) ||
  1.1596 +       mRoleMapEntry->Is(nsGkAtoms::rowheader)) &&
  1.1597 +      !(*aState & (states::READONLY | states::EDITABLE))) {
  1.1598 +    const TableCellAccessible* cell = AsTableCell();
  1.1599 +    if (cell) {
  1.1600 +      TableAccessible* table = cell->Table();
  1.1601 +      if (table) {
  1.1602 +        Accessible* grid = table->AsAccessible();
  1.1603 +        uint64_t gridState = 0;
  1.1604 +        grid->ApplyARIAState(&gridState);
  1.1605 +        *aState |= (gridState & (states::READONLY | states::EDITABLE));
  1.1606 +      }
  1.1607 +    }
  1.1608 +  }
  1.1609 +}
  1.1610 +
  1.1611 +NS_IMETHODIMP
  1.1612 +Accessible::GetValue(nsAString& aValue)
  1.1613 +{
  1.1614 +  if (IsDefunct())
  1.1615 +    return NS_ERROR_FAILURE;
  1.1616 +
  1.1617 +  nsAutoString value;
  1.1618 +  Value(value);
  1.1619 +  aValue.Assign(value);
  1.1620 +
  1.1621 +  return NS_OK;
  1.1622 +}
  1.1623 +
  1.1624 +void
  1.1625 +Accessible::Value(nsString& aValue)
  1.1626 +{
  1.1627 +  if (!mRoleMapEntry)
  1.1628 +    return;
  1.1629 +
  1.1630 +  if (mRoleMapEntry->valueRule != eNoValue) {
  1.1631 +    // aria-valuenow is a number, and aria-valuetext is the optional text
  1.1632 +    // equivalent. For the string value, we will try the optional text
  1.1633 +    // equivalent first.
  1.1634 +    if (!mContent->GetAttr(kNameSpaceID_None,
  1.1635 +                           nsGkAtoms::aria_valuetext, aValue)) {
  1.1636 +      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
  1.1637 +                        aValue);
  1.1638 +    }
  1.1639 +    return;
  1.1640 +  }
  1.1641 +
  1.1642 +  // Value of textbox is a textified subtree.
  1.1643 +  if (mRoleMapEntry->Is(nsGkAtoms::textbox)) {
  1.1644 +    nsTextEquivUtils::GetTextEquivFromSubtree(this, aValue);
  1.1645 +    return;
  1.1646 +  }
  1.1647 +
  1.1648 +  // Value of combobox is a text of current or selected item.
  1.1649 +  if (mRoleMapEntry->Is(nsGkAtoms::combobox)) {
  1.1650 +    Accessible* option = CurrentItem();
  1.1651 +    if (!option) {
  1.1652 +      Accessible* listbox = nullptr;
  1.1653 +      IDRefsIterator iter(mDoc, mContent, nsGkAtoms::aria_owns);
  1.1654 +      while ((listbox = iter.Next()) && !listbox->IsListControl());
  1.1655 +
  1.1656 +      if (!listbox) {
  1.1657 +        uint32_t childCount = ChildCount();
  1.1658 +        for (uint32_t idx = 0; idx < childCount; idx++) {
  1.1659 +          Accessible* child = mChildren.ElementAt(idx);
  1.1660 +          if (child->IsListControl())
  1.1661 +            listbox = child;
  1.1662 +        }
  1.1663 +      }
  1.1664 +
  1.1665 +      if (listbox)
  1.1666 +        option = listbox->GetSelectedItem(0);
  1.1667 +    }
  1.1668 +
  1.1669 +    if (option)
  1.1670 +      nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
  1.1671 +  }
  1.1672 +}
  1.1673 +
  1.1674 +double
  1.1675 +Accessible::MaxValue() const
  1.1676 +{
  1.1677 +  return AttrNumericValue(nsGkAtoms::aria_valuemax);
  1.1678 +}
  1.1679 +
  1.1680 +double
  1.1681 +Accessible::MinValue() const
  1.1682 +{
  1.1683 +  return AttrNumericValue(nsGkAtoms::aria_valuemin);
  1.1684 +}
  1.1685 +
  1.1686 +double
  1.1687 +Accessible::Step() const
  1.1688 +{
  1.1689 +  return UnspecifiedNaN<double>(); // no mimimum increment (step) in ARIA.
  1.1690 +}
  1.1691 +
  1.1692 +double
  1.1693 +Accessible::CurValue() const
  1.1694 +{
  1.1695 +  return AttrNumericValue(nsGkAtoms::aria_valuenow);
  1.1696 +}
  1.1697 +
  1.1698 +bool
  1.1699 +Accessible::SetCurValue(double aValue)
  1.1700 +{
  1.1701 +  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
  1.1702 +    return false;
  1.1703 +
  1.1704 +  const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
  1.1705 +  if (State() & kValueCannotChange)
  1.1706 +    return false;
  1.1707 +
  1.1708 +  double checkValue = MinValue();
  1.1709 +  if (!IsNaN(checkValue) && aValue < checkValue)
  1.1710 +    return false;
  1.1711 +
  1.1712 +  checkValue = MaxValue();
  1.1713 +  if (!IsNaN(checkValue) && aValue > checkValue)
  1.1714 +    return false;
  1.1715 +
  1.1716 +  nsAutoString strValue;
  1.1717 +  strValue.AppendFloat(aValue);
  1.1718 +
  1.1719 +  return NS_SUCCEEDED(
  1.1720 +    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
  1.1721 +}
  1.1722 +
  1.1723 +/* void setName (in DOMString name); */
  1.1724 +NS_IMETHODIMP
  1.1725 +Accessible::SetName(const nsAString& aName)
  1.1726 +{
  1.1727 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.1728 +}
  1.1729 +
  1.1730 +NS_IMETHODIMP
  1.1731 +Accessible::GetKeyboardShortcut(nsAString& aKeyBinding)
  1.1732 +{
  1.1733 +  aKeyBinding.Truncate();
  1.1734 +  if (IsDefunct())
  1.1735 +    return NS_ERROR_FAILURE;
  1.1736 +
  1.1737 +  KeyboardShortcut().ToString(aKeyBinding);
  1.1738 +  return NS_OK;
  1.1739 +}
  1.1740 +
  1.1741 +role
  1.1742 +Accessible::ARIATransformRole(role aRole)
  1.1743 +{
  1.1744 +  // XXX: these unfortunate exceptions don't fit into the ARIA table. This is
  1.1745 +  // where the accessible role depends on both the role and ARIA state.
  1.1746 +  if (aRole == roles::PUSHBUTTON) {
  1.1747 +    if (nsAccUtils::HasDefinedARIAToken(mContent, nsGkAtoms::aria_pressed)) {
  1.1748 +      // For simplicity, any existing pressed attribute except "" or "undefined"
  1.1749 +      // indicates a toggle.
  1.1750 +      return roles::TOGGLE_BUTTON;
  1.1751 +    }
  1.1752 +
  1.1753 +    if (mContent->AttrValueIs(kNameSpaceID_None,
  1.1754 +                              nsGkAtoms::aria_haspopup,
  1.1755 +                              nsGkAtoms::_true,
  1.1756 +                              eCaseMatters)) {
  1.1757 +      // For button with aria-haspopup="true".
  1.1758 +      return roles::BUTTONMENU;
  1.1759 +    }
  1.1760 +
  1.1761 +  } else if (aRole == roles::LISTBOX) {
  1.1762 +    // A listbox inside of a combobox needs a special role because of ATK
  1.1763 +    // mapping to menu.
  1.1764 +    if (mParent && mParent->Role() == roles::COMBOBOX) {
  1.1765 +      return roles::COMBOBOX_LIST;
  1.1766 +
  1.1767 +      Relation rel = RelationByType(RelationType::NODE_CHILD_OF);
  1.1768 +      Accessible* targetAcc = nullptr;
  1.1769 +      while ((targetAcc = rel.Next()))
  1.1770 +        if (targetAcc->Role() == roles::COMBOBOX)
  1.1771 +          return roles::COMBOBOX_LIST;
  1.1772 +    }
  1.1773 +
  1.1774 +  } else if (aRole == roles::OPTION) {
  1.1775 +    if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
  1.1776 +      return roles::COMBOBOX_OPTION;
  1.1777 +
  1.1778 +  } else if (aRole == roles::MENUITEM) {
  1.1779 +    // Menuitem has a submenu.
  1.1780 +    if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_haspopup,
  1.1781 +                              nsGkAtoms::_true, eCaseMatters)) {
  1.1782 +      return roles::PARENT_MENUITEM;
  1.1783 +    }
  1.1784 +  }
  1.1785 +
  1.1786 +  return aRole;
  1.1787 +}
  1.1788 +
  1.1789 +role
  1.1790 +Accessible::NativeRole()
  1.1791 +{
  1.1792 +  return roles::NOTHING;
  1.1793 +}
  1.1794 +
  1.1795 +// readonly attribute uint8_t actionCount
  1.1796 +NS_IMETHODIMP
  1.1797 +Accessible::GetActionCount(uint8_t* aActionCount)
  1.1798 +{
  1.1799 +  NS_ENSURE_ARG_POINTER(aActionCount);
  1.1800 +  *aActionCount = 0;
  1.1801 +  if (IsDefunct())
  1.1802 +    return NS_ERROR_FAILURE;
  1.1803 +
  1.1804 +  *aActionCount = ActionCount();
  1.1805 +  return NS_OK;
  1.1806 +}
  1.1807 +
  1.1808 +uint8_t
  1.1809 +Accessible::ActionCount()
  1.1810 +{
  1.1811 +  return GetActionRule() == eNoAction ? 0 : 1;
  1.1812 +}
  1.1813 +
  1.1814 +/* DOMString getAccActionName (in uint8_t index); */
  1.1815 +NS_IMETHODIMP
  1.1816 +Accessible::GetActionName(uint8_t aIndex, nsAString& aName)
  1.1817 +{
  1.1818 +  aName.Truncate();
  1.1819 +
  1.1820 +  if (aIndex != 0)
  1.1821 +    return NS_ERROR_INVALID_ARG;
  1.1822 +
  1.1823 +  if (IsDefunct())
  1.1824 +    return NS_ERROR_FAILURE;
  1.1825 +
  1.1826 +  uint32_t actionRule = GetActionRule();
  1.1827 +
  1.1828 + switch (actionRule) {
  1.1829 +   case eActivateAction:
  1.1830 +     aName.AssignLiteral("activate");
  1.1831 +     return NS_OK;
  1.1832 +
  1.1833 +   case eClickAction:
  1.1834 +     aName.AssignLiteral("click");
  1.1835 +     return NS_OK;
  1.1836 +
  1.1837 +   case ePressAction:
  1.1838 +     aName.AssignLiteral("press");
  1.1839 +     return NS_OK;
  1.1840 +
  1.1841 +   case eCheckUncheckAction:
  1.1842 +   {
  1.1843 +     uint64_t state = State();
  1.1844 +     if (state & states::CHECKED)
  1.1845 +       aName.AssignLiteral("uncheck");
  1.1846 +     else if (state & states::MIXED)
  1.1847 +       aName.AssignLiteral("cycle");
  1.1848 +     else
  1.1849 +       aName.AssignLiteral("check");
  1.1850 +     return NS_OK;
  1.1851 +   }
  1.1852 +
  1.1853 +   case eJumpAction:
  1.1854 +     aName.AssignLiteral("jump");
  1.1855 +     return NS_OK;
  1.1856 +
  1.1857 +   case eOpenCloseAction:
  1.1858 +     if (State() & states::COLLAPSED)
  1.1859 +       aName.AssignLiteral("open");
  1.1860 +     else
  1.1861 +       aName.AssignLiteral("close");
  1.1862 +     return NS_OK;
  1.1863 +
  1.1864 +   case eSelectAction:
  1.1865 +     aName.AssignLiteral("select");
  1.1866 +     return NS_OK;
  1.1867 +
  1.1868 +   case eSwitchAction:
  1.1869 +     aName.AssignLiteral("switch");
  1.1870 +     return NS_OK;
  1.1871 +
  1.1872 +   case eSortAction:
  1.1873 +     aName.AssignLiteral("sort");
  1.1874 +     return NS_OK;
  1.1875 +
  1.1876 +   case eExpandAction:
  1.1877 +     if (State() & states::COLLAPSED)
  1.1878 +       aName.AssignLiteral("expand");
  1.1879 +     else
  1.1880 +       aName.AssignLiteral("collapse");
  1.1881 +     return NS_OK;
  1.1882 +  }
  1.1883 +
  1.1884 +  return NS_ERROR_INVALID_ARG;
  1.1885 +}
  1.1886 +
  1.1887 +// AString getActionDescription(in uint8_t index)
  1.1888 +NS_IMETHODIMP
  1.1889 +Accessible::GetActionDescription(uint8_t aIndex, nsAString& aDescription)
  1.1890 +{
  1.1891 +  // default to localized action name.
  1.1892 +  nsAutoString name;
  1.1893 +  nsresult rv = GetActionName(aIndex, name);
  1.1894 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1895 +
  1.1896 +  TranslateString(name, aDescription);
  1.1897 +  return NS_OK;
  1.1898 +}
  1.1899 +
  1.1900 +// void doAction(in uint8_t index)
  1.1901 +NS_IMETHODIMP
  1.1902 +Accessible::DoAction(uint8_t aIndex)
  1.1903 +{
  1.1904 +  if (aIndex != 0)
  1.1905 +    return NS_ERROR_INVALID_ARG;
  1.1906 +
  1.1907 +  if (IsDefunct())
  1.1908 +    return NS_ERROR_FAILURE;
  1.1909 +
  1.1910 +  if (GetActionRule() != eNoAction) {
  1.1911 +    DoCommand();
  1.1912 +    return NS_OK;
  1.1913 +  }
  1.1914 +
  1.1915 +  return NS_ERROR_INVALID_ARG;
  1.1916 +}
  1.1917 +
  1.1918 +/* DOMString getHelp (); */
  1.1919 +NS_IMETHODIMP Accessible::GetHelp(nsAString& _retval)
  1.1920 +{
  1.1921 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.1922 +}
  1.1923 +
  1.1924 +nsIContent*
  1.1925 +Accessible::GetAtomicRegion() const
  1.1926 +{
  1.1927 +  nsIContent *loopContent = mContent;
  1.1928 +  nsAutoString atomic;
  1.1929 +  while (loopContent && !loopContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_atomic, atomic))
  1.1930 +    loopContent = loopContent->GetParent();
  1.1931 +
  1.1932 +  return atomic.EqualsLiteral("true") ? loopContent : nullptr;
  1.1933 +}
  1.1934 +
  1.1935 +// nsIAccessible getRelationByType()
  1.1936 +NS_IMETHODIMP
  1.1937 +Accessible::GetRelationByType(uint32_t aType, nsIAccessibleRelation** aRelation)
  1.1938 +{
  1.1939 +  NS_ENSURE_ARG_POINTER(aRelation);
  1.1940 +  *aRelation = nullptr;
  1.1941 +
  1.1942 +  NS_ENSURE_ARG(aType <= static_cast<uint32_t>(RelationType::LAST));
  1.1943 +
  1.1944 +  if (IsDefunct())
  1.1945 +    return NS_ERROR_FAILURE;
  1.1946 +
  1.1947 +  Relation rel = RelationByType(static_cast<RelationType>(aType));
  1.1948 +  NS_ADDREF(*aRelation = new nsAccessibleRelation(aType, &rel));
  1.1949 +  return *aRelation ? NS_OK : NS_ERROR_FAILURE;
  1.1950 +}
  1.1951 +
  1.1952 +Relation
  1.1953 +Accessible::RelationByType(RelationType aType)
  1.1954 +{
  1.1955 +  if (!HasOwnContent())
  1.1956 +    return Relation();
  1.1957 +
  1.1958 +  // Relationships are defined on the same content node that the role would be
  1.1959 +  // defined on.
  1.1960 +  switch (aType) {
  1.1961 +    case RelationType::LABELLED_BY: {
  1.1962 +      Relation rel(new IDRefsIterator(mDoc, mContent,
  1.1963 +                                      nsGkAtoms::aria_labelledby));
  1.1964 +      if (mContent->IsHTML()) {
  1.1965 +        rel.AppendIter(new HTMLLabelIterator(Document(), this));
  1.1966 +      } else if (mContent->IsXUL()) {
  1.1967 +        rel.AppendIter(new XULLabelIterator(Document(), mContent));
  1.1968 +      }
  1.1969 +
  1.1970 +      return rel;
  1.1971 +    }
  1.1972 +
  1.1973 +    case RelationType::LABEL_FOR: {
  1.1974 +      Relation rel(new RelatedAccIterator(Document(), mContent,
  1.1975 +                                          nsGkAtoms::aria_labelledby));
  1.1976 +      if (mContent->Tag() == nsGkAtoms::label && mContent->IsXUL())
  1.1977 +        rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::control));
  1.1978 +
  1.1979 +      return rel;
  1.1980 +    }
  1.1981 +
  1.1982 +    case RelationType::DESCRIBED_BY: {
  1.1983 +      Relation rel(new IDRefsIterator(mDoc, mContent,
  1.1984 +                                      nsGkAtoms::aria_describedby));
  1.1985 +      if (mContent->IsXUL())
  1.1986 +        rel.AppendIter(new XULDescriptionIterator(Document(), mContent));
  1.1987 +
  1.1988 +      return rel;
  1.1989 +    }
  1.1990 +
  1.1991 +    case RelationType::DESCRIPTION_FOR: {
  1.1992 +      Relation rel(new RelatedAccIterator(Document(), mContent,
  1.1993 +                                          nsGkAtoms::aria_describedby));
  1.1994 +
  1.1995 +      // This affectively adds an optional control attribute to xul:description,
  1.1996 +      // which only affects accessibility, by allowing the description to be
  1.1997 +      // tied to a control.
  1.1998 +      if (mContent->Tag() == nsGkAtoms::description &&
  1.1999 +          mContent->IsXUL())
  1.2000 +        rel.AppendIter(new IDRefsIterator(mDoc, mContent,
  1.2001 +                                          nsGkAtoms::control));
  1.2002 +
  1.2003 +      return rel;
  1.2004 +    }
  1.2005 +
  1.2006 +    case RelationType::NODE_CHILD_OF: {
  1.2007 +      Relation rel(new RelatedAccIterator(Document(), mContent,
  1.2008 +                                          nsGkAtoms::aria_owns));
  1.2009 +
  1.2010 +      // This is an ARIA tree or treegrid that doesn't use owns, so we need to
  1.2011 +      // get the parent the hard way.
  1.2012 +      if (mRoleMapEntry && (mRoleMapEntry->role == roles::OUTLINEITEM ||
  1.2013 +                            mRoleMapEntry->role == roles::LISTITEM ||
  1.2014 +                            mRoleMapEntry->role == roles::ROW)) {
  1.2015 +        rel.AppendTarget(GetGroupInfo()->ConceptualParent());
  1.2016 +      }
  1.2017 +
  1.2018 +      // If accessible is in its own Window, or is the root of a document,
  1.2019 +      // then we should provide NODE_CHILD_OF relation so that MSAA clients
  1.2020 +      // can easily get to true parent instead of getting to oleacc's
  1.2021 +      // ROLE_WINDOW accessible which will prevent us from going up further
  1.2022 +      // (because it is system generated and has no idea about the hierarchy
  1.2023 +      // above it).
  1.2024 +      nsIFrame *frame = GetFrame();
  1.2025 +      if (frame) {
  1.2026 +        nsView *view = frame->GetViewExternal();
  1.2027 +        if (view) {
  1.2028 +          nsIScrollableFrame *scrollFrame = do_QueryFrame(frame);
  1.2029 +          if (scrollFrame || view->GetWidget() || !frame->GetParent())
  1.2030 +            rel.AppendTarget(Parent());
  1.2031 +        }
  1.2032 +      }
  1.2033 +
  1.2034 +      return rel;
  1.2035 +    }
  1.2036 +
  1.2037 +    case RelationType::NODE_PARENT_OF: {
  1.2038 +      Relation rel(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_owns));
  1.2039 +
  1.2040 +      // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
  1.2041 +      // also can be organized by groups.
  1.2042 +      if (mRoleMapEntry &&
  1.2043 +          (mRoleMapEntry->role == roles::OUTLINEITEM ||
  1.2044 +           mRoleMapEntry->role == roles::LISTITEM ||
  1.2045 +           mRoleMapEntry->role == roles::ROW ||
  1.2046 +           mRoleMapEntry->role == roles::OUTLINE ||
  1.2047 +           mRoleMapEntry->role == roles::LIST ||
  1.2048 +           mRoleMapEntry->role == roles::TREE_TABLE)) {
  1.2049 +        rel.AppendIter(new ItemIterator(this));
  1.2050 +      }
  1.2051 +
  1.2052 +      return rel;
  1.2053 +    }
  1.2054 +
  1.2055 +    case RelationType::CONTROLLED_BY:
  1.2056 +      return Relation(new RelatedAccIterator(Document(), mContent,
  1.2057 +                                             nsGkAtoms::aria_controls));
  1.2058 +
  1.2059 +    case RelationType::CONTROLLER_FOR: {
  1.2060 +      Relation rel(new IDRefsIterator(mDoc, mContent,
  1.2061 +                                      nsGkAtoms::aria_controls));
  1.2062 +      rel.AppendIter(new HTMLOutputIterator(Document(), mContent));
  1.2063 +      return rel;
  1.2064 +    }
  1.2065 +
  1.2066 +    case RelationType::FLOWS_TO:
  1.2067 +      return Relation(new IDRefsIterator(mDoc, mContent,
  1.2068 +                                         nsGkAtoms::aria_flowto));
  1.2069 +
  1.2070 +    case RelationType::FLOWS_FROM:
  1.2071 +      return Relation(new RelatedAccIterator(Document(), mContent,
  1.2072 +                                             nsGkAtoms::aria_flowto));
  1.2073 +
  1.2074 +    case RelationType::MEMBER_OF:
  1.2075 +          return Relation(mDoc, GetAtomicRegion());
  1.2076 +
  1.2077 +    case RelationType::SUBWINDOW_OF:
  1.2078 +    case RelationType::EMBEDS:
  1.2079 +    case RelationType::EMBEDDED_BY:
  1.2080 +    case RelationType::POPUP_FOR:
  1.2081 +    case RelationType::PARENT_WINDOW_OF:
  1.2082 +      return Relation();
  1.2083 +
  1.2084 +    case RelationType::DEFAULT_BUTTON: {
  1.2085 +      if (mContent->IsHTML()) {
  1.2086 +        // HTML form controls implements nsIFormControl interface.
  1.2087 +        nsCOMPtr<nsIFormControl> control(do_QueryInterface(mContent));
  1.2088 +        if (control) {
  1.2089 +          nsCOMPtr<nsIForm> form(do_QueryInterface(control->GetFormElement()));
  1.2090 +          if (form) {
  1.2091 +            nsCOMPtr<nsIContent> formContent =
  1.2092 +              do_QueryInterface(form->GetDefaultSubmitElement());
  1.2093 +            return Relation(mDoc, formContent);
  1.2094 +          }
  1.2095 +        }
  1.2096 +      } else {
  1.2097 +        // In XUL, use first <button default="true" .../> in the document
  1.2098 +        nsCOMPtr<nsIDOMXULDocument> xulDoc =
  1.2099 +          do_QueryInterface(mContent->OwnerDoc());
  1.2100 +        nsCOMPtr<nsIDOMXULButtonElement> buttonEl;
  1.2101 +        if (xulDoc) {
  1.2102 +          nsCOMPtr<nsIDOMNodeList> possibleDefaultButtons;
  1.2103 +          xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
  1.2104 +                                         NS_LITERAL_STRING("true"),
  1.2105 +                                         getter_AddRefs(possibleDefaultButtons));
  1.2106 +          if (possibleDefaultButtons) {
  1.2107 +            uint32_t length;
  1.2108 +            possibleDefaultButtons->GetLength(&length);
  1.2109 +            nsCOMPtr<nsIDOMNode> possibleButton;
  1.2110 +            // Check for button in list of default="true" elements
  1.2111 +            for (uint32_t count = 0; count < length && !buttonEl; count ++) {
  1.2112 +              possibleDefaultButtons->Item(count, getter_AddRefs(possibleButton));
  1.2113 +              buttonEl = do_QueryInterface(possibleButton);
  1.2114 +            }
  1.2115 +          }
  1.2116 +          if (!buttonEl) { // Check for anonymous accept button in <dialog>
  1.2117 +            dom::Element* rootElm = mContent->OwnerDoc()->GetRootElement();
  1.2118 +            if (rootElm) {
  1.2119 +              nsIContent* possibleButtonEl = rootElm->OwnerDoc()->
  1.2120 +                GetAnonymousElementByAttribute(rootElm, nsGkAtoms::_default,
  1.2121 +                                               NS_LITERAL_STRING("true"));
  1.2122 +              buttonEl = do_QueryInterface(possibleButtonEl);
  1.2123 +            }
  1.2124 +          }
  1.2125 +          nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
  1.2126 +          return Relation(mDoc, relatedContent);
  1.2127 +        }
  1.2128 +      }
  1.2129 +      return Relation();
  1.2130 +    }
  1.2131 +
  1.2132 +    case RelationType::CONTAINING_DOCUMENT:
  1.2133 +      return Relation(mDoc);
  1.2134 +
  1.2135 +    case RelationType::CONTAINING_TAB_PANE: {
  1.2136 +      nsCOMPtr<nsIDocShell> docShell =
  1.2137 +        nsCoreUtils::GetDocShellFor(GetNode());
  1.2138 +      if (docShell) {
  1.2139 +        // Walk up the parent chain without crossing the boundary at which item
  1.2140 +        // types change, preventing us from walking up out of tab content.
  1.2141 +        nsCOMPtr<nsIDocShellTreeItem> root;
  1.2142 +        docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
  1.2143 +        if (root) {
  1.2144 +          // If the item type is typeContent, we assume we are in browser tab
  1.2145 +          // content. Note, this includes content such as about:addons,
  1.2146 +          // for consistency.
  1.2147 +          if (root->ItemType() == nsIDocShellTreeItem::typeContent) {
  1.2148 +            return Relation(nsAccUtils::GetDocAccessibleFor(root));
  1.2149 +          }
  1.2150 +        }
  1.2151 +      }
  1.2152 +      return  Relation();
  1.2153 +    }
  1.2154 +
  1.2155 +    case RelationType::CONTAINING_APPLICATION:
  1.2156 +      return Relation(ApplicationAcc());
  1.2157 +
  1.2158 +    default:
  1.2159 +      return Relation();
  1.2160 +  }
  1.2161 +}
  1.2162 +
  1.2163 +NS_IMETHODIMP
  1.2164 +Accessible::GetRelations(nsIArray **aRelations)
  1.2165 +{
  1.2166 +  NS_ENSURE_ARG_POINTER(aRelations);
  1.2167 +  *aRelations = nullptr;
  1.2168 +
  1.2169 +  if (IsDefunct())
  1.2170 +    return NS_ERROR_FAILURE;
  1.2171 +
  1.2172 +  nsCOMPtr<nsIMutableArray> relations = do_CreateInstance(NS_ARRAY_CONTRACTID);
  1.2173 +  NS_ENSURE_TRUE(relations, NS_ERROR_OUT_OF_MEMORY);
  1.2174 +
  1.2175 +  static const uint32_t relationTypes[] = {
  1.2176 +    nsIAccessibleRelation::RELATION_LABELLED_BY,
  1.2177 +    nsIAccessibleRelation::RELATION_LABEL_FOR,
  1.2178 +    nsIAccessibleRelation::RELATION_DESCRIBED_BY,
  1.2179 +    nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
  1.2180 +    nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
  1.2181 +    nsIAccessibleRelation::RELATION_NODE_PARENT_OF,
  1.2182 +    nsIAccessibleRelation::RELATION_CONTROLLED_BY,
  1.2183 +    nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
  1.2184 +    nsIAccessibleRelation::RELATION_FLOWS_TO,
  1.2185 +    nsIAccessibleRelation::RELATION_FLOWS_FROM,
  1.2186 +    nsIAccessibleRelation::RELATION_MEMBER_OF,
  1.2187 +    nsIAccessibleRelation::RELATION_SUBWINDOW_OF,
  1.2188 +    nsIAccessibleRelation::RELATION_EMBEDS,
  1.2189 +    nsIAccessibleRelation::RELATION_EMBEDDED_BY,
  1.2190 +    nsIAccessibleRelation::RELATION_POPUP_FOR,
  1.2191 +    nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF,
  1.2192 +    nsIAccessibleRelation::RELATION_DEFAULT_BUTTON,
  1.2193 +    nsIAccessibleRelation::RELATION_CONTAINING_DOCUMENT,
  1.2194 +    nsIAccessibleRelation::RELATION_CONTAINING_TAB_PANE,
  1.2195 +    nsIAccessibleRelation::RELATION_CONTAINING_APPLICATION
  1.2196 +  };
  1.2197 +
  1.2198 +  for (uint32_t idx = 0; idx < ArrayLength(relationTypes); idx++) {
  1.2199 +    nsCOMPtr<nsIAccessibleRelation> relation;
  1.2200 +    nsresult rv = GetRelationByType(relationTypes[idx], getter_AddRefs(relation));
  1.2201 +
  1.2202 +    if (NS_SUCCEEDED(rv) && relation) {
  1.2203 +      uint32_t targets = 0;
  1.2204 +      relation->GetTargetsCount(&targets);
  1.2205 +      if (targets)
  1.2206 +        relations->AppendElement(relation, false);
  1.2207 +    }
  1.2208 +  }
  1.2209 +
  1.2210 +  NS_ADDREF(*aRelations = relations);
  1.2211 +  return NS_OK;
  1.2212 +}
  1.2213 +
  1.2214 +/* void extendSelection (); */
  1.2215 +NS_IMETHODIMP Accessible::ExtendSelection()
  1.2216 +{
  1.2217 +  // XXX Should be implemented, but not high priority
  1.2218 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.2219 +}
  1.2220 +
  1.2221 +/* [noscript] void getNativeInterface(out voidPtr aOutAccessible); */
  1.2222 +NS_IMETHODIMP Accessible::GetNativeInterface(void **aOutAccessible)
  1.2223 +{
  1.2224 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.2225 +}
  1.2226 +
  1.2227 +void
  1.2228 +Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
  1.2229 +{
  1.2230 +  class Runnable MOZ_FINAL : public nsRunnable
  1.2231 +  {
  1.2232 +  public:
  1.2233 +    Runnable(Accessible* aAcc, nsIContent* aContent, uint32_t aIdx) :
  1.2234 +      mAcc(aAcc), mContent(aContent), mIdx(aIdx) { }
  1.2235 +
  1.2236 +    NS_IMETHOD Run()
  1.2237 +    {
  1.2238 +      if (mAcc)
  1.2239 +        mAcc->DispatchClickEvent(mContent, mIdx);
  1.2240 +
  1.2241 +      return NS_OK;
  1.2242 +    }
  1.2243 +
  1.2244 +    void Revoke()
  1.2245 +    {
  1.2246 +      mAcc = nullptr;
  1.2247 +      mContent = nullptr;
  1.2248 +    }
  1.2249 +
  1.2250 +  private:
  1.2251 +    nsRefPtr<Accessible> mAcc;
  1.2252 +    nsCOMPtr<nsIContent> mContent;
  1.2253 +    uint32_t mIdx;
  1.2254 +  };
  1.2255 +
  1.2256 +  nsIContent* content = aContent ? aContent : mContent.get();
  1.2257 +  nsCOMPtr<nsIRunnable> runnable = new Runnable(this, content, aActionIndex);
  1.2258 +  NS_DispatchToMainThread(runnable);
  1.2259 +}
  1.2260 +
  1.2261 +void
  1.2262 +Accessible::DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex)
  1.2263 +{
  1.2264 +  if (IsDefunct())
  1.2265 +    return;
  1.2266 +
  1.2267 +  nsCOMPtr<nsIPresShell> presShell = mDoc->PresShell();
  1.2268 +
  1.2269 +  // Scroll into view.
  1.2270 +  presShell->ScrollContentIntoView(aContent,
  1.2271 +                                   nsIPresShell::ScrollAxis(),
  1.2272 +                                   nsIPresShell::ScrollAxis(),
  1.2273 +                                   nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
  1.2274 +
  1.2275 +  nsWeakFrame frame = aContent->GetPrimaryFrame();
  1.2276 +  if (!frame)
  1.2277 +    return;
  1.2278 +
  1.2279 +  // Compute x and y coordinates.
  1.2280 +  nsPoint point;
  1.2281 +  nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
  1.2282 +  if (!widget)
  1.2283 +    return;
  1.2284 +
  1.2285 +  nsSize size = frame->GetSize();
  1.2286 +
  1.2287 +  nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
  1.2288 +  int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
  1.2289 +  int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
  1.2290 +
  1.2291 +  // Simulate a touch interaction by dispatching touch events with mouse events.
  1.2292 +  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_START, x, y, aContent, frame, presShell, widget);
  1.2293 +  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, x, y, aContent, frame, presShell, widget);
  1.2294 +  nsCoreUtils::DispatchTouchEvent(NS_TOUCH_END, x, y, aContent, frame, presShell, widget);
  1.2295 +  nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, x, y, aContent, frame, presShell, widget);
  1.2296 +}
  1.2297 +
  1.2298 +NS_IMETHODIMP
  1.2299 +Accessible::ScrollTo(uint32_t aHow)
  1.2300 +{
  1.2301 +  if (IsDefunct())
  1.2302 +    return NS_ERROR_FAILURE;
  1.2303 +
  1.2304 +  nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
  1.2305 +  return NS_OK;
  1.2306 +}
  1.2307 +
  1.2308 +NS_IMETHODIMP
  1.2309 +Accessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY)
  1.2310 +{
  1.2311 +  nsIFrame *frame = GetFrame();
  1.2312 +  if (!frame)
  1.2313 +    return NS_ERROR_FAILURE;
  1.2314 +
  1.2315 +  nsIntPoint coords = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType,
  1.2316 +                                                        this);
  1.2317 +
  1.2318 +  nsIFrame *parentFrame = frame;
  1.2319 +  while ((parentFrame = parentFrame->GetParent()))
  1.2320 +    nsCoreUtils::ScrollFrameToPoint(parentFrame, frame, coords);
  1.2321 +
  1.2322 +  return NS_OK;
  1.2323 +}
  1.2324 +
  1.2325 +// nsIAccessibleHyperLink
  1.2326 +// Because of new-atk design, any embedded object in text can implement
  1.2327 +// nsIAccessibleHyperLink, which helps determine where it is located
  1.2328 +// within containing text
  1.2329 +
  1.2330 +// readonly attribute long nsIAccessibleHyperLink::anchorCount
  1.2331 +NS_IMETHODIMP
  1.2332 +Accessible::GetAnchorCount(int32_t *aAnchorCount)
  1.2333 +{
  1.2334 +  NS_ENSURE_ARG_POINTER(aAnchorCount);
  1.2335 +  *aAnchorCount = 0;
  1.2336 +
  1.2337 +  if (IsDefunct())
  1.2338 +    return NS_ERROR_FAILURE;
  1.2339 +
  1.2340 +  *aAnchorCount = AnchorCount();
  1.2341 +  return NS_OK;
  1.2342 +}
  1.2343 +
  1.2344 +// readonly attribute long nsIAccessibleHyperLink::startIndex
  1.2345 +NS_IMETHODIMP
  1.2346 +Accessible::GetStartIndex(int32_t *aStartIndex)
  1.2347 +{
  1.2348 +  NS_ENSURE_ARG_POINTER(aStartIndex);
  1.2349 +  *aStartIndex = 0;
  1.2350 +
  1.2351 +  if (IsDefunct())
  1.2352 +    return NS_ERROR_FAILURE;
  1.2353 +
  1.2354 +  *aStartIndex = StartOffset();
  1.2355 +  return NS_OK;
  1.2356 +}
  1.2357 +
  1.2358 +// readonly attribute long nsIAccessibleHyperLink::endIndex
  1.2359 +NS_IMETHODIMP
  1.2360 +Accessible::GetEndIndex(int32_t *aEndIndex)
  1.2361 +{
  1.2362 +  NS_ENSURE_ARG_POINTER(aEndIndex);
  1.2363 +  *aEndIndex = 0;
  1.2364 +
  1.2365 +  if (IsDefunct())
  1.2366 +    return NS_ERROR_FAILURE;
  1.2367 +
  1.2368 +  *aEndIndex = EndOffset();
  1.2369 +  return NS_OK;
  1.2370 +}
  1.2371 +
  1.2372 +NS_IMETHODIMP
  1.2373 +Accessible::GetURI(int32_t aIndex, nsIURI **aURI)
  1.2374 +{
  1.2375 +  NS_ENSURE_ARG_POINTER(aURI);
  1.2376 +
  1.2377 +  if (IsDefunct())
  1.2378 +    return NS_ERROR_FAILURE;
  1.2379 +
  1.2380 +  if (aIndex < 0 || aIndex >= static_cast<int32_t>(AnchorCount()))
  1.2381 +    return NS_ERROR_INVALID_ARG;
  1.2382 +
  1.2383 +  nsRefPtr<nsIURI>(AnchorURIAt(aIndex)).forget(aURI);
  1.2384 +  return NS_OK;
  1.2385 +}
  1.2386 +
  1.2387 +
  1.2388 +NS_IMETHODIMP
  1.2389 +Accessible::GetAnchor(int32_t aIndex, nsIAccessible** aAccessible)
  1.2390 +{
  1.2391 +  NS_ENSURE_ARG_POINTER(aAccessible);
  1.2392 +  *aAccessible = nullptr;
  1.2393 +
  1.2394 +  if (IsDefunct())
  1.2395 +    return NS_ERROR_FAILURE;
  1.2396 +
  1.2397 +  if (aIndex < 0 || aIndex >= static_cast<int32_t>(AnchorCount()))
  1.2398 +    return NS_ERROR_INVALID_ARG;
  1.2399 +
  1.2400 +  NS_IF_ADDREF(*aAccessible = AnchorAt(aIndex));
  1.2401 +  return NS_OK;
  1.2402 +}
  1.2403 +
  1.2404 +// readonly attribute boolean nsIAccessibleHyperLink::valid
  1.2405 +NS_IMETHODIMP
  1.2406 +Accessible::GetValid(bool *aValid)
  1.2407 +{
  1.2408 +  NS_ENSURE_ARG_POINTER(aValid);
  1.2409 +  *aValid = false;
  1.2410 +
  1.2411 +  if (IsDefunct())
  1.2412 +    return NS_ERROR_FAILURE;
  1.2413 +
  1.2414 +  *aValid = IsLinkValid();
  1.2415 +  return NS_OK;
  1.2416 +}
  1.2417 +
  1.2418 +void
  1.2419 +Accessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
  1.2420 +                         uint32_t aLength)
  1.2421 +{
  1.2422 +  // Return text representation of non-text accessible within hypertext
  1.2423 +  // accessible. Text accessible overrides this method to return enclosed text.
  1.2424 +  if (aStartOffset != 0 || aLength == 0)
  1.2425 +    return;
  1.2426 +
  1.2427 +  nsIFrame *frame = GetFrame();
  1.2428 +  if (!frame)
  1.2429 +    return;
  1.2430 +
  1.2431 +  NS_ASSERTION(mParent,
  1.2432 +               "Called on accessible unbound from tree. Result can be wrong.");
  1.2433 +
  1.2434 +  if (frame->GetType() == nsGkAtoms::brFrame) {
  1.2435 +    aText += kForcedNewLineChar;
  1.2436 +  } else if (mParent && nsAccUtils::MustPrune(mParent)) {
  1.2437 +    // Expose the embedded object accessible as imaginary embedded object
  1.2438 +    // character if its parent hypertext accessible doesn't expose children to
  1.2439 +    // AT.
  1.2440 +    aText += kImaginaryEmbeddedObjectChar;
  1.2441 +  } else {
  1.2442 +    aText += kEmbeddedObjectChar;
  1.2443 +  }
  1.2444 +}
  1.2445 +
  1.2446 +void
  1.2447 +Accessible::Shutdown()
  1.2448 +{
  1.2449 +  // Mark the accessible as defunct, invalidate the child count and pointers to 
  1.2450 +  // other accessibles, also make sure none of its children point to this parent
  1.2451 +  mStateFlags |= eIsDefunct;
  1.2452 +
  1.2453 +  InvalidateChildren();
  1.2454 +  if (mParent)
  1.2455 +    mParent->RemoveChild(this);
  1.2456 +
  1.2457 +  mContent = nullptr;
  1.2458 +  mDoc = nullptr;
  1.2459 +}
  1.2460 +
  1.2461 +// Accessible protected
  1.2462 +void
  1.2463 +Accessible::ARIAName(nsString& aName)
  1.2464 +{
  1.2465 +  // aria-labelledby now takes precedence over aria-label
  1.2466 +  nsresult rv = nsTextEquivUtils::
  1.2467 +    GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, aName);
  1.2468 +  if (NS_SUCCEEDED(rv)) {
  1.2469 +    aName.CompressWhitespace();
  1.2470 +  }
  1.2471 +
  1.2472 +  if (aName.IsEmpty() &&
  1.2473 +      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label, aName)) {
  1.2474 +    aName.CompressWhitespace();
  1.2475 +  }
  1.2476 +}
  1.2477 +
  1.2478 +// Accessible protected
  1.2479 +ENameValueFlag
  1.2480 +Accessible::NativeName(nsString& aName)
  1.2481 +{
  1.2482 +  if (mContent->IsHTML()) {
  1.2483 +    Accessible* label = nullptr;
  1.2484 +    HTMLLabelIterator iter(Document(), this);
  1.2485 +    while ((label = iter.Next())) {
  1.2486 +      nsTextEquivUtils::AppendTextEquivFromContent(this, label->GetContent(),
  1.2487 +                                                   &aName);
  1.2488 +      aName.CompressWhitespace();
  1.2489 +    }
  1.2490 +
  1.2491 +    if (!aName.IsEmpty())
  1.2492 +      return eNameOK;
  1.2493 +
  1.2494 +    nsTextEquivUtils::GetNameFromSubtree(this, aName);
  1.2495 +    return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
  1.2496 +  }
  1.2497 +
  1.2498 +  if (mContent->IsXUL()) {
  1.2499 +    XULElmName(mDoc, mContent, aName);
  1.2500 +    if (!aName.IsEmpty())
  1.2501 +      return eNameOK;
  1.2502 +
  1.2503 +    nsTextEquivUtils::GetNameFromSubtree(this, aName);
  1.2504 +    return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
  1.2505 +  }
  1.2506 +
  1.2507 +  if (mContent->IsSVG()) {
  1.2508 +    // If user agents need to choose among multiple ‘desc’ or ‘title’ elements
  1.2509 +    // for processing, the user agent shall choose the first one.
  1.2510 +    for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
  1.2511 +         childElm = childElm->GetNextSibling()) {
  1.2512 +      if (childElm->IsSVG(nsGkAtoms::title)) {
  1.2513 +        nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
  1.2514 +        return eNameOK;
  1.2515 +      }
  1.2516 +    }
  1.2517 +  }
  1.2518 +
  1.2519 +  return eNameOK;
  1.2520 +}
  1.2521 +
  1.2522 +// Accessible protected
  1.2523 +void
  1.2524 +Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
  1.2525 +{
  1.2526 +  NS_PRECONDITION(aParent, "This method isn't used to set null parent!");
  1.2527 +
  1.2528 +  if (mParent) {
  1.2529 +    if (mParent != aParent) {
  1.2530 +      NS_ERROR("Adopting child!");
  1.2531 +      mParent->RemoveChild(this);
  1.2532 +      mParent->InvalidateChildrenGroupInfo();
  1.2533 +    } else {
  1.2534 +      NS_ERROR("Binding to the same parent!");
  1.2535 +      return;
  1.2536 +    }
  1.2537 +  }
  1.2538 +
  1.2539 +  mParent = aParent;
  1.2540 +  mIndexInParent = aIndexInParent;
  1.2541 +
  1.2542 +  mParent->InvalidateChildrenGroupInfo();
  1.2543 +
  1.2544 +  // Note: this is currently only used for richlistitems and their children.
  1.2545 +  if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
  1.2546 +    mContextFlags |= eHasNameDependentParent;
  1.2547 +  else
  1.2548 +    mContextFlags &= ~eHasNameDependentParent;
  1.2549 +}
  1.2550 +
  1.2551 +// Accessible protected
  1.2552 +void
  1.2553 +Accessible::UnbindFromParent()
  1.2554 +{
  1.2555 +  mParent->InvalidateChildrenGroupInfo();
  1.2556 +  mParent = nullptr;
  1.2557 +  mIndexInParent = -1;
  1.2558 +  mIndexOfEmbeddedChild = -1;
  1.2559 +  mGroupInfo = nullptr;
  1.2560 +  mContextFlags &= ~eHasNameDependentParent;
  1.2561 +}
  1.2562 +
  1.2563 +////////////////////////////////////////////////////////////////////////////////
  1.2564 +// Accessible public methods
  1.2565 +
  1.2566 +RootAccessible*
  1.2567 +Accessible::RootAccessible() const
  1.2568 +{
  1.2569 +  nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(GetNode());
  1.2570 +  NS_ASSERTION(docShell, "No docshell for mContent");
  1.2571 +  if (!docShell) {
  1.2572 +    return nullptr;
  1.2573 +  }
  1.2574 +
  1.2575 +  nsCOMPtr<nsIDocShellTreeItem> root;
  1.2576 +  docShell->GetRootTreeItem(getter_AddRefs(root));
  1.2577 +  NS_ASSERTION(root, "No root content tree item");
  1.2578 +  if (!root) {
  1.2579 +    return nullptr;
  1.2580 +  }
  1.2581 +
  1.2582 +  DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
  1.2583 +  return docAcc ? docAcc->AsRoot() : nullptr;
  1.2584 +}
  1.2585 +
  1.2586 +nsIFrame*
  1.2587 +Accessible::GetFrame() const
  1.2588 +{
  1.2589 +  return mContent ? mContent->GetPrimaryFrame() : nullptr;
  1.2590 +}
  1.2591 +
  1.2592 +nsINode*
  1.2593 +Accessible::GetNode() const
  1.2594 +{
  1.2595 +  return mContent;
  1.2596 +}
  1.2597 +
  1.2598 +void
  1.2599 +Accessible::Language(nsAString& aLanguage)
  1.2600 +{
  1.2601 +  aLanguage.Truncate();
  1.2602 +
  1.2603 +  if (!mDoc)
  1.2604 +    return;
  1.2605 +
  1.2606 +  nsCoreUtils::GetLanguageFor(mContent, nullptr, aLanguage);
  1.2607 +  if (aLanguage.IsEmpty()) { // Nothing found, so use document's language
  1.2608 +    mDoc->DocumentNode()->GetHeaderData(nsGkAtoms::headerContentLanguage,
  1.2609 +                                        aLanguage);
  1.2610 +  }
  1.2611 +}
  1.2612 +
  1.2613 +void
  1.2614 +Accessible::InvalidateChildren()
  1.2615 +{
  1.2616 +  int32_t childCount = mChildren.Length();
  1.2617 +  for (int32_t childIdx = 0; childIdx < childCount; childIdx++) {
  1.2618 +    Accessible* child = mChildren.ElementAt(childIdx);
  1.2619 +    child->UnbindFromParent();
  1.2620 +  }
  1.2621 +
  1.2622 +  mEmbeddedObjCollector = nullptr;
  1.2623 +  mChildren.Clear();
  1.2624 +  SetChildrenFlag(eChildrenUninitialized);
  1.2625 +}
  1.2626 +
  1.2627 +bool
  1.2628 +Accessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
  1.2629 +{
  1.2630 +  if (!aChild)
  1.2631 +    return false;
  1.2632 +
  1.2633 +  if (aIndex == mChildren.Length()) {
  1.2634 +    if (!mChildren.AppendElement(aChild))
  1.2635 +      return false;
  1.2636 +
  1.2637 +  } else {
  1.2638 +    if (!mChildren.InsertElementAt(aIndex, aChild))
  1.2639 +      return false;
  1.2640 +
  1.2641 +    for (uint32_t idx = aIndex + 1; idx < mChildren.Length(); idx++) {
  1.2642 +      NS_ASSERTION(static_cast<uint32_t>(mChildren[idx]->mIndexInParent) == idx - 1,
  1.2643 +                   "Accessible child index doesn't match");
  1.2644 +      mChildren[idx]->mIndexInParent = idx;
  1.2645 +    }
  1.2646 +
  1.2647 +    mEmbeddedObjCollector = nullptr;
  1.2648 +  }
  1.2649 +
  1.2650 +  if (!nsAccUtils::IsEmbeddedObject(aChild))
  1.2651 +    SetChildrenFlag(eMixedChildren);
  1.2652 +
  1.2653 +  aChild->BindToParent(this, aIndex);
  1.2654 +  return true;
  1.2655 +}
  1.2656 +
  1.2657 +bool
  1.2658 +Accessible::RemoveChild(Accessible* aChild)
  1.2659 +{
  1.2660 +  if (!aChild)
  1.2661 +    return false;
  1.2662 +
  1.2663 +  if (aChild->mParent != this || aChild->mIndexInParent == -1)
  1.2664 +    return false;
  1.2665 +
  1.2666 +  uint32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
  1.2667 +  if (index >= mChildren.Length() || mChildren[index] != aChild) {
  1.2668 +    NS_ERROR("Child is bound to parent but parent hasn't this child at its index!");
  1.2669 +    aChild->UnbindFromParent();
  1.2670 +    return false;
  1.2671 +  }
  1.2672 +
  1.2673 +  for (uint32_t idx = index + 1; idx < mChildren.Length(); idx++) {
  1.2674 +    NS_ASSERTION(static_cast<uint32_t>(mChildren[idx]->mIndexInParent) == idx,
  1.2675 +                 "Accessible child index doesn't match");
  1.2676 +    mChildren[idx]->mIndexInParent = idx - 1;
  1.2677 +  }
  1.2678 +
  1.2679 +  aChild->UnbindFromParent();
  1.2680 +  mChildren.RemoveElementAt(index);
  1.2681 +  mEmbeddedObjCollector = nullptr;
  1.2682 +
  1.2683 +  return true;
  1.2684 +}
  1.2685 +
  1.2686 +Accessible*
  1.2687 +Accessible::GetChildAt(uint32_t aIndex) const
  1.2688 +{
  1.2689 +  Accessible* child = mChildren.SafeElementAt(aIndex, nullptr);
  1.2690 +  if (!child)
  1.2691 +    return nullptr;
  1.2692 +
  1.2693 +#ifdef DEBUG
  1.2694 +  Accessible* realParent = child->mParent;
  1.2695 +  NS_ASSERTION(!realParent || realParent == this,
  1.2696 +               "Two accessibles have the same first child accessible!");
  1.2697 +#endif
  1.2698 +
  1.2699 +  return child;
  1.2700 +}
  1.2701 +
  1.2702 +uint32_t
  1.2703 +Accessible::ChildCount() const
  1.2704 +{
  1.2705 +  return mChildren.Length();
  1.2706 +}
  1.2707 +
  1.2708 +int32_t
  1.2709 +Accessible::IndexInParent() const
  1.2710 +{
  1.2711 +  return mIndexInParent;
  1.2712 +}
  1.2713 +
  1.2714 +uint32_t
  1.2715 +Accessible::EmbeddedChildCount()
  1.2716 +{
  1.2717 +  if (IsChildrenFlag(eMixedChildren)) {
  1.2718 +    if (!mEmbeddedObjCollector)
  1.2719 +      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
  1.2720 +    return mEmbeddedObjCollector->Count();
  1.2721 +  }
  1.2722 +
  1.2723 +  return ChildCount();
  1.2724 +}
  1.2725 +
  1.2726 +Accessible*
  1.2727 +Accessible::GetEmbeddedChildAt(uint32_t aIndex)
  1.2728 +{
  1.2729 +  if (IsChildrenFlag(eMixedChildren)) {
  1.2730 +    if (!mEmbeddedObjCollector)
  1.2731 +      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
  1.2732 +    return mEmbeddedObjCollector ?
  1.2733 +      mEmbeddedObjCollector->GetAccessibleAt(aIndex) : nullptr;
  1.2734 +  }
  1.2735 +
  1.2736 +  return GetChildAt(aIndex);
  1.2737 +}
  1.2738 +
  1.2739 +int32_t
  1.2740 +Accessible::GetIndexOfEmbeddedChild(Accessible* aChild)
  1.2741 +{
  1.2742 +  if (IsChildrenFlag(eMixedChildren)) {
  1.2743 +    if (!mEmbeddedObjCollector)
  1.2744 +      mEmbeddedObjCollector = new EmbeddedObjCollector(this);
  1.2745 +    return mEmbeddedObjCollector ?
  1.2746 +      mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
  1.2747 +  }
  1.2748 +
  1.2749 +  return GetIndexOf(aChild);
  1.2750 +}
  1.2751 +
  1.2752 +////////////////////////////////////////////////////////////////////////////////
  1.2753 +// HyperLinkAccessible methods
  1.2754 +
  1.2755 +bool
  1.2756 +Accessible::IsLink()
  1.2757 +{
  1.2758 +  // Every embedded accessible within hypertext accessible implements
  1.2759 +  // hyperlink interface.
  1.2760 +  return mParent && mParent->IsHyperText() && nsAccUtils::IsEmbeddedObject(this);
  1.2761 +}
  1.2762 +
  1.2763 +uint32_t
  1.2764 +Accessible::StartOffset()
  1.2765 +{
  1.2766 +  NS_PRECONDITION(IsLink(), "StartOffset is called not on hyper link!");
  1.2767 +
  1.2768 +  HyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nullptr;
  1.2769 +  return hyperText ? hyperText->GetChildOffset(this) : 0;
  1.2770 +}
  1.2771 +
  1.2772 +uint32_t
  1.2773 +Accessible::EndOffset()
  1.2774 +{
  1.2775 +  NS_PRECONDITION(IsLink(), "EndOffset is called on not hyper link!");
  1.2776 +
  1.2777 +  HyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nullptr;
  1.2778 +  return hyperText ? (hyperText->GetChildOffset(this) + 1) : 0;
  1.2779 +}
  1.2780 +
  1.2781 +uint32_t
  1.2782 +Accessible::AnchorCount()
  1.2783 +{
  1.2784 +  NS_PRECONDITION(IsLink(), "AnchorCount is called on not hyper link!");
  1.2785 +  return 1;
  1.2786 +}
  1.2787 +
  1.2788 +Accessible*
  1.2789 +Accessible::AnchorAt(uint32_t aAnchorIndex)
  1.2790 +{
  1.2791 +  NS_PRECONDITION(IsLink(), "GetAnchor is called on not hyper link!");
  1.2792 +  return aAnchorIndex == 0 ? this : nullptr;
  1.2793 +}
  1.2794 +
  1.2795 +already_AddRefed<nsIURI>
  1.2796 +Accessible::AnchorURIAt(uint32_t aAnchorIndex)
  1.2797 +{
  1.2798 +  NS_PRECONDITION(IsLink(), "AnchorURIAt is called on not hyper link!");
  1.2799 +  return nullptr;
  1.2800 +}
  1.2801 +
  1.2802 +
  1.2803 +////////////////////////////////////////////////////////////////////////////////
  1.2804 +// SelectAccessible
  1.2805 +
  1.2806 +already_AddRefed<nsIArray>
  1.2807 +Accessible::SelectedItems()
  1.2808 +{
  1.2809 +  nsCOMPtr<nsIMutableArray> selectedItems = do_CreateInstance(NS_ARRAY_CONTRACTID);
  1.2810 +  if (!selectedItems)
  1.2811 +    return nullptr;
  1.2812 +
  1.2813 +  AccIterator iter(this, filters::GetSelected);
  1.2814 +  nsIAccessible* selected = nullptr;
  1.2815 +  while ((selected = iter.Next()))
  1.2816 +    selectedItems->AppendElement(selected, false);
  1.2817 +
  1.2818 +  return selectedItems.forget();
  1.2819 +}
  1.2820 +
  1.2821 +uint32_t
  1.2822 +Accessible::SelectedItemCount()
  1.2823 +{
  1.2824 +  uint32_t count = 0;
  1.2825 +  AccIterator iter(this, filters::GetSelected);
  1.2826 +  Accessible* selected = nullptr;
  1.2827 +  while ((selected = iter.Next()))
  1.2828 +    ++count;
  1.2829 +
  1.2830 +  return count;
  1.2831 +}
  1.2832 +
  1.2833 +Accessible*
  1.2834 +Accessible::GetSelectedItem(uint32_t aIndex)
  1.2835 +{
  1.2836 +  AccIterator iter(this, filters::GetSelected);
  1.2837 +  Accessible* selected = nullptr;
  1.2838 +
  1.2839 +  uint32_t index = 0;
  1.2840 +  while ((selected = iter.Next()) && index < aIndex)
  1.2841 +    index++;
  1.2842 +
  1.2843 +  return selected;
  1.2844 +}
  1.2845 +
  1.2846 +bool
  1.2847 +Accessible::IsItemSelected(uint32_t aIndex)
  1.2848 +{
  1.2849 +  uint32_t index = 0;
  1.2850 +  AccIterator iter(this, filters::GetSelectable);
  1.2851 +  Accessible* selected = nullptr;
  1.2852 +  while ((selected = iter.Next()) && index < aIndex)
  1.2853 +    index++;
  1.2854 +
  1.2855 +  return selected &&
  1.2856 +    selected->State() & states::SELECTED;
  1.2857 +}
  1.2858 +
  1.2859 +bool
  1.2860 +Accessible::AddItemToSelection(uint32_t aIndex)
  1.2861 +{
  1.2862 +  uint32_t index = 0;
  1.2863 +  AccIterator iter(this, filters::GetSelectable);
  1.2864 +  Accessible* selected = nullptr;
  1.2865 +  while ((selected = iter.Next()) && index < aIndex)
  1.2866 +    index++;
  1.2867 +
  1.2868 +  if (selected)
  1.2869 +    selected->SetSelected(true);
  1.2870 +
  1.2871 +  return static_cast<bool>(selected);
  1.2872 +}
  1.2873 +
  1.2874 +bool
  1.2875 +Accessible::RemoveItemFromSelection(uint32_t aIndex)
  1.2876 +{
  1.2877 +  uint32_t index = 0;
  1.2878 +  AccIterator iter(this, filters::GetSelectable);
  1.2879 +  Accessible* selected = nullptr;
  1.2880 +  while ((selected = iter.Next()) && index < aIndex)
  1.2881 +    index++;
  1.2882 +
  1.2883 +  if (selected)
  1.2884 +    selected->SetSelected(false);
  1.2885 +
  1.2886 +  return static_cast<bool>(selected);
  1.2887 +}
  1.2888 +
  1.2889 +bool
  1.2890 +Accessible::SelectAll()
  1.2891 +{
  1.2892 +  bool success = false;
  1.2893 +  Accessible* selectable = nullptr;
  1.2894 +
  1.2895 +  AccIterator iter(this, filters::GetSelectable);
  1.2896 +  while((selectable = iter.Next())) {
  1.2897 +    success = true;
  1.2898 +    selectable->SetSelected(true);
  1.2899 +  }
  1.2900 +  return success;
  1.2901 +}
  1.2902 +
  1.2903 +bool
  1.2904 +Accessible::UnselectAll()
  1.2905 +{
  1.2906 +  bool success = false;
  1.2907 +  Accessible* selected = nullptr;
  1.2908 +
  1.2909 +  AccIterator iter(this, filters::GetSelected);
  1.2910 +  while ((selected = iter.Next())) {
  1.2911 +    success = true;
  1.2912 +    selected->SetSelected(false);
  1.2913 +  }
  1.2914 +  return success;
  1.2915 +}
  1.2916 +
  1.2917 +////////////////////////////////////////////////////////////////////////////////
  1.2918 +// Widgets
  1.2919 +
  1.2920 +bool
  1.2921 +Accessible::IsWidget() const
  1.2922 +{
  1.2923 +  return false;
  1.2924 +}
  1.2925 +
  1.2926 +bool
  1.2927 +Accessible::IsActiveWidget() const
  1.2928 +{
  1.2929 +  if (FocusMgr()->HasDOMFocus(mContent))
  1.2930 +    return true;
  1.2931 +
  1.2932 +  // If text entry of combobox widget has a focus then the combobox widget is
  1.2933 +  // active.
  1.2934 +  if (mRoleMapEntry && mRoleMapEntry->Is(nsGkAtoms::combobox)) {
  1.2935 +    uint32_t childCount = ChildCount();
  1.2936 +    for (uint32_t idx = 0; idx < childCount; idx++) {
  1.2937 +      Accessible* child = mChildren.ElementAt(idx);
  1.2938 +      if (child->Role() == roles::ENTRY)
  1.2939 +        return FocusMgr()->HasDOMFocus(child->GetContent());
  1.2940 +    }
  1.2941 +  }
  1.2942 +
  1.2943 +  return false;
  1.2944 +}
  1.2945 +
  1.2946 +bool
  1.2947 +Accessible::AreItemsOperable() const
  1.2948 +{
  1.2949 +  return HasOwnContent() &&
  1.2950 +    mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant);
  1.2951 +}
  1.2952 +
  1.2953 +Accessible*
  1.2954 +Accessible::CurrentItem()
  1.2955 +{
  1.2956 +  // Check for aria-activedescendant, which changes which element has focus.
  1.2957 +  // For activedescendant, the ARIA spec does not require that the user agent
  1.2958 +  // checks whether pointed node is actually a DOM descendant of the element
  1.2959 +  // with the aria-activedescendant attribute.
  1.2960 +  nsAutoString id;
  1.2961 +  if (HasOwnContent() &&
  1.2962 +      mContent->GetAttr(kNameSpaceID_None,
  1.2963 +                        nsGkAtoms::aria_activedescendant, id)) {
  1.2964 +    nsIDocument* DOMDoc = mContent->OwnerDoc();
  1.2965 +    dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
  1.2966 +    if (activeDescendantElm) {
  1.2967 +      DocAccessible* document = Document();
  1.2968 +      if (document)
  1.2969 +        return document->GetAccessible(activeDescendantElm);
  1.2970 +    }
  1.2971 +  }
  1.2972 +  return nullptr;
  1.2973 +}
  1.2974 +
  1.2975 +void
  1.2976 +Accessible::SetCurrentItem(Accessible* aItem)
  1.2977 +{
  1.2978 +  nsIAtom* id = aItem->GetContent()->GetID();
  1.2979 +  if (id) {
  1.2980 +    nsAutoString idStr;
  1.2981 +    id->ToString(idStr);
  1.2982 +    mContent->SetAttr(kNameSpaceID_None,
  1.2983 +                      nsGkAtoms::aria_activedescendant, idStr, true);
  1.2984 +  }
  1.2985 +}
  1.2986 +
  1.2987 +Accessible*
  1.2988 +Accessible::ContainerWidget() const
  1.2989 +{
  1.2990 +  if (HasARIARole() && mContent->HasID()) {
  1.2991 +    for (Accessible* parent = Parent(); parent; parent = parent->Parent()) {
  1.2992 +      nsIContent* parentContent = parent->GetContent();
  1.2993 +      if (parentContent &&
  1.2994 +        parentContent->HasAttr(kNameSpaceID_None,
  1.2995 +                               nsGkAtoms::aria_activedescendant)) {
  1.2996 +        return parent;
  1.2997 +      }
  1.2998 +
  1.2999 +      // Don't cross DOM document boundaries.
  1.3000 +      if (parent->IsDoc())
  1.3001 +        break;
  1.3002 +    }
  1.3003 +  }
  1.3004 +  return nullptr;
  1.3005 +}
  1.3006 +
  1.3007 +////////////////////////////////////////////////////////////////////////////////
  1.3008 +// Accessible protected methods
  1.3009 +
  1.3010 +void
  1.3011 +Accessible::LastRelease()
  1.3012 +{
  1.3013 +  // First cleanup if needed...
  1.3014 +  if (mDoc) {
  1.3015 +    Shutdown();
  1.3016 +    NS_ASSERTION(!mDoc,
  1.3017 +                 "A Shutdown() impl forgot to call its parent's Shutdown?");
  1.3018 +  }
  1.3019 +  // ... then die.
  1.3020 +  delete this;
  1.3021 +}
  1.3022 +
  1.3023 +void
  1.3024 +Accessible::CacheChildren()
  1.3025 +{
  1.3026 +  DocAccessible* doc = Document();
  1.3027 +  NS_ENSURE_TRUE_VOID(doc);
  1.3028 +
  1.3029 +  TreeWalker walker(this, mContent);
  1.3030 +
  1.3031 +  Accessible* child = nullptr;
  1.3032 +  while ((child = walker.NextChild()) && AppendChild(child));
  1.3033 +}
  1.3034 +
  1.3035 +void
  1.3036 +Accessible::TestChildCache(Accessible* aCachedChild) const
  1.3037 +{
  1.3038 +#ifdef DEBUG
  1.3039 +  int32_t childCount = mChildren.Length();
  1.3040 +  if (childCount == 0) {
  1.3041 +    NS_ASSERTION(IsChildrenFlag(eChildrenUninitialized),
  1.3042 +                 "No children but initialized!");
  1.3043 +    return;
  1.3044 +  }
  1.3045 +
  1.3046 +  Accessible* child = nullptr;
  1.3047 +  for (int32_t childIdx = 0; childIdx < childCount; childIdx++) {
  1.3048 +    child = mChildren[childIdx];
  1.3049 +    if (child == aCachedChild)
  1.3050 +      break;
  1.3051 +  }
  1.3052 +
  1.3053 +  NS_ASSERTION(child == aCachedChild,
  1.3054 +               "[TestChildCache] cached accessible wasn't found. Wrong accessible tree!");  
  1.3055 +#endif
  1.3056 +}
  1.3057 +
  1.3058 +// Accessible public
  1.3059 +bool
  1.3060 +Accessible::EnsureChildren()
  1.3061 +{
  1.3062 +  if (IsDefunct()) {
  1.3063 +    SetChildrenFlag(eChildrenUninitialized);
  1.3064 +    return true;
  1.3065 +  }
  1.3066 +
  1.3067 +  if (!IsChildrenFlag(eChildrenUninitialized))
  1.3068 +    return false;
  1.3069 +
  1.3070 +  // State is embedded children until text leaf accessible is appended.
  1.3071 +  SetChildrenFlag(eEmbeddedChildren); // Prevent reentry
  1.3072 +
  1.3073 +  CacheChildren();
  1.3074 +  return false;
  1.3075 +}
  1.3076 +
  1.3077 +Accessible*
  1.3078 +Accessible::GetSiblingAtOffset(int32_t aOffset, nsresult* aError) const
  1.3079 +{
  1.3080 +  if (!mParent || mIndexInParent == -1) {
  1.3081 +    if (aError)
  1.3082 +      *aError = NS_ERROR_UNEXPECTED;
  1.3083 +
  1.3084 +    return nullptr;
  1.3085 +  }
  1.3086 +
  1.3087 +  if (aError &&
  1.3088 +      mIndexInParent + aOffset >= static_cast<int32_t>(mParent->ChildCount())) {
  1.3089 +    *aError = NS_OK; // fail peacefully
  1.3090 +    return nullptr;
  1.3091 +  }
  1.3092 +
  1.3093 +  Accessible* child = mParent->GetChildAt(mIndexInParent + aOffset);
  1.3094 +  if (aError && !child)
  1.3095 +    *aError = NS_ERROR_UNEXPECTED;
  1.3096 +
  1.3097 +  return child;
  1.3098 +}
  1.3099 +
  1.3100 +double
  1.3101 +Accessible::AttrNumericValue(nsIAtom* aAttr) const
  1.3102 +{
  1.3103 +  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
  1.3104 +    return UnspecifiedNaN<double>();
  1.3105 +
  1.3106 +  nsAutoString attrValue;
  1.3107 +  if (!mContent->GetAttr(kNameSpaceID_None, aAttr, attrValue))
  1.3108 +    return UnspecifiedNaN<double>();
  1.3109 +
  1.3110 +  nsresult error = NS_OK;
  1.3111 +  double value = attrValue.ToDouble(&error);
  1.3112 +  return NS_FAILED(error) ? UnspecifiedNaN<double>() : value;
  1.3113 +}
  1.3114 +
  1.3115 +uint32_t
  1.3116 +Accessible::GetActionRule()
  1.3117 +{
  1.3118 +  if (!HasOwnContent() || (InteractiveState() & states::UNAVAILABLE))
  1.3119 +    return eNoAction;
  1.3120 +
  1.3121 +  // Return "click" action on elements that have an attached popup menu.
  1.3122 +  if (mContent->IsXUL())
  1.3123 +    if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
  1.3124 +      return eClickAction;
  1.3125 +
  1.3126 +  // Has registered 'click' event handler.
  1.3127 +  bool isOnclick = nsCoreUtils::HasClickListener(mContent);
  1.3128 +
  1.3129 +  if (isOnclick)
  1.3130 +    return eClickAction;
  1.3131 +  
  1.3132 +  // Get an action based on ARIA role.
  1.3133 +  if (mRoleMapEntry &&
  1.3134 +      mRoleMapEntry->actionRule != eNoAction)
  1.3135 +    return mRoleMapEntry->actionRule;
  1.3136 +
  1.3137 +  // Get an action based on ARIA attribute.
  1.3138 +  if (nsAccUtils::HasDefinedARIAToken(mContent,
  1.3139 +                                      nsGkAtoms::aria_expanded))
  1.3140 +    return eExpandAction;
  1.3141 +
  1.3142 +  return eNoAction;
  1.3143 +}
  1.3144 +
  1.3145 +AccGroupInfo*
  1.3146 +Accessible::GetGroupInfo()
  1.3147 +{
  1.3148 +  if (mGroupInfo){
  1.3149 +    if (HasDirtyGroupInfo()) {
  1.3150 +      mGroupInfo->Update();
  1.3151 +      SetDirtyGroupInfo(false);
  1.3152 +    }
  1.3153 +
  1.3154 +    return mGroupInfo;
  1.3155 +  }
  1.3156 +
  1.3157 +  mGroupInfo = AccGroupInfo::CreateGroupInfo(this);
  1.3158 +  return mGroupInfo;
  1.3159 +}
  1.3160 +
  1.3161 +void
  1.3162 +Accessible::InvalidateChildrenGroupInfo()
  1.3163 +{
  1.3164 +  uint32_t length = mChildren.Length();
  1.3165 +  for (uint32_t i = 0; i < length; i++) {
  1.3166 +    Accessible* child = mChildren[i];
  1.3167 +    child->SetDirtyGroupInfo(true);
  1.3168 +  }
  1.3169 +}
  1.3170 +
  1.3171 +void
  1.3172 +Accessible::GetPositionAndSizeInternal(int32_t *aPosInSet, int32_t *aSetSize)
  1.3173 +{
  1.3174 +  AccGroupInfo* groupInfo = GetGroupInfo();
  1.3175 +  if (groupInfo) {
  1.3176 +    *aPosInSet = groupInfo->PosInSet();
  1.3177 +    *aSetSize = groupInfo->SetSize();
  1.3178 +  }
  1.3179 +}
  1.3180 +
  1.3181 +int32_t
  1.3182 +Accessible::GetLevelInternal()
  1.3183 +{
  1.3184 +  int32_t level = nsAccUtils::GetDefaultLevel(this);
  1.3185 +
  1.3186 +  if (!IsBoundToParent())
  1.3187 +    return level;
  1.3188 +
  1.3189 +  roles::Role role = Role();
  1.3190 +  if (role == roles::OUTLINEITEM) {
  1.3191 +    // Always expose 'level' attribute for 'outlineitem' accessible. The number
  1.3192 +    // of nested 'grouping' accessibles containing 'outlineitem' accessible is
  1.3193 +    // its level.
  1.3194 +    level = 1;
  1.3195 +
  1.3196 +    Accessible* parent = this;
  1.3197 +    while ((parent = parent->Parent())) {
  1.3198 +      roles::Role parentRole = parent->Role();
  1.3199 +
  1.3200 +      if (parentRole == roles::OUTLINE)
  1.3201 +        break;
  1.3202 +      if (parentRole == roles::GROUPING)
  1.3203 +        ++ level;
  1.3204 +
  1.3205 +    }
  1.3206 +
  1.3207 +  } else if (role == roles::LISTITEM) {
  1.3208 +    // Expose 'level' attribute on nested lists. We support two hierarchies:
  1.3209 +    // a) list -> listitem -> list -> listitem (nested list is a last child
  1.3210 +    //   of listitem of the parent list);
  1.3211 +    // b) list -> listitem -> group -> listitem (nested listitems are contained
  1.3212 +    //   by group that is a last child of the parent listitem).
  1.3213 +
  1.3214 +    // Calculate 'level' attribute based on number of parent listitems.
  1.3215 +    level = 0;
  1.3216 +    Accessible* parent = this;
  1.3217 +    while ((parent = parent->Parent())) {
  1.3218 +      roles::Role parentRole = parent->Role();
  1.3219 +
  1.3220 +      if (parentRole == roles::LISTITEM)
  1.3221 +        ++ level;
  1.3222 +      else if (parentRole != roles::LIST && parentRole != roles::GROUPING)
  1.3223 +        break;
  1.3224 +    }
  1.3225 +
  1.3226 +    if (level == 0) {
  1.3227 +      // If this listitem is on top of nested lists then expose 'level'
  1.3228 +      // attribute.
  1.3229 +      parent = Parent();
  1.3230 +      uint32_t siblingCount = parent->ChildCount();
  1.3231 +      for (uint32_t siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
  1.3232 +        Accessible* sibling = parent->GetChildAt(siblingIdx);
  1.3233 +
  1.3234 +        Accessible* siblingChild = sibling->LastChild();
  1.3235 +        if (siblingChild) {
  1.3236 +          roles::Role lastChildRole = siblingChild->Role();
  1.3237 +          if (lastChildRole == roles::LIST || lastChildRole == roles::GROUPING)
  1.3238 +            return 1;
  1.3239 +        }
  1.3240 +      }
  1.3241 +    } else {
  1.3242 +      ++ level; // level is 1-index based
  1.3243 +    }
  1.3244 +  }
  1.3245 +
  1.3246 +  return level;
  1.3247 +}
  1.3248 +
  1.3249 +void
  1.3250 +Accessible::StaticAsserts() const
  1.3251 +{
  1.3252 +  static_assert(eLastChildrenFlag <= (1 << kChildrenFlagsBits) - 1,
  1.3253 +                "Accessible::mChildrenFlags was oversized by eLastChildrenFlag!");
  1.3254 +  static_assert(eLastStateFlag <= (1 << kStateFlagsBits) - 1,
  1.3255 +                "Accessible::mStateFlags was oversized by eLastStateFlag!");
  1.3256 +  static_assert(eLastAccType <= (1 << kTypeBits) - 1,
  1.3257 +                "Accessible::mType was oversized by eLastAccType!");
  1.3258 +  static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
  1.3259 +                "Accessible::mContextFlags was oversized by eLastContextFlag!");
  1.3260 +  static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
  1.3261 +                "Accessible::mGenericType was oversized by eLastAccGenericType!");
  1.3262 +}
  1.3263 +
  1.3264 +
  1.3265 +////////////////////////////////////////////////////////////////////////////////
  1.3266 +// KeyBinding class
  1.3267 +
  1.3268 +void
  1.3269 +KeyBinding::ToPlatformFormat(nsAString& aValue) const
  1.3270 +{
  1.3271 +  nsCOMPtr<nsIStringBundle> keyStringBundle;
  1.3272 +  nsCOMPtr<nsIStringBundleService> stringBundleService =
  1.3273 +      mozilla::services::GetStringBundleService();
  1.3274 +  if (stringBundleService)
  1.3275 +    stringBundleService->CreateBundle(
  1.3276 +      "chrome://global-platform/locale/platformKeys.properties",
  1.3277 +      getter_AddRefs(keyStringBundle));
  1.3278 +
  1.3279 +  if (!keyStringBundle)
  1.3280 +    return;
  1.3281 +
  1.3282 +  nsAutoString separator;
  1.3283 +  keyStringBundle->GetStringFromName(MOZ_UTF16("MODIFIER_SEPARATOR"),
  1.3284 +                                     getter_Copies(separator));
  1.3285 +
  1.3286 +  nsAutoString modifierName;
  1.3287 +  if (mModifierMask & kControl) {
  1.3288 +    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_CONTROL"),
  1.3289 +                                       getter_Copies(modifierName));
  1.3290 +
  1.3291 +    aValue.Append(modifierName);
  1.3292 +    aValue.Append(separator);
  1.3293 +  }
  1.3294 +
  1.3295 +  if (mModifierMask & kAlt) {
  1.3296 +    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_ALT"),
  1.3297 +                                       getter_Copies(modifierName));
  1.3298 +
  1.3299 +    aValue.Append(modifierName);
  1.3300 +    aValue.Append(separator);
  1.3301 +  }
  1.3302 +
  1.3303 +  if (mModifierMask & kShift) {
  1.3304 +    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_SHIFT"),
  1.3305 +                                       getter_Copies(modifierName));
  1.3306 +
  1.3307 +    aValue.Append(modifierName);
  1.3308 +    aValue.Append(separator);
  1.3309 +  }
  1.3310 +
  1.3311 +  if (mModifierMask & kMeta) {
  1.3312 +    keyStringBundle->GetStringFromName(MOZ_UTF16("VK_META"),
  1.3313 +                                       getter_Copies(modifierName));
  1.3314 +
  1.3315 +    aValue.Append(modifierName);
  1.3316 +    aValue.Append(separator);
  1.3317 +  }
  1.3318 +
  1.3319 +  aValue.Append(mKey);
  1.3320 +}
  1.3321 +
  1.3322 +void
  1.3323 +KeyBinding::ToAtkFormat(nsAString& aValue) const
  1.3324 +{
  1.3325 +  nsAutoString modifierName;
  1.3326 +  if (mModifierMask & kControl)
  1.3327 +    aValue.Append(NS_LITERAL_STRING("<Control>"));
  1.3328 +
  1.3329 +  if (mModifierMask & kAlt)
  1.3330 +    aValue.Append(NS_LITERAL_STRING("<Alt>"));
  1.3331 +
  1.3332 +  if (mModifierMask & kShift)
  1.3333 +    aValue.Append(NS_LITERAL_STRING("<Shift>"));
  1.3334 +
  1.3335 +  if (mModifierMask & kMeta)
  1.3336 +      aValue.Append(NS_LITERAL_STRING("<Meta>"));
  1.3337 +
  1.3338 +  aValue.Append(mKey);
  1.3339 +}
  1.3340 +

mercurial