LCOV - code coverage report
Current view: top level - accessible/generic - Accessible.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1436 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 108 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "Accessible-inl.h"
       7             : 
       8             : #include "nsIXBLAccessible.h"
       9             : 
      10             : #include "EmbeddedObjCollector.h"
      11             : #include "AccGroupInfo.h"
      12             : #include "AccIterator.h"
      13             : #include "nsAccUtils.h"
      14             : #include "nsAccessibilityService.h"
      15             : #include "ApplicationAccessible.h"
      16             : #include "NotificationController.h"
      17             : #include "nsEventShell.h"
      18             : #include "nsTextEquivUtils.h"
      19             : #include "DocAccessibleChild.h"
      20             : #include "EventTree.h"
      21             : #include "Relation.h"
      22             : #include "Role.h"
      23             : #include "RootAccessible.h"
      24             : #include "States.h"
      25             : #include "StyleInfo.h"
      26             : #include "TableAccessible.h"
      27             : #include "TableCellAccessible.h"
      28             : #include "TreeWalker.h"
      29             : 
      30             : #include "nsIDOMElement.h"
      31             : #include "nsIDOMNodeFilter.h"
      32             : #include "nsIDOMHTMLElement.h"
      33             : #include "nsIDOMKeyEvent.h"
      34             : #include "nsIDOMTreeWalker.h"
      35             : #include "nsIDOMXULButtonElement.h"
      36             : #include "nsIDOMXULDocument.h"
      37             : #include "nsIDOMXULElement.h"
      38             : #include "nsIDOMXULLabelElement.h"
      39             : #include "nsIDOMXULSelectCntrlEl.h"
      40             : #include "nsIDOMXULSelectCntrlItemEl.h"
      41             : #include "nsPIDOMWindow.h"
      42             : 
      43             : #include "nsIDocument.h"
      44             : #include "nsIContent.h"
      45             : #include "nsIForm.h"
      46             : #include "nsIFormControl.h"
      47             : 
      48             : #include "nsDeckFrame.h"
      49             : #include "nsLayoutUtils.h"
      50             : #include "nsIPresShell.h"
      51             : #include "nsIStringBundle.h"
      52             : #include "nsPresContext.h"
      53             : #include "nsIFrame.h"
      54             : #include "nsView.h"
      55             : #include "nsIDocShellTreeItem.h"
      56             : #include "nsIScrollableFrame.h"
      57             : #include "nsFocusManager.h"
      58             : 
      59             : #include "nsXPIDLString.h"
      60             : #include "nsUnicharUtils.h"
      61             : #include "nsReadableUtils.h"
      62             : #include "prdtoa.h"
      63             : #include "nsIAtom.h"
      64             : #include "nsIURI.h"
      65             : #include "nsArrayUtils.h"
      66             : #include "nsIMutableArray.h"
      67             : #include "nsIObserverService.h"
      68             : #include "nsIServiceManager.h"
      69             : #include "nsWhitespaceTokenizer.h"
      70             : #include "nsAttrName.h"
      71             : 
      72             : #ifdef DEBUG
      73             : #include "nsIDOMCharacterData.h"
      74             : #endif
      75             : 
      76             : #include "mozilla/Assertions.h"
      77             : #include "mozilla/BasicEvents.h"
      78             : #include "mozilla/EventStates.h"
      79             : #include "mozilla/FloatingPoint.h"
      80             : #include "mozilla/MouseEvents.h"
      81             : #include "mozilla/Unused.h"
      82             : #include "mozilla/Preferences.h"
      83             : #include "mozilla/dom/CanvasRenderingContext2D.h"
      84             : #include "mozilla/dom/Element.h"
      85             : #include "mozilla/dom/HTMLCanvasElement.h"
      86             : #include "mozilla/dom/HTMLBodyElement.h"
      87             : #include "mozilla/dom/TreeWalker.h"
      88             : 
      89             : using namespace mozilla;
      90             : using namespace mozilla::a11y;
      91             : 
      92             : 
      93             : ////////////////////////////////////////////////////////////////////////////////
      94             : // Accessible: nsISupports and cycle collection
      95             : 
      96             : NS_IMPL_CYCLE_COLLECTION_CLASS(Accessible)
      97           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Accessible)
      98           0 :   tmp->Shutdown();
      99           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     100           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Accessible)
     101           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc)
     102           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     103             : 
     104           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible)
     105           0 :   if (aIID.Equals(NS_GET_IID(Accessible)))
     106           0 :     foundInterface = this;
     107             :   else
     108           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, Accessible)
     109           0 : NS_INTERFACE_MAP_END
     110             : 
     111           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible)
     112           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease())
     113             : 
     114           0 : Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) :
     115             :   mContent(aContent), mDoc(aDoc),
     116             :   mParent(nullptr), mIndexInParent(-1),
     117             :   mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX),
     118             :   mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0),
     119           0 :   mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false)
     120             : {
     121           0 :   mBits.groupInfo = nullptr;
     122           0 :   mInt.mIndexOfEmbeddedChild = -1;
     123           0 : }
     124             : 
     125           0 : Accessible::~Accessible()
     126             : {
     127           0 :   NS_ASSERTION(!mDoc, "LastRelease was never called!?!");
     128           0 : }
     129             : 
     130             : ENameValueFlag
     131           0 : Accessible::Name(nsString& aName)
     132             : {
     133           0 :   aName.Truncate();
     134             : 
     135           0 :   if (!HasOwnContent())
     136           0 :     return eNameOK;
     137             : 
     138           0 :   ARIAName(aName);
     139           0 :   if (!aName.IsEmpty())
     140           0 :     return eNameOK;
     141             : 
     142           0 :   nsCOMPtr<nsIXBLAccessible> xblAccessible(do_QueryInterface(mContent));
     143           0 :   if (xblAccessible) {
     144           0 :     xblAccessible->GetAccessibleName(aName);
     145           0 :     if (!aName.IsEmpty())
     146           0 :       return eNameOK;
     147             :   }
     148             : 
     149           0 :   ENameValueFlag nameFlag = NativeName(aName);
     150           0 :   if (!aName.IsEmpty())
     151           0 :     return nameFlag;
     152             : 
     153             :   // In the end get the name from tooltip.
     154           0 :   if (mContent->IsHTMLElement()) {
     155           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) {
     156           0 :       aName.CompressWhitespace();
     157           0 :       return eNameFromTooltip;
     158             :     }
     159           0 :   } else if (mContent->IsXULElement()) {
     160           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
     161           0 :       aName.CompressWhitespace();
     162           0 :       return eNameFromTooltip;
     163             :     }
     164           0 :   } else if (mContent->IsSVGElement()) {
     165             :     // If user agents need to choose among multiple ‘desc’ or ‘title’ elements
     166             :     // for processing, the user agent shall choose the first one.
     167           0 :     for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
     168           0 :          childElm = childElm->GetNextSibling()) {
     169           0 :       if (childElm->IsSVGElement(nsGkAtoms::desc)) {
     170           0 :         nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
     171           0 :         return eNameFromTooltip;
     172             :       }
     173             :     }
     174             :   }
     175             : 
     176           0 :   if (nameFlag != eNoNameOnPurpose)
     177           0 :     aName.SetIsVoid(true);
     178             : 
     179           0 :   return nameFlag;
     180             : }
     181             : 
     182             : void
     183           0 : Accessible::Description(nsString& aDescription)
     184             : {
     185             :   // There are 4 conditions that make an accessible have no accDescription:
     186             :   // 1. it's a text node; or
     187             :   // 2. It has no DHTML describedby property
     188             :   // 3. it doesn't have an accName; or
     189             :   // 4. its title attribute already equals to its accName nsAutoString name;
     190             : 
     191           0 :   if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT))
     192           0 :     return;
     193             : 
     194             :   nsTextEquivUtils::
     195           0 :     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby,
     196           0 :                            aDescription);
     197             : 
     198           0 :   if (aDescription.IsEmpty()) {
     199           0 :     NativeDescription(aDescription);
     200             : 
     201           0 :     if (aDescription.IsEmpty()) {
     202             :       // Keep the Name() method logic.
     203           0 :       if (mContent->IsHTMLElement()) {
     204           0 :         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription);
     205           0 :       } else if (mContent->IsXULElement()) {
     206           0 :         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription);
     207           0 :       } else if (mContent->IsSVGElement()) {
     208           0 :         for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
     209           0 :              childElm = childElm->GetNextSibling()) {
     210           0 :           if (childElm->IsSVGElement(nsGkAtoms::desc)) {
     211           0 :             nsTextEquivUtils::AppendTextEquivFromContent(this, childElm,
     212           0 :                                                          &aDescription);
     213           0 :             break;
     214             :           }
     215             :         }
     216             :       }
     217             :     }
     218             :   }
     219             : 
     220           0 :   if (!aDescription.IsEmpty()) {
     221           0 :     aDescription.CompressWhitespace();
     222           0 :     nsAutoString name;
     223           0 :     Name(name);
     224             :     // Don't expose a description if it is the same as the name.
     225           0 :     if (aDescription.Equals(name))
     226           0 :       aDescription.Truncate();
     227             :   }
     228             : }
     229             : 
     230             : KeyBinding
     231           0 : Accessible::AccessKey() const
     232             : {
     233           0 :   if (!HasOwnContent())
     234           0 :     return KeyBinding();
     235             : 
     236           0 :   uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent);
     237           0 :   if (!key && mContent->IsElement()) {
     238           0 :     Accessible* label = nullptr;
     239             : 
     240             :     // Copy access key from label node.
     241           0 :     if (mContent->IsHTMLElement()) {
     242             :       // Unless it is labeled via an ancestor <label>, in which case that would
     243             :       // be redundant.
     244             :       HTMLLabelIterator iter(Document(), this,
     245           0 :                              HTMLLabelIterator::eSkipAncestorLabel);
     246           0 :       label = iter.Next();
     247             : 
     248           0 :     } else if (mContent->IsXULElement()) {
     249           0 :       XULLabelIterator iter(Document(), mContent);
     250           0 :       label = iter.Next();
     251             :     }
     252             : 
     253           0 :     if (label)
     254           0 :       key = nsCoreUtils::GetAccessKeyFor(label->GetContent());
     255             :   }
     256             : 
     257           0 :   if (!key)
     258           0 :     return KeyBinding();
     259             : 
     260             :   // Get modifier mask. Use ui.key.generalAccessKey (unless it is -1).
     261           0 :   switch (Preferences::GetInt("ui.key.generalAccessKey", -1)) {
     262             :   case -1:
     263           0 :     break;
     264             :   case nsIDOMKeyEvent::DOM_VK_SHIFT:
     265           0 :     return KeyBinding(key, KeyBinding::kShift);
     266             :   case nsIDOMKeyEvent::DOM_VK_CONTROL:
     267           0 :     return KeyBinding(key, KeyBinding::kControl);
     268             :   case nsIDOMKeyEvent::DOM_VK_ALT:
     269           0 :     return KeyBinding(key, KeyBinding::kAlt);
     270             :   case nsIDOMKeyEvent::DOM_VK_META:
     271           0 :     return KeyBinding(key, KeyBinding::kMeta);
     272             :   default:
     273           0 :     return KeyBinding();
     274             :   }
     275             : 
     276             :   // Determine the access modifier used in this context.
     277           0 :   nsIDocument* document = mContent->GetUncomposedDoc();
     278           0 :   if (!document)
     279           0 :     return KeyBinding();
     280             : 
     281           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(document->GetDocShell());
     282           0 :   if (!treeItem)
     283           0 :     return KeyBinding();
     284             : 
     285           0 :   nsresult rv = NS_ERROR_FAILURE;
     286           0 :   int32_t modifierMask = 0;
     287           0 :   switch (treeItem->ItemType()) {
     288             :     case nsIDocShellTreeItem::typeChrome:
     289           0 :       rv = Preferences::GetInt("ui.key.chromeAccess", &modifierMask);
     290           0 :       break;
     291             :     case nsIDocShellTreeItem::typeContent:
     292           0 :       rv = Preferences::GetInt("ui.key.contentAccess", &modifierMask);
     293           0 :       break;
     294             :   }
     295             : 
     296           0 :   return NS_SUCCEEDED(rv) ? KeyBinding(key, modifierMask) : KeyBinding();
     297             : }
     298             : 
     299             : KeyBinding
     300           0 : Accessible::KeyboardShortcut() const
     301             : {
     302           0 :   return KeyBinding();
     303             : }
     304             : 
     305             : void
     306           0 : Accessible::TranslateString(const nsString& aKey, nsAString& aStringOut)
     307             : {
     308             :   nsCOMPtr<nsIStringBundleService> stringBundleService =
     309           0 :     services::GetStringBundleService();
     310           0 :   if (!stringBundleService)
     311           0 :     return;
     312             : 
     313           0 :   nsCOMPtr<nsIStringBundle> stringBundle;
     314           0 :   stringBundleService->CreateBundle(
     315             :     "chrome://global-platform/locale/accessible.properties",
     316           0 :     getter_AddRefs(stringBundle));
     317           0 :   if (!stringBundle)
     318           0 :     return;
     319             : 
     320           0 :   nsXPIDLString xsValue;
     321           0 :   nsresult rv = stringBundle->GetStringFromName(aKey.get(), getter_Copies(xsValue));
     322           0 :   if (NS_SUCCEEDED(rv))
     323           0 :     aStringOut.Assign(xsValue);
     324             : }
     325             : 
     326             : uint64_t
     327           0 : Accessible::VisibilityState()
     328             : {
     329           0 :   nsIFrame* frame = GetFrame();
     330           0 :   if (!frame)
     331           0 :     return states::INVISIBLE;
     332             : 
     333             :   // Walk the parent frame chain to see if there's invisible parent or the frame
     334             :   // is in background tab.
     335           0 :   if (!frame->StyleVisibility()->IsVisible())
     336           0 :     return states::INVISIBLE;
     337             : 
     338             :   // Offscreen state if the document's visibility state is not visible.
     339           0 :   if (Document()->IsHidden())
     340           0 :     return states::OFFSCREEN;
     341             : 
     342           0 :   nsIFrame* curFrame = frame;
     343           0 :   do {
     344           0 :     nsView* view = curFrame->GetView();
     345           0 :     if (view && view->GetVisibility() == nsViewVisibility_kHide)
     346           0 :       return states::INVISIBLE;
     347             : 
     348           0 :     if (nsLayoutUtils::IsPopup(curFrame))
     349           0 :       return 0;
     350             : 
     351             :     // Offscreen state for background tab content and invisible for not selected
     352             :     // deck panel.
     353           0 :     nsIFrame* parentFrame = curFrame->GetParent();
     354           0 :     nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
     355           0 :     if (deckFrame && deckFrame->GetSelectedBox() != curFrame) {
     356           0 :       if (deckFrame->GetContent()->IsXULElement(nsGkAtoms::tabpanels))
     357           0 :         return states::OFFSCREEN;
     358             : 
     359           0 :       NS_NOTREACHED("Children of not selected deck panel are not accessible.");
     360           0 :       return states::INVISIBLE;
     361             :     }
     362             : 
     363             :     // If contained by scrollable frame then check that at least 12 pixels
     364             :     // around the object is visible, otherwise the object is offscreen.
     365           0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);
     366           0 :     if (scrollableFrame) {
     367           0 :       nsRect scrollPortRect = scrollableFrame->GetScrollPortRect();
     368             :       nsRect frameRect = nsLayoutUtils::TransformFrameRectToAncestor(
     369           0 :         frame, frame->GetRectRelativeToSelf(), parentFrame);
     370           0 :       if (!scrollPortRect.Contains(frameRect)) {
     371           0 :         const nscoord kMinPixels = nsPresContext::CSSPixelsToAppUnits(12);
     372           0 :         scrollPortRect.Deflate(kMinPixels, kMinPixels);
     373           0 :         if (!scrollPortRect.Intersects(frameRect))
     374           0 :           return states::OFFSCREEN;
     375             :       }
     376             :     }
     377             : 
     378           0 :     if (!parentFrame) {
     379           0 :       parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
     380           0 :       if (parentFrame && !parentFrame->StyleVisibility()->IsVisible())
     381           0 :         return states::INVISIBLE;
     382             :     }
     383             : 
     384           0 :     curFrame = parentFrame;
     385           0 :   } while (curFrame);
     386             : 
     387             :   // Zero area rects can occur in the first frame of a multi-frame text flow,
     388             :   // in which case the rendered text is not empty and the frame should not be
     389             :   // marked invisible.
     390             :   // XXX Can we just remove this check? Why do we need to mark empty
     391             :   // text invisible?
     392           0 :   if (frame->IsTextFrame() &&
     393           0 :       !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
     394           0 :       frame->GetRect().IsEmpty()) {
     395             :     nsIFrame::RenderedText text = frame->GetRenderedText(0,
     396             :         UINT32_MAX, nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
     397           0 :         nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
     398           0 :     if (text.mString.IsEmpty()) {
     399           0 :       return states::INVISIBLE;
     400             :     }
     401             :   }
     402             : 
     403           0 :   return 0;
     404             : }
     405             : 
     406             : uint64_t
     407           0 : Accessible::NativeState()
     408             : {
     409           0 :   uint64_t state = 0;
     410             : 
     411           0 :   if (!IsInDocument())
     412           0 :     state |= states::STALE;
     413             : 
     414           0 :   if (HasOwnContent() && mContent->IsElement()) {
     415           0 :     EventStates elementState = mContent->AsElement()->State();
     416             : 
     417           0 :     if (elementState.HasState(NS_EVENT_STATE_INVALID))
     418           0 :       state |= states::INVALID;
     419             : 
     420           0 :     if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
     421           0 :       state |= states::REQUIRED;
     422             : 
     423           0 :     state |= NativeInteractiveState();
     424           0 :     if (FocusMgr()->IsFocused(this))
     425           0 :       state |= states::FOCUSED;
     426             :   }
     427             : 
     428             :   // Gather states::INVISIBLE and states::OFFSCREEN flags for this object.
     429           0 :   state |= VisibilityState();
     430             : 
     431           0 :   nsIFrame *frame = GetFrame();
     432           0 :   if (frame) {
     433           0 :     if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
     434           0 :       state |= states::FLOATING;
     435             : 
     436             :     // XXX we should look at layout for non XUL box frames, but need to decide
     437             :     // how that interacts with ARIA.
     438           0 :     if (HasOwnContent() && mContent->IsXULElement() && frame->IsXULBoxFrame()) {
     439           0 :       const nsStyleXUL* xulStyle = frame->StyleXUL();
     440           0 :       if (xulStyle && frame->IsXULBoxFrame()) {
     441             :         // In XUL all boxes are either vertical or horizontal
     442           0 :         if (xulStyle->mBoxOrient == StyleBoxOrient::Vertical)
     443           0 :           state |= states::VERTICAL;
     444             :         else
     445           0 :           state |= states::HORIZONTAL;
     446             :       }
     447             :     }
     448             :   }
     449             : 
     450             :   // Check if a XUL element has the popup attribute (an attached popup menu).
     451           0 :   if (HasOwnContent() && mContent->IsXULElement() &&
     452           0 :       mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
     453           0 :     state |= states::HASPOPUP;
     454             : 
     455             :   // Bypass the link states specialization for non links.
     456           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
     457           0 :   if (!roleMapEntry || roleMapEntry->roleRule == kUseNativeRole ||
     458           0 :       roleMapEntry->role == roles::LINK)
     459           0 :     state |= NativeLinkState();
     460             : 
     461           0 :   return state;
     462             : }
     463             : 
     464             : uint64_t
     465           0 : Accessible::NativeInteractiveState() const
     466             : {
     467           0 :   if (!mContent->IsElement())
     468           0 :     return 0;
     469             : 
     470           0 :   if (NativelyUnavailable())
     471           0 :     return states::UNAVAILABLE;
     472             : 
     473           0 :   nsIFrame* frame = GetFrame();
     474           0 :   if (frame && frame->IsFocusable())
     475           0 :     return states::FOCUSABLE;
     476             : 
     477           0 :   return 0;
     478             : }
     479             : 
     480             : uint64_t
     481           0 : Accessible::NativeLinkState() const
     482             : {
     483           0 :   return 0;
     484             : }
     485             : 
     486             : bool
     487           0 : Accessible::NativelyUnavailable() const
     488             : {
     489           0 :   if (mContent->IsHTMLElement())
     490           0 :     return mContent->AsElement()->State().HasState(NS_EVENT_STATE_DISABLED);
     491             : 
     492           0 :   return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
     493           0 :                                nsGkAtoms::_true, eCaseMatters);
     494             : }
     495             : 
     496             : Accessible*
     497           0 : Accessible::FocusedChild()
     498             : {
     499           0 :   Accessible* focus = FocusMgr()->FocusedAccessible();
     500           0 :   if (focus && (focus == this || focus->Parent() == this))
     501           0 :     return focus;
     502             : 
     503           0 :   return nullptr;
     504             : }
     505             : 
     506             : Accessible*
     507           0 : Accessible::ChildAtPoint(int32_t aX, int32_t aY,
     508             :                          EWhichChildAtPoint aWhichChild)
     509             : {
     510             :   // If we can't find the point in a child, we will return the fallback answer:
     511             :   // we return |this| if the point is within it, otherwise nullptr.
     512           0 :   Accessible* fallbackAnswer = nullptr;
     513           0 :   nsIntRect rect = Bounds();
     514           0 :   if (aX >= rect.x && aX < rect.x + rect.width &&
     515           0 :       aY >= rect.y && aY < rect.y + rect.height)
     516           0 :     fallbackAnswer = this;
     517             : 
     518           0 :   if (nsAccUtils::MustPrune(this))  // Do not dig any further
     519           0 :     return fallbackAnswer;
     520             : 
     521             :   // Search an accessible at the given point starting from accessible document
     522             :   // because containing block (see CSS2) for out of flow element (for example,
     523             :   // absolutely positioned element) may be different from its DOM parent and
     524             :   // therefore accessible for containing block may be different from accessible
     525             :   // for DOM parent but GetFrameForPoint() should be called for containing block
     526             :   // to get an out of flow element.
     527           0 :   DocAccessible* accDocument = Document();
     528           0 :   NS_ENSURE_TRUE(accDocument, nullptr);
     529             : 
     530           0 :   nsIFrame* rootFrame = accDocument->GetFrame();
     531           0 :   NS_ENSURE_TRUE(rootFrame, nullptr);
     532             : 
     533           0 :   nsIFrame* startFrame = rootFrame;
     534             : 
     535             :   // Check whether the point is at popup content.
     536           0 :   nsIWidget* rootWidget = rootFrame->GetView()->GetNearestWidget(nullptr);
     537           0 :   NS_ENSURE_TRUE(rootWidget, nullptr);
     538             : 
     539           0 :   LayoutDeviceIntRect rootRect = rootWidget->GetScreenBounds();
     540             : 
     541             :   WidgetMouseEvent dummyEvent(true, eMouseMove, rootWidget,
     542           0 :                               WidgetMouseEvent::eSynthesized);
     543           0 :   dummyEvent.mRefPoint = LayoutDeviceIntPoint(aX - rootRect.x, aY - rootRect.y);
     544             : 
     545             :   nsIFrame* popupFrame = nsLayoutUtils::
     546           0 :     GetPopupFrameForEventCoordinates(accDocument->PresContext()->GetRootPresContext(),
     547           0 :                                      &dummyEvent);
     548           0 :   if (popupFrame) {
     549             :     // If 'this' accessible is not inside the popup then ignore the popup when
     550             :     // searching an accessible at point.
     551             :     DocAccessible* popupDoc =
     552           0 :       GetAccService()->GetDocAccessible(popupFrame->GetContent()->OwnerDoc());
     553             :     Accessible* popupAcc =
     554           0 :       popupDoc->GetAccessibleOrContainer(popupFrame->GetContent());
     555           0 :     Accessible* popupChild = this;
     556           0 :     while (popupChild && !popupChild->IsDoc() && popupChild != popupAcc)
     557           0 :       popupChild = popupChild->Parent();
     558             : 
     559           0 :     if (popupChild == popupAcc)
     560           0 :       startFrame = popupFrame;
     561             :   }
     562             : 
     563           0 :   nsPresContext* presContext = startFrame->PresContext();
     564           0 :   nsRect screenRect = startFrame->GetScreenRectInAppUnits();
     565           0 :     nsPoint offset(presContext->DevPixelsToAppUnits(aX) - screenRect.x,
     566           0 :                    presContext->DevPixelsToAppUnits(aY) - screenRect.y);
     567           0 :   nsIFrame* foundFrame = nsLayoutUtils::GetFrameForPoint(startFrame, offset);
     568             : 
     569           0 :   nsIContent* content = nullptr;
     570           0 :   if (!foundFrame || !(content = foundFrame->GetContent()))
     571           0 :     return fallbackAnswer;
     572             : 
     573             :   // Get accessible for the node with the point or the first accessible in
     574             :   // the DOM parent chain.
     575           0 :   DocAccessible* contentDocAcc = GetAccService()->
     576           0 :     GetDocAccessible(content->OwnerDoc());
     577             : 
     578             :   // contentDocAcc in some circumstances can be nullptr. See bug 729861
     579           0 :   NS_ASSERTION(contentDocAcc, "could not get the document accessible");
     580           0 :   if (!contentDocAcc)
     581           0 :     return fallbackAnswer;
     582             : 
     583           0 :   Accessible* accessible = contentDocAcc->GetAccessibleOrContainer(content);
     584           0 :   if (!accessible)
     585           0 :     return fallbackAnswer;
     586             : 
     587             :   // Hurray! We have an accessible for the frame that layout gave us.
     588             :   // Since DOM node of obtained accessible may be out of flow then we should
     589             :   // ensure obtained accessible is a child of this accessible.
     590           0 :   Accessible* child = accessible;
     591           0 :   while (child != this) {
     592           0 :     Accessible* parent = child->Parent();
     593           0 :     if (!parent) {
     594             :       // Reached the top of the hierarchy. These bounds were inside an
     595             :       // accessible that is not a descendant of this one.
     596           0 :       return fallbackAnswer;
     597             :     }
     598             : 
     599             :     // If we landed on a legitimate child of |this|, and we want the direct
     600             :     // child, return it here.
     601           0 :     if (parent == this && aWhichChild == eDirectChild)
     602           0 :         return child;
     603             : 
     604           0 :     child = parent;
     605             :   }
     606             : 
     607             :   // Manually walk through accessible children and see if the are within this
     608             :   // point. Skip offscreen or invisible accessibles. This takes care of cases
     609             :   // where layout won't walk into things for us, such as image map areas and
     610             :   // sub documents (XXX: subdocuments should be handled by methods of
     611             :   // OuterDocAccessibles).
     612           0 :   uint32_t childCount = accessible->ChildCount();
     613           0 :   for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
     614           0 :     Accessible* child = accessible->GetChildAt(childIdx);
     615             : 
     616           0 :     nsIntRect childRect = child->Bounds();
     617           0 :     if (aX >= childRect.x && aX < childRect.x + childRect.width &&
     618           0 :         aY >= childRect.y && aY < childRect.y + childRect.height &&
     619           0 :         (child->State() & states::INVISIBLE) == 0) {
     620             : 
     621           0 :       if (aWhichChild == eDeepestChild)
     622           0 :         return child->ChildAtPoint(aX, aY, eDeepestChild);
     623             : 
     624           0 :       return child;
     625             :     }
     626             :   }
     627             : 
     628           0 :   return accessible;
     629             : }
     630             : 
     631             : nsRect
     632           0 : Accessible::RelativeBounds(nsIFrame** aBoundingFrame) const
     633             : {
     634           0 :   nsIFrame* frame = GetFrame();
     635           0 :   if (frame && mContent) {
     636           0 :     bool* hasHitRegionRect = static_cast<bool*>(mContent->GetProperty(nsGkAtoms::hitregion));
     637             : 
     638           0 :     if (hasHitRegionRect && mContent->IsElement()) {
     639             :       // This is for canvas fallback content
     640             :       // Find a canvas frame the found hit region is relative to.
     641           0 :       nsIFrame* canvasFrame = frame->GetParent();
     642           0 :       if (canvasFrame) {
     643             :         canvasFrame = nsLayoutUtils::GetClosestFrameOfType(
     644           0 :           canvasFrame, LayoutFrameType::HTMLCanvas);
     645             :       }
     646             : 
     647             :       // make the canvas the bounding frame
     648           0 :       if (canvasFrame) {
     649           0 :         *aBoundingFrame = canvasFrame;
     650             :         dom::HTMLCanvasElement *canvas =
     651           0 :           dom::HTMLCanvasElement::FromContent(canvasFrame->GetContent());
     652             : 
     653             :         // get the bounding rect of the hit region
     654           0 :         nsRect bounds;
     655           0 :         if (canvas && canvas->CountContexts() &&
     656           0 :           canvas->GetContextAtIndex(0)->GetHitRegionRect(mContent->AsElement(), bounds)) {
     657           0 :           return bounds;
     658             :         }
     659             :       }
     660             :     }
     661             : 
     662           0 :     *aBoundingFrame = nsLayoutUtils::GetContainingBlockForClientRect(frame);
     663             :     return nsLayoutUtils::
     664             :       GetAllInFlowRectsUnion(frame, *aBoundingFrame,
     665           0 :                              nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
     666             :   }
     667             : 
     668           0 :   return nsRect();
     669             : }
     670             : 
     671             : nsIntRect
     672           0 : Accessible::Bounds() const
     673             : {
     674           0 :   nsIFrame* boundingFrame = nullptr;
     675           0 :   nsRect unionRectTwips = RelativeBounds(&boundingFrame);
     676           0 :   if (!boundingFrame)
     677           0 :     return nsIntRect();
     678             : 
     679           0 :   nsIntRect screenRect;
     680           0 :   nsPresContext* presContext = mDoc->PresContext();
     681           0 :   screenRect.x = presContext->AppUnitsToDevPixels(unionRectTwips.x);
     682           0 :   screenRect.y = presContext->AppUnitsToDevPixels(unionRectTwips.y);
     683           0 :   screenRect.width = presContext->AppUnitsToDevPixels(unionRectTwips.width);
     684           0 :   screenRect.height = presContext->AppUnitsToDevPixels(unionRectTwips.height);
     685             : 
     686             :   // We have the union of the rectangle, now we need to put it in absolute
     687             :   // screen coords.
     688           0 :   nsIntRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits().
     689           0 :     ToNearestPixels(presContext->AppUnitsPerDevPixel());
     690           0 :   screenRect.x += orgRectPixels.x;
     691           0 :   screenRect.y += orgRectPixels.y;
     692             : 
     693           0 :   return screenRect;
     694             : }
     695             : 
     696             : void
     697           0 : Accessible::SetSelected(bool aSelect)
     698             : {
     699           0 :   if (!HasOwnContent())
     700           0 :     return;
     701             : 
     702           0 :   Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
     703           0 :   if (select) {
     704           0 :     if (select->State() & states::MULTISELECTABLE) {
     705           0 :       if (ARIARoleMap()) {
     706           0 :         if (aSelect) {
     707           0 :           mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected,
     708           0 :                             NS_LITERAL_STRING("true"), true);
     709             :         } else {
     710           0 :           mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, true);
     711             :         }
     712             :       }
     713           0 :       return;
     714             :     }
     715             : 
     716           0 :     if (aSelect)
     717           0 :       TakeFocus();
     718             :   }
     719             : }
     720             : 
     721             : void
     722           0 : Accessible::TakeSelection()
     723             : {
     724           0 :   Accessible* select = nsAccUtils::GetSelectableContainer(this, State());
     725           0 :   if (select) {
     726           0 :     if (select->State() & states::MULTISELECTABLE)
     727           0 :       select->UnselectAll();
     728           0 :     SetSelected(true);
     729             :   }
     730           0 : }
     731             : 
     732             : void
     733           0 : Accessible::TakeFocus()
     734             : {
     735           0 :   nsIFrame* frame = GetFrame();
     736           0 :   if (!frame)
     737           0 :     return;
     738             : 
     739           0 :   nsIContent* focusContent = mContent;
     740             : 
     741             :   // If the accessible focus is managed by container widget then focus the
     742             :   // widget and set the accessible as its current item.
     743           0 :   if (!frame->IsFocusable()) {
     744           0 :     Accessible* widget = ContainerWidget();
     745           0 :     if (widget && widget->AreItemsOperable()) {
     746           0 :       nsIContent* widgetElm = widget->GetContent();
     747           0 :       nsIFrame* widgetFrame = widgetElm->GetPrimaryFrame();
     748           0 :       if (widgetFrame && widgetFrame->IsFocusable()) {
     749           0 :         focusContent = widgetElm;
     750           0 :         widget->SetCurrentItem(this);
     751             :       }
     752             :     }
     753             :   }
     754             : 
     755           0 :   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
     756           0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
     757           0 :   if (fm)
     758           0 :     fm->SetFocus(element, 0);
     759             : }
     760             : 
     761             : void
     762           0 : Accessible::XULElmName(DocAccessible* aDocument,
     763             :                        nsIContent* aElm, nsString& aName)
     764             : {
     765             :   /**
     766             :    * 3 main cases for XUL Controls to be labeled
     767             :    *   1 - control contains label="foo"
     768             :    *   2 - control has, as a child, a label element
     769             :    *        - label has either value="foo" or children
     770             :    *   3 - non-child label contains control="controlID"
     771             :    *        - label has either value="foo" or children
     772             :    * Once a label is found, the search is discontinued, so a control
     773             :    *  that has a label child as well as having a label external to
     774             :    *  the control that uses the control="controlID" syntax will use
     775             :    *  the child label for its Name.
     776             :    */
     777             : 
     778             :   // CASE #1 (via label attribute) -- great majority of the cases
     779           0 :   nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl = do_QueryInterface(aElm);
     780           0 :   if (labeledEl) {
     781           0 :     labeledEl->GetLabel(aName);
     782             :   } else {
     783           0 :     nsCOMPtr<nsIDOMXULSelectControlItemElement> itemEl = do_QueryInterface(aElm);
     784           0 :     if (itemEl) {
     785           0 :       itemEl->GetLabel(aName);
     786             :     } else {
     787           0 :       nsCOMPtr<nsIDOMXULSelectControlElement> select = do_QueryInterface(aElm);
     788             :       // Use label if this is not a select control element which
     789             :       // uses label attribute to indicate which option is selected
     790           0 :       if (!select) {
     791           0 :         nsCOMPtr<nsIDOMXULElement> xulEl(do_QueryInterface(aElm));
     792           0 :         if (xulEl)
     793           0 :           xulEl->GetAttribute(NS_LITERAL_STRING("label"), aName);
     794             :       }
     795             :     }
     796             :   }
     797             : 
     798             :   // CASES #2 and #3 ------ label as a child or <label control="id" ... > </label>
     799           0 :   if (aName.IsEmpty()) {
     800           0 :     Accessible* labelAcc = nullptr;
     801           0 :     XULLabelIterator iter(aDocument, aElm);
     802           0 :     while ((labelAcc = iter.Next())) {
     803             :       nsCOMPtr<nsIDOMXULLabelElement> xulLabel =
     804           0 :         do_QueryInterface(labelAcc->GetContent());
     805             :       // Check if label's value attribute is used
     806           0 :       if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(aName)) && aName.IsEmpty()) {
     807             :         // If no value attribute, a non-empty label must contain
     808             :         // children that define its text -- possibly using HTML
     809             :         nsTextEquivUtils::
     810           0 :           AppendTextEquivFromContent(labelAcc, labelAcc->GetContent(), &aName);
     811             :       }
     812             :     }
     813             :   }
     814             : 
     815           0 :   aName.CompressWhitespace();
     816           0 :   if (!aName.IsEmpty())
     817           0 :     return;
     818             : 
     819             :   // Can get text from title of <toolbaritem> if we're a child of a <toolbaritem>
     820           0 :   nsIContent *bindingParent = aElm->GetBindingParent();
     821             :   nsIContent* parent =
     822           0 :     bindingParent? bindingParent->GetParent() : aElm->GetParent();
     823           0 :   nsAutoString ancestorTitle;
     824           0 :   while (parent) {
     825           0 :     if (parent->IsXULElement(nsGkAtoms::toolbaritem) &&
     826           0 :         parent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, ancestorTitle)) {
     827             :       // Before returning this, check if the element itself has a tooltip:
     828           0 :       if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) {
     829           0 :         aName.CompressWhitespace();
     830           0 :         return;
     831             :       }
     832             : 
     833           0 :       aName.Assign(ancestorTitle);
     834           0 :       aName.CompressWhitespace();
     835           0 :       return;
     836             :     }
     837           0 :     parent = parent->GetParent();
     838             :   }
     839             : }
     840             : 
     841             : nsresult
     842           0 : Accessible::HandleAccEvent(AccEvent* aEvent)
     843             : {
     844           0 :   NS_ENSURE_ARG_POINTER(aEvent);
     845             : 
     846           0 :   if (IPCAccessibilityActive() && Document()) {
     847           0 :     DocAccessibleChild* ipcDoc = mDoc->IPCDoc();
     848           0 :     MOZ_ASSERT(ipcDoc);
     849           0 :     if (ipcDoc) {
     850           0 :       uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 :
     851           0 :         reinterpret_cast<uintptr_t>(aEvent->GetAccessible());
     852             : 
     853           0 :       switch(aEvent->GetEventType()) {
     854             :         case nsIAccessibleEvent::EVENT_SHOW:
     855           0 :           ipcDoc->ShowEvent(downcast_accEvent(aEvent));
     856           0 :           break;
     857             : 
     858             :         case nsIAccessibleEvent::EVENT_HIDE:
     859           0 :           ipcDoc->SendHideEvent(id, aEvent->IsFromUserInput());
     860           0 :           break;
     861             : 
     862             :         case nsIAccessibleEvent::EVENT_REORDER:
     863             :           // reorder events on the application acc aren't necessary to tell the parent
     864             :           // about new top level documents.
     865           0 :           if (!aEvent->GetAccessible()->IsApplication())
     866           0 :             ipcDoc->SendEvent(id, aEvent->GetEventType());
     867           0 :           break;
     868             :         case nsIAccessibleEvent::EVENT_STATE_CHANGE: {
     869           0 :           AccStateChangeEvent* event = downcast_accEvent(aEvent);
     870           0 :           ipcDoc->SendStateChangeEvent(id, event->GetState(),
     871           0 :                                        event->IsStateEnabled());
     872           0 :           break;
     873             :         }
     874             :         case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: {
     875           0 :           AccCaretMoveEvent* event = downcast_accEvent(aEvent);
     876           0 :           ipcDoc->SendCaretMoveEvent(id, event->GetCaretOffset());
     877           0 :           break;
     878             :         }
     879             :         case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
     880             :         case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
     881           0 :           AccTextChangeEvent* event = downcast_accEvent(aEvent);
     882           0 :           ipcDoc->SendTextChangeEvent(id, event->ModifiedText(),
     883           0 :                                       event->GetStartOffset(),
     884           0 :                                       event->GetLength(),
     885           0 :                                       event->IsTextInserted(),
     886           0 :                                       event->IsFromUserInput());
     887           0 :           break;
     888             :         }
     889             :         case nsIAccessibleEvent::EVENT_SELECTION:
     890             :         case nsIAccessibleEvent::EVENT_SELECTION_ADD:
     891             :         case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: {
     892           0 :           AccSelChangeEvent* selEvent = downcast_accEvent(aEvent);
     893           0 :           uint64_t widgetID = selEvent->Widget()->IsDoc() ? 0 :
     894           0 :             reinterpret_cast<uintptr_t>(selEvent->Widget());
     895           0 :           ipcDoc->SendSelectionEvent(id, widgetID, aEvent->GetEventType());
     896           0 :           break;
     897             :         }
     898             : #if defined(XP_WIN)
     899             :         case nsIAccessibleEvent::EVENT_FOCUS: {
     900             :           ipcDoc->SendFocusEvent(id);
     901             :           break;
     902             :         }
     903             : #endif
     904             :         default:
     905           0 :           ipcDoc->SendEvent(id, aEvent->GetEventType());
     906             :       }
     907             :     }
     908             :   }
     909             : 
     910           0 :   if (nsCoreUtils::AccEventObserversExist()) {
     911           0 :     nsCoreUtils::DispatchAccEvent(MakeXPCEvent(aEvent));
     912             :   }
     913             : 
     914           0 :   return NS_OK;
     915             : }
     916             : 
     917             : already_AddRefed<nsIPersistentProperties>
     918           0 : Accessible::Attributes()
     919             : {
     920           0 :   nsCOMPtr<nsIPersistentProperties> attributes = NativeAttributes();
     921           0 :   if (!HasOwnContent() || !mContent->IsElement())
     922           0 :     return attributes.forget();
     923             : 
     924             :   // 'xml-roles' attribute for landmark.
     925           0 :   nsIAtom* landmark = LandmarkRole();
     926           0 :   if (landmark) {
     927           0 :     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, landmark);
     928             : 
     929             :   } else {
     930             :     // 'xml-roles' attribute coming from ARIA.
     931           0 :     nsAutoString xmlRoles;
     932           0 :     if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::role, xmlRoles))
     933           0 :       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, xmlRoles);
     934             :   }
     935             : 
     936             :   // Expose object attributes from ARIA attributes.
     937           0 :   nsAutoString unused;
     938           0 :   aria::AttrIterator attribIter(mContent);
     939           0 :   nsAutoString name, value;
     940           0 :   while(attribIter.Next(name, value))
     941           0 :     attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, unused);
     942             : 
     943           0 :   if (IsARIAHidden()) {
     944           0 :     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::hidden,
     945           0 :                            NS_LITERAL_STRING("true"));
     946             :   }
     947             : 
     948             :   // XXX: In ARIA 1.1, the value of aria-haspopup became a token (bug 1355449).
     949           0 :   if (aria::UniversalStatesFor(mContent->AsElement()) & states::HASPOPUP)
     950           0 :     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::haspopup, NS_LITERAL_STRING("true"));
     951             : 
     952             :   // If there is no aria-live attribute then expose default value of 'live'
     953             :   // object attribute used for ARIA role of this accessible.
     954           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
     955           0 :   if (roleMapEntry) {
     956           0 :     if (roleMapEntry->Is(nsGkAtoms::searchbox)) {
     957           0 :       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType,
     958           0 :                              NS_LITERAL_STRING("search"));
     959             :     }
     960             : 
     961           0 :     nsAutoString live;
     962           0 :     nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
     963           0 :     if (live.IsEmpty()) {
     964           0 :       if (nsAccUtils::GetLiveAttrValue(roleMapEntry->liveAttRule, live))
     965           0 :         nsAccUtils::SetAccAttr(attributes, nsGkAtoms::live, live);
     966             :     }
     967             :   }
     968             : 
     969           0 :   return attributes.forget();
     970             : }
     971             : 
     972             : already_AddRefed<nsIPersistentProperties>
     973           0 : Accessible::NativeAttributes()
     974             : {
     975             :   nsCOMPtr<nsIPersistentProperties> attributes =
     976           0 :     do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
     977             : 
     978           0 :   nsAutoString unused;
     979             : 
     980             :   // We support values, so expose the string value as well, via the valuetext
     981             :   // object attribute. We test for the value interface because we don't want
     982             :   // to expose traditional Value() information such as URL's on links and
     983             :   // documents, or text in an input.
     984           0 :   if (HasNumericValue()) {
     985           0 :     nsAutoString valuetext;
     986           0 :     Value(valuetext);
     987           0 :     attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext,
     988           0 :                                   unused);
     989             :   }
     990             : 
     991             :   // Expose checkable object attribute if the accessible has checkable state
     992           0 :   if (State() & states::CHECKABLE) {
     993           0 :     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::checkable,
     994           0 :                            NS_LITERAL_STRING("true"));
     995             :   }
     996             : 
     997             :   // Expose 'explicit-name' attribute.
     998           0 :   nsAutoString name;
     999           0 :   if (Name(name) != eNameFromSubtree && !name.IsVoid()) {
    1000           0 :     attributes->SetStringProperty(NS_LITERAL_CSTRING("explicit-name"),
    1001           0 :                                   NS_LITERAL_STRING("true"), unused);
    1002             :   }
    1003             : 
    1004             :   // Group attributes (level/setsize/posinset)
    1005           0 :   GroupPos groupPos = GroupPosition();
    1006           0 :   nsAccUtils::SetAccGroupAttrs(attributes, groupPos.level,
    1007           0 :                                groupPos.setSize, groupPos.posInSet);
    1008             : 
    1009             :   // If the accessible doesn't have own content (such as list item bullet or
    1010             :   // xul tree item) then don't calculate content based attributes.
    1011           0 :   if (!HasOwnContent())
    1012           0 :     return attributes.forget();
    1013             : 
    1014           0 :   nsEventShell::GetEventAttributes(GetNode(), attributes);
    1015             : 
    1016             :   // Get container-foo computed live region properties based on the closest
    1017             :   // container with the live region attribute. Inner nodes override outer nodes
    1018             :   // within the same document. The inner nodes can be used to override live
    1019             :   // region behavior on more general outer nodes. However, nodes in outer
    1020             :   // documents override nodes in inner documents: outer doc author may want to
    1021             :   // override properties on a widget they used in an iframe.
    1022           0 :   nsIContent* startContent = mContent;
    1023           0 :   while (startContent) {
    1024           0 :     nsIDocument* doc = startContent->GetComposedDoc();
    1025           0 :     if (!doc)
    1026           0 :       break;
    1027             : 
    1028           0 :     nsAccUtils::SetLiveContainerAttributes(attributes, startContent,
    1029           0 :                                            doc->GetRootElement());
    1030             : 
    1031             :     // Allow ARIA live region markup from outer documents to override
    1032           0 :     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
    1033           0 :     if (!docShellTreeItem)
    1034           0 :       break;
    1035             : 
    1036           0 :     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
    1037           0 :     docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
    1038           0 :     if (!sameTypeParent || sameTypeParent == docShellTreeItem)
    1039           0 :       break;
    1040             : 
    1041           0 :     nsIDocument* parentDoc = doc->GetParentDocument();
    1042           0 :     if (!parentDoc)
    1043           0 :       break;
    1044             : 
    1045           0 :     startContent = parentDoc->FindContentForSubDocument(doc);
    1046             :   }
    1047             : 
    1048           0 :   if (!mContent->IsElement())
    1049           0 :     return attributes.forget();
    1050             : 
    1051           0 :   nsAutoString id;
    1052           0 :   if (nsCoreUtils::GetID(mContent, id))
    1053           0 :     attributes->SetStringProperty(NS_LITERAL_CSTRING("id"), id, unused);
    1054             : 
    1055             :   // Expose class because it may have useful microformat information.
    1056           0 :   nsAutoString _class;
    1057           0 :   if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, _class))
    1058           0 :     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::_class, _class);
    1059             : 
    1060             :   // Expose tag.
    1061           0 :   nsAutoString tagName;
    1062           0 :   mContent->NodeInfo()->GetName(tagName);
    1063           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tag, tagName);
    1064             : 
    1065             :   // Expose draggable object attribute.
    1066           0 :   nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mContent);
    1067           0 :   if (htmlElement) {
    1068           0 :     bool draggable = false;
    1069           0 :     htmlElement->GetDraggable(&draggable);
    1070           0 :     if (draggable) {
    1071           0 :       nsAccUtils::SetAccAttr(attributes, nsGkAtoms::draggable,
    1072           0 :                              NS_LITERAL_STRING("true"));
    1073             :     }
    1074             :   }
    1075             : 
    1076             :   // Don't calculate CSS-based object attributes when no frame (i.e.
    1077             :   // the accessible is unattached from the tree).
    1078           0 :   if (!mContent->GetPrimaryFrame())
    1079           0 :     return attributes.forget();
    1080             : 
    1081             :   // CSS style based object attributes.
    1082           0 :   nsAutoString value;
    1083           0 :   StyleInfo styleInfo(mContent->AsElement(), mDoc->PresShell());
    1084             : 
    1085             :   // Expose 'display' attribute.
    1086           0 :   styleInfo.Display(value);
    1087           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::display, value);
    1088             : 
    1089             :   // Expose 'text-align' attribute.
    1090           0 :   styleInfo.TextAlign(value);
    1091           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textAlign, value);
    1092             : 
    1093             :   // Expose 'text-indent' attribute.
    1094           0 :   styleInfo.TextIndent(value);
    1095           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textIndent, value);
    1096             : 
    1097             :   // Expose 'margin-left' attribute.
    1098           0 :   styleInfo.MarginLeft(value);
    1099           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginLeft, value);
    1100             : 
    1101             :   // Expose 'margin-right' attribute.
    1102           0 :   styleInfo.MarginRight(value);
    1103           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginRight, value);
    1104             : 
    1105             :   // Expose 'margin-top' attribute.
    1106           0 :   styleInfo.MarginTop(value);
    1107           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginTop, value);
    1108             : 
    1109             :   // Expose 'margin-bottom' attribute.
    1110           0 :   styleInfo.MarginBottom(value);
    1111           0 :   nsAccUtils::SetAccAttr(attributes, nsGkAtoms::marginBottom, value);
    1112             : 
    1113           0 :   return attributes.forget();
    1114             : }
    1115             : 
    1116             : GroupPos
    1117           0 : Accessible::GroupPosition()
    1118             : {
    1119           0 :   GroupPos groupPos;
    1120           0 :   if (!HasOwnContent())
    1121           0 :     return groupPos;
    1122             : 
    1123             :   // Get group position from ARIA attributes.
    1124           0 :   nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_level, &groupPos.level);
    1125           0 :   nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_setsize, &groupPos.setSize);
    1126           0 :   nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_posinset, &groupPos.posInSet);
    1127             : 
    1128             :   // If ARIA is missed and the accessible is visible then calculate group
    1129             :   // position from hierarchy.
    1130           0 :   if (State() & states::INVISIBLE)
    1131           0 :     return groupPos;
    1132             : 
    1133             :   // Calculate group level if ARIA is missed.
    1134           0 :   if (groupPos.level == 0) {
    1135           0 :     int32_t level = GetLevelInternal();
    1136           0 :     if (level != 0)
    1137           0 :       groupPos.level = level;
    1138             :   }
    1139             : 
    1140             :   // Calculate position in group and group size if ARIA is missed.
    1141           0 :   if (groupPos.posInSet == 0 || groupPos.setSize == 0) {
    1142           0 :     int32_t posInSet = 0, setSize = 0;
    1143           0 :     GetPositionAndSizeInternal(&posInSet, &setSize);
    1144           0 :     if (posInSet != 0 && setSize != 0) {
    1145           0 :       if (groupPos.posInSet == 0)
    1146           0 :         groupPos.posInSet = posInSet;
    1147             : 
    1148           0 :       if (groupPos.setSize == 0)
    1149           0 :         groupPos.setSize = setSize;
    1150             :     }
    1151             :   }
    1152             : 
    1153           0 :   return groupPos;
    1154             : }
    1155             : 
    1156             : uint64_t
    1157           0 : Accessible::State()
    1158             : {
    1159           0 :   if (IsDefunct())
    1160           0 :     return states::DEFUNCT;
    1161             : 
    1162           0 :   uint64_t state = NativeState();
    1163             :   // Apply ARIA states to be sure accessible states will be overridden.
    1164           0 :   ApplyARIAState(&state);
    1165             : 
    1166             :   // If this is an ARIA item of the selectable widget and if it's focused and
    1167             :   // not marked unselected explicitly (i.e. aria-selected="false") then expose
    1168             :   // it as selected to make ARIA widget authors life easier.
    1169           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1170           0 :   if (roleMapEntry && !(state & states::SELECTED) &&
    1171           0 :       !mContent->AttrValueIs(kNameSpaceID_None,
    1172             :                              nsGkAtoms::aria_selected,
    1173             :                              nsGkAtoms::_false, eCaseMatters)) {
    1174             :     // Special case for tabs: focused tab or focus inside related tab panel
    1175             :     // implies selected state.
    1176           0 :     if (roleMapEntry->role == roles::PAGETAB) {
    1177           0 :       if (state & states::FOCUSED) {
    1178           0 :         state |= states::SELECTED;
    1179             :       } else {
    1180             :         // If focus is in a child of the tab panel surely the tab is selected!
    1181           0 :         Relation rel = RelationByType(RelationType::LABEL_FOR);
    1182           0 :         Accessible* relTarget = nullptr;
    1183           0 :         while ((relTarget = rel.Next())) {
    1184           0 :           if (relTarget->Role() == roles::PROPERTYPAGE &&
    1185           0 :               FocusMgr()->IsFocusWithin(relTarget))
    1186           0 :             state |= states::SELECTED;
    1187             :         }
    1188             :       }
    1189           0 :     } else if (state & states::FOCUSED) {
    1190           0 :       Accessible* container = nsAccUtils::GetSelectableContainer(this, state);
    1191           0 :       if (container &&
    1192           0 :           !nsAccUtils::HasDefinedARIAToken(container->GetContent(),
    1193             :                                            nsGkAtoms::aria_multiselectable)) {
    1194           0 :         state |= states::SELECTED;
    1195             :       }
    1196             :     }
    1197             :   }
    1198             : 
    1199           0 :   const uint32_t kExpandCollapseStates = states::COLLAPSED | states::EXPANDED;
    1200           0 :   if ((state & kExpandCollapseStates) == kExpandCollapseStates) {
    1201             :     // Cannot be both expanded and collapsed -- this happens in ARIA expanded
    1202             :     // combobox because of limitation of ARIAMap.
    1203             :     // XXX: Perhaps we will be able to make this less hacky if we support
    1204             :     // extended states in ARIAMap, e.g. derive COLLAPSED from
    1205             :     // EXPANDABLE && !EXPANDED.
    1206           0 :     state &= ~states::COLLAPSED;
    1207             :   }
    1208             : 
    1209           0 :   if (!(state & states::UNAVAILABLE)) {
    1210           0 :     state |= states::ENABLED | states::SENSITIVE;
    1211             : 
    1212             :     // If the object is a current item of container widget then mark it as
    1213             :     // ACTIVE. This allows screen reader virtual buffer modes to know which
    1214             :     // descendant is the current one that would get focus if the user navigates
    1215             :     // to the container widget.
    1216           0 :     Accessible* widget = ContainerWidget();
    1217           0 :     if (widget && widget->CurrentItem() == this)
    1218           0 :       state |= states::ACTIVE;
    1219             :   }
    1220             : 
    1221           0 :   if ((state & states::COLLAPSED) || (state & states::EXPANDED))
    1222           0 :     state |= states::EXPANDABLE;
    1223             : 
    1224             :   // For some reasons DOM node may have not a frame. We tract such accessibles
    1225             :   // as invisible.
    1226           0 :   nsIFrame *frame = GetFrame();
    1227           0 :   if (!frame)
    1228           0 :     return state;
    1229             : 
    1230           0 :   if (frame->StyleEffects()->mOpacity == 1.0f &&
    1231           0 :       !(state & states::INVISIBLE)) {
    1232           0 :     state |= states::OPAQUE1;
    1233             :   }
    1234             : 
    1235           0 :   return state;
    1236             : }
    1237             : 
    1238             : void
    1239           0 : Accessible::ApplyARIAState(uint64_t* aState) const
    1240             : {
    1241           0 :   if (!mContent->IsElement())
    1242           0 :     return;
    1243             : 
    1244           0 :   dom::Element* element = mContent->AsElement();
    1245             : 
    1246             :   // Test for universal states first
    1247           0 :   *aState |= aria::UniversalStatesFor(element);
    1248             : 
    1249           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1250           0 :   if (roleMapEntry) {
    1251             : 
    1252             :     // We only force the readonly bit off if we have a real mapping for the aria
    1253             :     // role. This preserves the ability for screen readers to use readonly
    1254             :     // (primarily on the document) as the hint for creating a virtual buffer.
    1255           0 :     if (roleMapEntry->role != roles::NOTHING)
    1256           0 :       *aState &= ~states::READONLY;
    1257             : 
    1258           0 :     if (mContent->HasID()) {
    1259             :       // If has a role & ID and aria-activedescendant on the container, assume
    1260             :       // focusable.
    1261           0 :       const Accessible* ancestor = this;
    1262           0 :       while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
    1263           0 :         dom::Element* el = ancestor->Elm();
    1264           0 :         if (el &&
    1265           0 :             el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
    1266           0 :           *aState |= states::FOCUSABLE;
    1267           0 :           break;
    1268             :         }
    1269             :       }
    1270             :     }
    1271             :   }
    1272             : 
    1273           0 :   if (*aState & states::FOCUSABLE) {
    1274             :     // Propogate aria-disabled from ancestors down to any focusable descendant.
    1275           0 :     const Accessible* ancestor = this;
    1276           0 :     while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
    1277           0 :       dom::Element* el = ancestor->Elm();
    1278           0 :       if (el && el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
    1279             :                                 nsGkAtoms::_true, eCaseMatters)) {
    1280           0 :         *aState |= states::UNAVAILABLE;
    1281           0 :         break;
    1282             :       }
    1283             :     }
    1284             :   }
    1285             : 
    1286             :   // special case: A native button element whose role got transformed by ARIA to a toggle button
    1287             :   // Also applies to togglable button menus, like in the Dev Tools Web Console.
    1288           0 :   if (IsButton() || IsMenuButton())
    1289           0 :     aria::MapToState(aria::eARIAPressed, element, aState);
    1290             : 
    1291           0 :   if (!roleMapEntry)
    1292           0 :     return;
    1293             : 
    1294           0 :   *aState |= roleMapEntry->state;
    1295             : 
    1296           0 :   if (aria::MapToState(roleMapEntry->attributeMap1, element, aState) &&
    1297           0 :       aria::MapToState(roleMapEntry->attributeMap2, element, aState) &&
    1298           0 :       aria::MapToState(roleMapEntry->attributeMap3, element, aState))
    1299           0 :     aria::MapToState(roleMapEntry->attributeMap4, element, aState);
    1300             : 
    1301             :   // ARIA gridcell inherits editable/readonly states from the grid until it's
    1302             :   // overridden.
    1303           0 :   if ((roleMapEntry->Is(nsGkAtoms::gridcell) ||
    1304           0 :        roleMapEntry->Is(nsGkAtoms::columnheader) ||
    1305           0 :        roleMapEntry->Is(nsGkAtoms::rowheader)) &&
    1306           0 :       !(*aState & (states::READONLY | states::EDITABLE))) {
    1307           0 :     const TableCellAccessible* cell = AsTableCell();
    1308           0 :     if (cell) {
    1309           0 :       TableAccessible* table = cell->Table();
    1310           0 :       if (table) {
    1311           0 :         Accessible* grid = table->AsAccessible();
    1312           0 :         uint64_t gridState = 0;
    1313           0 :         grid->ApplyARIAState(&gridState);
    1314           0 :         *aState |= (gridState & (states::READONLY | states::EDITABLE));
    1315             :       }
    1316             :     }
    1317             :   }
    1318             : }
    1319             : 
    1320             : void
    1321           0 : Accessible::Value(nsString& aValue)
    1322             : {
    1323           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1324           0 :   if (!roleMapEntry)
    1325           0 :     return;
    1326             : 
    1327           0 :   if (roleMapEntry->valueRule != eNoValue) {
    1328             :     // aria-valuenow is a number, and aria-valuetext is the optional text
    1329             :     // equivalent. For the string value, we will try the optional text
    1330             :     // equivalent first.
    1331           0 :     if (!mContent->GetAttr(kNameSpaceID_None,
    1332             :                            nsGkAtoms::aria_valuetext, aValue)) {
    1333           0 :       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow,
    1334           0 :                         aValue);
    1335             :     }
    1336           0 :     return;
    1337             :   }
    1338             : 
    1339             :   // Value of textbox is a textified subtree.
    1340           0 :   if (roleMapEntry->Is(nsGkAtoms::textbox)) {
    1341           0 :     nsTextEquivUtils::GetTextEquivFromSubtree(this, aValue);
    1342           0 :     return;
    1343             :   }
    1344             : 
    1345             :   // Value of combobox is a text of current or selected item.
    1346           0 :   if (roleMapEntry->Is(nsGkAtoms::combobox)) {
    1347           0 :     Accessible* option = CurrentItem();
    1348           0 :     if (!option) {
    1349           0 :       uint32_t childCount = ChildCount();
    1350           0 :       for (uint32_t idx = 0; idx < childCount; idx++) {
    1351           0 :         Accessible* child = mChildren.ElementAt(idx);
    1352           0 :         if (child->IsListControl()) {
    1353           0 :           option = child->GetSelectedItem(0);
    1354           0 :           break;
    1355             :         }
    1356             :       }
    1357             :     }
    1358             : 
    1359           0 :     if (option)
    1360           0 :       nsTextEquivUtils::GetTextEquivFromSubtree(option, aValue);
    1361             :   }
    1362             : }
    1363             : 
    1364             : double
    1365           0 : Accessible::MaxValue() const
    1366             : {
    1367           0 :   return AttrNumericValue(nsGkAtoms::aria_valuemax);
    1368             : }
    1369             : 
    1370             : double
    1371           0 : Accessible::MinValue() const
    1372             : {
    1373           0 :   return AttrNumericValue(nsGkAtoms::aria_valuemin);
    1374             : }
    1375             : 
    1376             : double
    1377           0 : Accessible::Step() const
    1378             : {
    1379           0 :   return UnspecifiedNaN<double>(); // no mimimum increment (step) in ARIA.
    1380             : }
    1381             : 
    1382             : double
    1383           0 : Accessible::CurValue() const
    1384             : {
    1385           0 :   return AttrNumericValue(nsGkAtoms::aria_valuenow);
    1386             : }
    1387             : 
    1388             : bool
    1389           0 : Accessible::SetCurValue(double aValue)
    1390             : {
    1391           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1392           0 :   if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
    1393           0 :     return false;
    1394             : 
    1395           0 :   const uint32_t kValueCannotChange = states::READONLY | states::UNAVAILABLE;
    1396           0 :   if (State() & kValueCannotChange)
    1397           0 :     return false;
    1398             : 
    1399           0 :   double checkValue = MinValue();
    1400           0 :   if (!IsNaN(checkValue) && aValue < checkValue)
    1401           0 :     return false;
    1402             : 
    1403           0 :   checkValue = MaxValue();
    1404           0 :   if (!IsNaN(checkValue) && aValue > checkValue)
    1405           0 :     return false;
    1406             : 
    1407           0 :   nsAutoString strValue;
    1408           0 :   strValue.AppendFloat(aValue);
    1409             : 
    1410           0 :   return NS_SUCCEEDED(
    1411             :     mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_valuenow, strValue, true));
    1412             : }
    1413             : 
    1414             : role
    1415           0 : Accessible::ARIATransformRole(role aRole)
    1416             : {
    1417             :   // Beginning with ARIA 1.1, user agents are expected to use the native host
    1418             :   // language role of the element when the region role is used without a name.
    1419             :   // https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-region
    1420             :   //
    1421             :   // XXX: While the name computation algorithm can be non-trivial in the general
    1422             :   // case, it should not be especially bad here: If the author hasn't used the
    1423             :   // region role, this calculation won't occur. And the region role's name
    1424             :   // calculation rule excludes name from content. That said, this use case is
    1425             :   // another example of why we should consider caching the accessible name. See:
    1426             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=1378235.
    1427           0 :   if (aRole == roles::REGION) {
    1428           0 :     nsAutoString name;
    1429           0 :     Name(name);
    1430           0 :     return name.IsEmpty() ? NativeRole() : aRole;
    1431             :   }
    1432             : 
    1433             :   // XXX: these unfortunate exceptions don't fit into the ARIA table. This is
    1434             :   // where the accessible role depends on both the role and ARIA state.
    1435           0 :   if (aRole == roles::PUSHBUTTON) {
    1436           0 :     if (nsAccUtils::HasDefinedARIAToken(mContent, nsGkAtoms::aria_pressed)) {
    1437             :       // For simplicity, any existing pressed attribute except "" or "undefined"
    1438             :       // indicates a toggle.
    1439           0 :       return roles::TOGGLE_BUTTON;
    1440             :     }
    1441             : 
    1442           0 :     if (mContent->AttrValueIs(kNameSpaceID_None,
    1443             :                               nsGkAtoms::aria_haspopup,
    1444             :                               nsGkAtoms::_true,
    1445             :                               eCaseMatters)) {
    1446             :       // For button with aria-haspopup="true".
    1447           0 :       return roles::BUTTONMENU;
    1448             :     }
    1449             : 
    1450           0 :   } else if (aRole == roles::LISTBOX) {
    1451             :     // A listbox inside of a combobox needs a special role because of ATK
    1452             :     // mapping to menu.
    1453           0 :     if (mParent && mParent->IsCombobox()) {
    1454           0 :       return roles::COMBOBOX_LIST;
    1455             :     } else {
    1456             :       // Listbox is owned by a combobox
    1457           0 :       Relation rel = RelationByType(RelationType::NODE_CHILD_OF);
    1458           0 :       Accessible* targetAcc = nullptr;
    1459           0 :       while ((targetAcc = rel.Next()))
    1460           0 :         if (targetAcc->IsCombobox())
    1461           0 :           return roles::COMBOBOX_LIST;
    1462             :     }
    1463             : 
    1464           0 :   } else if (aRole == roles::OPTION) {
    1465           0 :     if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
    1466           0 :       return roles::COMBOBOX_OPTION;
    1467             : 
    1468           0 :   } else if (aRole == roles::MENUITEM) {
    1469             :     // Menuitem has a submenu.
    1470           0 :     if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_haspopup,
    1471             :                               nsGkAtoms::_true, eCaseMatters)) {
    1472           0 :       return roles::PARENT_MENUITEM;
    1473             :     }
    1474             :   }
    1475             : 
    1476           0 :   return aRole;
    1477             : }
    1478             : 
    1479             : nsIAtom*
    1480           0 : Accessible::LandmarkRole() const
    1481             : {
    1482           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1483           0 :   return roleMapEntry && roleMapEntry->IsOfType(eLandmark) ?
    1484           0 :     *(roleMapEntry->roleAtom) : nullptr;
    1485             : }
    1486             : 
    1487             : role
    1488           0 : Accessible::NativeRole()
    1489             : {
    1490           0 :   return roles::NOTHING;
    1491             : }
    1492             : 
    1493             : uint8_t
    1494           0 : Accessible::ActionCount()
    1495             : {
    1496           0 :   return GetActionRule() == eNoAction ? 0 : 1;
    1497             : }
    1498             : 
    1499             : void
    1500           0 : Accessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
    1501             : {
    1502           0 :   aName.Truncate();
    1503             : 
    1504           0 :   if (aIndex != 0)
    1505           0 :     return;
    1506             : 
    1507           0 :   uint32_t actionRule = GetActionRule();
    1508             : 
    1509           0 :  switch (actionRule) {
    1510             :    case eActivateAction:
    1511           0 :      aName.AssignLiteral("activate");
    1512           0 :      return;
    1513             : 
    1514             :    case eClickAction:
    1515           0 :      aName.AssignLiteral("click");
    1516           0 :      return;
    1517             : 
    1518             :    case ePressAction:
    1519           0 :      aName.AssignLiteral("press");
    1520           0 :      return;
    1521             : 
    1522             :    case eCheckUncheckAction:
    1523             :    {
    1524           0 :      uint64_t state = State();
    1525           0 :      if (state & states::CHECKED)
    1526           0 :        aName.AssignLiteral("uncheck");
    1527           0 :      else if (state & states::MIXED)
    1528           0 :        aName.AssignLiteral("cycle");
    1529             :      else
    1530           0 :        aName.AssignLiteral("check");
    1531           0 :      return;
    1532             :    }
    1533             : 
    1534             :    case eJumpAction:
    1535           0 :      aName.AssignLiteral("jump");
    1536           0 :      return;
    1537             : 
    1538             :    case eOpenCloseAction:
    1539           0 :      if (State() & states::COLLAPSED)
    1540           0 :        aName.AssignLiteral("open");
    1541             :      else
    1542           0 :        aName.AssignLiteral("close");
    1543           0 :      return;
    1544             : 
    1545             :    case eSelectAction:
    1546           0 :      aName.AssignLiteral("select");
    1547           0 :      return;
    1548             : 
    1549             :    case eSwitchAction:
    1550           0 :      aName.AssignLiteral("switch");
    1551           0 :      return;
    1552             : 
    1553             :    case eSortAction:
    1554           0 :      aName.AssignLiteral("sort");
    1555           0 :      return;
    1556             : 
    1557             :    case eExpandAction:
    1558           0 :      if (State() & states::COLLAPSED)
    1559           0 :        aName.AssignLiteral("expand");
    1560             :      else
    1561           0 :        aName.AssignLiteral("collapse");
    1562           0 :      return;
    1563             :   }
    1564             : }
    1565             : 
    1566             : bool
    1567           0 : Accessible::DoAction(uint8_t aIndex)
    1568             : {
    1569           0 :   if (aIndex != 0)
    1570           0 :     return false;
    1571             : 
    1572           0 :   if (GetActionRule() != eNoAction) {
    1573           0 :     DoCommand();
    1574           0 :     return true;
    1575             :   }
    1576             : 
    1577           0 :   return false;
    1578             : }
    1579             : 
    1580             : nsIContent*
    1581           0 : Accessible::GetAtomicRegion() const
    1582             : {
    1583           0 :   nsIContent *loopContent = mContent;
    1584           0 :   nsAutoString atomic;
    1585           0 :   while (loopContent && !loopContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_atomic, atomic))
    1586           0 :     loopContent = loopContent->GetParent();
    1587             : 
    1588           0 :   return atomic.EqualsLiteral("true") ? loopContent : nullptr;
    1589             : }
    1590             : 
    1591             : Relation
    1592           0 : Accessible::RelationByType(RelationType aType)
    1593             : {
    1594           0 :   if (!HasOwnContent())
    1595           0 :     return Relation();
    1596             : 
    1597           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    1598             : 
    1599             :   // Relationships are defined on the same content node that the role would be
    1600             :   // defined on.
    1601           0 :   switch (aType) {
    1602             :     case RelationType::LABELLED_BY: {
    1603             :       Relation rel(new IDRefsIterator(mDoc, mContent,
    1604           0 :                                       nsGkAtoms::aria_labelledby));
    1605           0 :       if (mContent->IsHTMLElement()) {
    1606           0 :         rel.AppendIter(new HTMLLabelIterator(Document(), this));
    1607           0 :       } else if (mContent->IsXULElement()) {
    1608           0 :         rel.AppendIter(new XULLabelIterator(Document(), mContent));
    1609             :       }
    1610             : 
    1611           0 :       return rel;
    1612             :     }
    1613             : 
    1614             :     case RelationType::LABEL_FOR: {
    1615           0 :       Relation rel(new RelatedAccIterator(Document(), mContent,
    1616           0 :                                           nsGkAtoms::aria_labelledby));
    1617           0 :       if (mContent->IsXULElement(nsGkAtoms::label))
    1618           0 :         rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::control));
    1619             : 
    1620           0 :       return rel;
    1621             :     }
    1622             : 
    1623             :     case RelationType::DESCRIBED_BY: {
    1624             :       Relation rel(new IDRefsIterator(mDoc, mContent,
    1625           0 :                                       nsGkAtoms::aria_describedby));
    1626           0 :       if (mContent->IsXULElement())
    1627           0 :         rel.AppendIter(new XULDescriptionIterator(Document(), mContent));
    1628             : 
    1629           0 :       return rel;
    1630             :     }
    1631             : 
    1632             :     case RelationType::DESCRIPTION_FOR: {
    1633           0 :       Relation rel(new RelatedAccIterator(Document(), mContent,
    1634           0 :                                           nsGkAtoms::aria_describedby));
    1635             : 
    1636             :       // This affectively adds an optional control attribute to xul:description,
    1637             :       // which only affects accessibility, by allowing the description to be
    1638             :       // tied to a control.
    1639           0 :       if (mContent->IsXULElement(nsGkAtoms::description))
    1640             :         rel.AppendIter(new IDRefsIterator(mDoc, mContent,
    1641           0 :                                           nsGkAtoms::control));
    1642             : 
    1643           0 :       return rel;
    1644             :     }
    1645             : 
    1646             :     case RelationType::NODE_CHILD_OF: {
    1647           0 :       Relation rel;
    1648             :       // This is an ARIA tree or treegrid that doesn't use owns, so we need to
    1649             :       // get the parent the hard way.
    1650           0 :       if (roleMapEntry && (roleMapEntry->role == roles::OUTLINEITEM ||
    1651           0 :                             roleMapEntry->role == roles::LISTITEM ||
    1652           0 :                             roleMapEntry->role == roles::ROW)) {
    1653           0 :         rel.AppendTarget(GetGroupInfo()->ConceptualParent());
    1654             :       }
    1655             : 
    1656             :       // If accessible is in its own Window, or is the root of a document,
    1657             :       // then we should provide NODE_CHILD_OF relation so that MSAA clients
    1658             :       // can easily get to true parent instead of getting to oleacc's
    1659             :       // ROLE_WINDOW accessible which will prevent us from going up further
    1660             :       // (because it is system generated and has no idea about the hierarchy
    1661             :       // above it).
    1662           0 :       nsIFrame *frame = GetFrame();
    1663           0 :       if (frame) {
    1664           0 :         nsView *view = frame->GetView();
    1665           0 :         if (view) {
    1666           0 :           nsIScrollableFrame *scrollFrame = do_QueryFrame(frame);
    1667           0 :           if (scrollFrame || view->GetWidget() || !frame->GetParent())
    1668           0 :             rel.AppendTarget(Parent());
    1669             :         }
    1670             :       }
    1671             : 
    1672           0 :       return rel;
    1673             :     }
    1674             : 
    1675             :     case RelationType::NODE_PARENT_OF: {
    1676             :       // ARIA tree or treegrid can do the hierarchy by @aria-level, ARIA trees
    1677             :       // also can be organized by groups.
    1678           0 :       if (roleMapEntry &&
    1679           0 :           (roleMapEntry->role == roles::OUTLINEITEM ||
    1680           0 :            roleMapEntry->role == roles::LISTITEM ||
    1681           0 :            roleMapEntry->role == roles::ROW ||
    1682           0 :            roleMapEntry->role == roles::OUTLINE ||
    1683           0 :            roleMapEntry->role == roles::LIST ||
    1684           0 :            roleMapEntry->role == roles::TREE_TABLE)) {
    1685           0 :         return Relation(new ItemIterator(this));
    1686             :       }
    1687             : 
    1688           0 :       return Relation();
    1689             :     }
    1690             : 
    1691             :     case RelationType::CONTROLLED_BY:
    1692           0 :       return Relation(new RelatedAccIterator(Document(), mContent,
    1693           0 :                                              nsGkAtoms::aria_controls));
    1694             : 
    1695             :     case RelationType::CONTROLLER_FOR: {
    1696             :       Relation rel(new IDRefsIterator(mDoc, mContent,
    1697           0 :                                       nsGkAtoms::aria_controls));
    1698           0 :       rel.AppendIter(new HTMLOutputIterator(Document(), mContent));
    1699           0 :       return rel;
    1700             :     }
    1701             : 
    1702             :     case RelationType::FLOWS_TO:
    1703             :       return Relation(new IDRefsIterator(mDoc, mContent,
    1704           0 :                                          nsGkAtoms::aria_flowto));
    1705             : 
    1706             :     case RelationType::FLOWS_FROM:
    1707           0 :       return Relation(new RelatedAccIterator(Document(), mContent,
    1708           0 :                                              nsGkAtoms::aria_flowto));
    1709             : 
    1710             :     case RelationType::MEMBER_OF:
    1711           0 :           return Relation(mDoc, GetAtomicRegion());
    1712             : 
    1713             :     case RelationType::SUBWINDOW_OF:
    1714             :     case RelationType::EMBEDS:
    1715             :     case RelationType::EMBEDDED_BY:
    1716             :     case RelationType::POPUP_FOR:
    1717             :     case RelationType::PARENT_WINDOW_OF:
    1718           0 :       return Relation();
    1719             : 
    1720             :     case RelationType::DEFAULT_BUTTON: {
    1721           0 :       if (mContent->IsHTMLElement()) {
    1722             :         // HTML form controls implements nsIFormControl interface.
    1723           0 :         nsCOMPtr<nsIFormControl> control(do_QueryInterface(mContent));
    1724           0 :         if (control) {
    1725           0 :           nsCOMPtr<nsIForm> form(do_QueryInterface(control->GetFormElement()));
    1726           0 :           if (form) {
    1727             :             nsCOMPtr<nsIContent> formContent =
    1728           0 :               do_QueryInterface(form->GetDefaultSubmitElement());
    1729           0 :             return Relation(mDoc, formContent);
    1730             :           }
    1731             :         }
    1732             :       } else {
    1733             :         // In XUL, use first <button default="true" .../> in the document
    1734             :         nsCOMPtr<nsIDOMXULDocument> xulDoc =
    1735           0 :           do_QueryInterface(mContent->OwnerDoc());
    1736           0 :         nsCOMPtr<nsIDOMXULButtonElement> buttonEl;
    1737           0 :         if (xulDoc) {
    1738           0 :           nsCOMPtr<nsIDOMNodeList> possibleDefaultButtons;
    1739           0 :           xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
    1740           0 :                                          NS_LITERAL_STRING("true"),
    1741           0 :                                          getter_AddRefs(possibleDefaultButtons));
    1742           0 :           if (possibleDefaultButtons) {
    1743             :             uint32_t length;
    1744           0 :             possibleDefaultButtons->GetLength(&length);
    1745           0 :             nsCOMPtr<nsIDOMNode> possibleButton;
    1746             :             // Check for button in list of default="true" elements
    1747           0 :             for (uint32_t count = 0; count < length && !buttonEl; count ++) {
    1748           0 :               possibleDefaultButtons->Item(count, getter_AddRefs(possibleButton));
    1749           0 :               buttonEl = do_QueryInterface(possibleButton);
    1750             :             }
    1751             :           }
    1752           0 :           if (!buttonEl) { // Check for anonymous accept button in <dialog>
    1753           0 :             dom::Element* rootElm = mContent->OwnerDoc()->GetRootElement();
    1754           0 :             if (rootElm) {
    1755           0 :               nsIContent* possibleButtonEl = rootElm->OwnerDoc()->
    1756           0 :                 GetAnonymousElementByAttribute(rootElm, nsGkAtoms::_default,
    1757           0 :                                                NS_LITERAL_STRING("true"));
    1758           0 :               buttonEl = do_QueryInterface(possibleButtonEl);
    1759             :             }
    1760             :           }
    1761           0 :           nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
    1762           0 :           return Relation(mDoc, relatedContent);
    1763             :         }
    1764             :       }
    1765           0 :       return Relation();
    1766             :     }
    1767             : 
    1768             :     case RelationType::CONTAINING_DOCUMENT:
    1769           0 :       return Relation(mDoc);
    1770             : 
    1771             :     case RelationType::CONTAINING_TAB_PANE: {
    1772             :       nsCOMPtr<nsIDocShell> docShell =
    1773           0 :         nsCoreUtils::GetDocShellFor(GetNode());
    1774           0 :       if (docShell) {
    1775             :         // Walk up the parent chain without crossing the boundary at which item
    1776             :         // types change, preventing us from walking up out of tab content.
    1777           0 :         nsCOMPtr<nsIDocShellTreeItem> root;
    1778           0 :         docShell->GetSameTypeRootTreeItem(getter_AddRefs(root));
    1779           0 :         if (root) {
    1780             :           // If the item type is typeContent, we assume we are in browser tab
    1781             :           // content. Note, this includes content such as about:addons,
    1782             :           // for consistency.
    1783           0 :           if (root->ItemType() == nsIDocShellTreeItem::typeContent) {
    1784           0 :             return Relation(nsAccUtils::GetDocAccessibleFor(root));
    1785             :           }
    1786             :         }
    1787             :       }
    1788           0 :       return Relation();
    1789             :     }
    1790             : 
    1791             :     case RelationType::CONTAINING_APPLICATION:
    1792           0 :       return Relation(ApplicationAcc());
    1793             : 
    1794             :     case RelationType::DETAILS:
    1795           0 :       return Relation(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_details));
    1796             : 
    1797             :     case RelationType::DETAILS_FOR:
    1798           0 :       return Relation(new RelatedAccIterator(mDoc, mContent, nsGkAtoms::aria_details));
    1799             : 
    1800             :     case RelationType::ERRORMSG:
    1801           0 :       return Relation(new IDRefsIterator(mDoc, mContent, nsGkAtoms::aria_errormessage));
    1802             : 
    1803             :     case RelationType::ERRORMSG_FOR:
    1804           0 :       return Relation(new RelatedAccIterator(mDoc, mContent, nsGkAtoms::aria_errormessage));
    1805             : 
    1806             :     default:
    1807           0 :       return Relation();
    1808             :   }
    1809             : }
    1810             : 
    1811             : void
    1812           0 : Accessible::GetNativeInterface(void** aNativeAccessible)
    1813             : {
    1814           0 : }
    1815             : 
    1816             : void
    1817           0 : Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
    1818             : {
    1819           0 :   class Runnable final : public mozilla::Runnable
    1820             :   {
    1821             :   public:
    1822           0 :     Runnable(Accessible* aAcc, nsIContent* aContent, uint32_t aIdx)
    1823           0 :       : mozilla::Runnable("Runnable")
    1824             :       , mAcc(aAcc)
    1825             :       , mContent(aContent)
    1826           0 :       , mIdx(aIdx)
    1827             :     {
    1828           0 :     }
    1829             : 
    1830           0 :     NS_IMETHOD Run() override
    1831             :     {
    1832           0 :       if (mAcc)
    1833           0 :         mAcc->DispatchClickEvent(mContent, mIdx);
    1834             : 
    1835           0 :       return NS_OK;
    1836             :     }
    1837             : 
    1838             :     void Revoke()
    1839             :     {
    1840             :       mAcc = nullptr;
    1841             :       mContent = nullptr;
    1842             :     }
    1843             : 
    1844             :   private:
    1845             :     RefPtr<Accessible> mAcc;
    1846             :     nsCOMPtr<nsIContent> mContent;
    1847             :     uint32_t mIdx;
    1848             :   };
    1849             : 
    1850           0 :   nsIContent* content = aContent ? aContent : mContent.get();
    1851           0 :   nsCOMPtr<nsIRunnable> runnable = new Runnable(this, content, aActionIndex);
    1852           0 :   NS_DispatchToMainThread(runnable);
    1853           0 : }
    1854             : 
    1855             : void
    1856           0 : Accessible::DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex)
    1857             : {
    1858           0 :   if (IsDefunct())
    1859           0 :     return;
    1860             : 
    1861           0 :   nsCOMPtr<nsIPresShell> presShell = mDoc->PresShell();
    1862             : 
    1863             :   // Scroll into view.
    1864           0 :   presShell->ScrollContentIntoView(aContent,
    1865             :                                    nsIPresShell::ScrollAxis(),
    1866             :                                    nsIPresShell::ScrollAxis(),
    1867           0 :                                    nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    1868             : 
    1869           0 :   AutoWeakFrame frame = aContent->GetPrimaryFrame();
    1870           0 :   if (!frame)
    1871           0 :     return;
    1872             : 
    1873             :   // Compute x and y coordinates.
    1874           0 :   nsPoint point;
    1875           0 :   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget(point);
    1876           0 :   if (!widget)
    1877           0 :     return;
    1878             : 
    1879           0 :   nsSize size = frame->GetSize();
    1880             : 
    1881           0 :   RefPtr<nsPresContext> presContext = presShell->GetPresContext();
    1882           0 :   int32_t x = presContext->AppUnitsToDevPixels(point.x + size.width / 2);
    1883           0 :   int32_t y = presContext->AppUnitsToDevPixels(point.y + size.height / 2);
    1884             : 
    1885             :   // Simulate a touch interaction by dispatching touch events with mouse events.
    1886           0 :   nsCoreUtils::DispatchTouchEvent(eTouchStart, x, y, aContent, frame,
    1887           0 :                                   presShell, widget);
    1888           0 :   nsCoreUtils::DispatchMouseEvent(eMouseDown, x, y, aContent, frame,
    1889           0 :                                   presShell, widget);
    1890           0 :   nsCoreUtils::DispatchTouchEvent(eTouchEnd, x, y, aContent, frame,
    1891           0 :                                   presShell, widget);
    1892           0 :   nsCoreUtils::DispatchMouseEvent(eMouseUp, x, y, aContent, frame,
    1893           0 :                                   presShell, widget);
    1894             : }
    1895             : 
    1896             : void
    1897           0 : Accessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY)
    1898             : {
    1899           0 :   nsIFrame* frame = GetFrame();
    1900           0 :   if (!frame)
    1901           0 :     return;
    1902             : 
    1903             :   nsIntPoint coords =
    1904           0 :     nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordinateType, this);
    1905             : 
    1906           0 :   nsIFrame* parentFrame = frame;
    1907           0 :   while ((parentFrame = parentFrame->GetParent()))
    1908           0 :     nsCoreUtils::ScrollFrameToPoint(parentFrame, frame, coords);
    1909             : }
    1910             : 
    1911             : void
    1912           0 : Accessible::AppendTextTo(nsAString& aText, uint32_t aStartOffset,
    1913             :                          uint32_t aLength)
    1914             : {
    1915             :   // Return text representation of non-text accessible within hypertext
    1916             :   // accessible. Text accessible overrides this method to return enclosed text.
    1917           0 :   if (aStartOffset != 0 || aLength == 0)
    1918           0 :     return;
    1919             : 
    1920           0 :   nsIFrame *frame = GetFrame();
    1921           0 :   if (!frame)
    1922           0 :     return;
    1923             : 
    1924           0 :   NS_ASSERTION(mParent,
    1925             :                "Called on accessible unbound from tree. Result can be wrong.");
    1926             : 
    1927           0 :   if (frame->IsBrFrame()) {
    1928           0 :     aText += kForcedNewLineChar;
    1929           0 :   } else if (mParent && nsAccUtils::MustPrune(mParent)) {
    1930             :     // Expose the embedded object accessible as imaginary embedded object
    1931             :     // character if its parent hypertext accessible doesn't expose children to
    1932             :     // AT.
    1933           0 :     aText += kImaginaryEmbeddedObjectChar;
    1934             :   } else {
    1935           0 :     aText += kEmbeddedObjectChar;
    1936             :   }
    1937             : }
    1938             : 
    1939             : void
    1940           0 : Accessible::Shutdown()
    1941             : {
    1942             :   // Mark the accessible as defunct, invalidate the child count and pointers to
    1943             :   // other accessibles, also make sure none of its children point to this parent
    1944           0 :   mStateFlags |= eIsDefunct;
    1945             : 
    1946           0 :   int32_t childCount = mChildren.Length();
    1947           0 :   for (int32_t childIdx = 0; childIdx < childCount; childIdx++) {
    1948           0 :     mChildren.ElementAt(childIdx)->UnbindFromParent();
    1949             :   }
    1950           0 :   mChildren.Clear();
    1951             : 
    1952           0 :   mEmbeddedObjCollector = nullptr;
    1953             : 
    1954           0 :   if (mParent)
    1955           0 :     mParent->RemoveChild(this);
    1956             : 
    1957           0 :   mContent = nullptr;
    1958           0 :   mDoc = nullptr;
    1959           0 :   if (SelectionMgr() && SelectionMgr()->AccessibleWithCaret(nullptr) == this)
    1960           0 :     SelectionMgr()->ResetCaretOffset();
    1961           0 : }
    1962             : 
    1963             : // Accessible protected
    1964             : void
    1965           0 : Accessible::ARIAName(nsString& aName)
    1966             : {
    1967             :   // aria-labelledby now takes precedence over aria-label
    1968             :   nsresult rv = nsTextEquivUtils::
    1969           0 :     GetTextEquivFromIDRefs(this, nsGkAtoms::aria_labelledby, aName);
    1970           0 :   if (NS_SUCCEEDED(rv)) {
    1971           0 :     aName.CompressWhitespace();
    1972             :   }
    1973             : 
    1974           0 :   if (aName.IsEmpty() &&
    1975           0 :       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_label, aName)) {
    1976           0 :     aName.CompressWhitespace();
    1977             :   }
    1978           0 : }
    1979             : 
    1980             : // Accessible protected
    1981             : ENameValueFlag
    1982           0 : Accessible::NativeName(nsString& aName)
    1983             : {
    1984           0 :   if (mContent->IsHTMLElement()) {
    1985           0 :     Accessible* label = nullptr;
    1986           0 :     HTMLLabelIterator iter(Document(), this);
    1987           0 :     while ((label = iter.Next())) {
    1988           0 :       nsTextEquivUtils::AppendTextEquivFromContent(this, label->GetContent(),
    1989           0 :                                                    &aName);
    1990           0 :       aName.CompressWhitespace();
    1991             :     }
    1992             : 
    1993           0 :     if (!aName.IsEmpty())
    1994           0 :       return eNameOK;
    1995             : 
    1996           0 :     nsTextEquivUtils::GetNameFromSubtree(this, aName);
    1997           0 :     return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
    1998             :   }
    1999             : 
    2000           0 :   if (mContent->IsXULElement()) {
    2001           0 :     XULElmName(mDoc, mContent, aName);
    2002           0 :     if (!aName.IsEmpty())
    2003           0 :       return eNameOK;
    2004             : 
    2005           0 :     nsTextEquivUtils::GetNameFromSubtree(this, aName);
    2006           0 :     return aName.IsEmpty() ? eNameOK : eNameFromSubtree;
    2007             :   }
    2008             : 
    2009           0 :   if (mContent->IsSVGElement()) {
    2010             :     // If user agents need to choose among multiple ‘desc’ or ‘title’ elements
    2011             :     // for processing, the user agent shall choose the first one.
    2012           0 :     for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
    2013           0 :          childElm = childElm->GetNextSibling()) {
    2014           0 :       if (childElm->IsSVGElement(nsGkAtoms::title)) {
    2015           0 :         nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName);
    2016           0 :         return eNameOK;
    2017             :       }
    2018             :     }
    2019             :   }
    2020             : 
    2021           0 :   return eNameOK;
    2022             : }
    2023             : 
    2024             : // Accessible protected
    2025             : void
    2026           0 : Accessible::NativeDescription(nsString& aDescription)
    2027             : {
    2028           0 :   bool isXUL = mContent->IsXULElement();
    2029           0 :   if (isXUL) {
    2030             :     // Try XUL <description control="[id]">description text</description>
    2031           0 :     XULDescriptionIterator iter(Document(), mContent);
    2032           0 :     Accessible* descr = nullptr;
    2033           0 :     while ((descr = iter.Next())) {
    2034           0 :       nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(),
    2035           0 :                                                    &aDescription);
    2036             :     }
    2037             :   }
    2038           0 : }
    2039             : 
    2040             : // Accessible protected
    2041             : void
    2042           0 : Accessible::BindToParent(Accessible* aParent, uint32_t aIndexInParent)
    2043             : {
    2044           0 :   MOZ_ASSERT(aParent, "This method isn't used to set null parent");
    2045           0 :   MOZ_ASSERT(!mParent, "The child was expected to be moved");
    2046             : 
    2047             : #ifdef A11Y_LOG
    2048           0 :   if (mParent) {
    2049           0 :     logging::TreeInfo("BindToParent: stealing accessible", 0,
    2050             :                       "old parent", mParent,
    2051             :                       "new parent", aParent,
    2052           0 :                       "child", this, nullptr);
    2053             :   }
    2054             : #endif
    2055             : 
    2056           0 :   mParent = aParent;
    2057           0 :   mIndexInParent = aIndexInParent;
    2058             : 
    2059             :   // Note: this is currently only used for richlistitems and their children.
    2060           0 :   if (mParent->HasNameDependentParent() || mParent->IsXULListItem())
    2061           0 :     mContextFlags |= eHasNameDependentParent;
    2062             :   else
    2063           0 :     mContextFlags &= ~eHasNameDependentParent;
    2064             : 
    2065           0 :   if (mParent->IsARIAHidden() || aria::HasDefinedARIAHidden(mContent))
    2066           0 :     SetARIAHidden(true);
    2067             : 
    2068           0 :   mContextFlags |=
    2069           0 :     static_cast<uint32_t>((mParent->IsAlert() ||
    2070           0 :                            mParent->IsInsideAlert())) & eInsideAlert;
    2071           0 : }
    2072             : 
    2073             : // Accessible protected
    2074             : void
    2075           0 : Accessible::UnbindFromParent()
    2076             : {
    2077           0 :   mParent = nullptr;
    2078           0 :   mIndexInParent = -1;
    2079           0 :   mInt.mIndexOfEmbeddedChild = -1;
    2080           0 :   if (IsProxy())
    2081           0 :     MOZ_CRASH("this should never be called on proxy wrappers");
    2082             : 
    2083           0 :   delete mBits.groupInfo;
    2084           0 :   mBits.groupInfo = nullptr;
    2085           0 :   mContextFlags &= ~eHasNameDependentParent & ~eInsideAlert;
    2086           0 : }
    2087             : 
    2088             : ////////////////////////////////////////////////////////////////////////////////
    2089             : // Accessible public methods
    2090             : 
    2091             : RootAccessible*
    2092           0 : Accessible::RootAccessible() const
    2093             : {
    2094           0 :   nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(GetNode());
    2095           0 :   NS_ASSERTION(docShell, "No docshell for mContent");
    2096           0 :   if (!docShell) {
    2097           0 :     return nullptr;
    2098             :   }
    2099             : 
    2100           0 :   nsCOMPtr<nsIDocShellTreeItem> root;
    2101           0 :   docShell->GetRootTreeItem(getter_AddRefs(root));
    2102           0 :   NS_ASSERTION(root, "No root content tree item");
    2103           0 :   if (!root) {
    2104           0 :     return nullptr;
    2105             :   }
    2106             : 
    2107           0 :   DocAccessible* docAcc = nsAccUtils::GetDocAccessibleFor(root);
    2108           0 :   return docAcc ? docAcc->AsRoot() : nullptr;
    2109             : }
    2110             : 
    2111             : nsIFrame*
    2112           0 : Accessible::GetFrame() const
    2113             : {
    2114           0 :   return mContent ? mContent->GetPrimaryFrame() : nullptr;
    2115             : }
    2116             : 
    2117             : nsINode*
    2118           0 : Accessible::GetNode() const
    2119             : {
    2120           0 :   return mContent;
    2121             : }
    2122             : 
    2123             : void
    2124           0 : Accessible::Language(nsAString& aLanguage)
    2125             : {
    2126           0 :   aLanguage.Truncate();
    2127             : 
    2128           0 :   if (!mDoc)
    2129           0 :     return;
    2130             : 
    2131           0 :   nsCoreUtils::GetLanguageFor(mContent, nullptr, aLanguage);
    2132           0 :   if (aLanguage.IsEmpty()) { // Nothing found, so use document's language
    2133           0 :     mDoc->DocumentNode()->GetHeaderData(nsGkAtoms::headerContentLanguage,
    2134           0 :                                         aLanguage);
    2135             :   }
    2136             : }
    2137             : 
    2138             : bool
    2139           0 : Accessible::InsertChildAt(uint32_t aIndex, Accessible* aChild)
    2140             : {
    2141           0 :   if (!aChild)
    2142           0 :     return false;
    2143             : 
    2144           0 :   if (aIndex == mChildren.Length()) {
    2145           0 :     if (!mChildren.AppendElement(aChild))
    2146           0 :       return false;
    2147             : 
    2148             :   } else {
    2149           0 :     if (!mChildren.InsertElementAt(aIndex, aChild))
    2150           0 :       return false;
    2151             : 
    2152           0 :     MOZ_ASSERT(mStateFlags & eKidsMutating, "Illicit children change");
    2153             : 
    2154           0 :     for (uint32_t idx = aIndex + 1; idx < mChildren.Length(); idx++) {
    2155           0 :       mChildren[idx]->mIndexInParent = idx;
    2156             :     }
    2157             :   }
    2158             : 
    2159           0 :   if (aChild->IsText()) {
    2160           0 :     mStateFlags |= eHasTextKids;
    2161             :   }
    2162             : 
    2163           0 :   aChild->BindToParent(this, aIndex);
    2164           0 :   return true;
    2165             : }
    2166             : 
    2167             : bool
    2168           0 : Accessible::RemoveChild(Accessible* aChild)
    2169             : {
    2170           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
    2171           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mParent, "No parent");
    2172           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "Wrong parent");
    2173           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
    2174           0 :   MOZ_DIAGNOSTIC_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() ||
    2175             :                         aChild->IsDoc() || IsApplication(),
    2176             :                         "Illicit children change");
    2177             : 
    2178           0 :   int32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
    2179           0 :   if (mChildren.SafeElementAt(index) != aChild) {
    2180           0 :     MOZ_ASSERT_UNREACHABLE("A wrong child index");
    2181             :     index = mChildren.IndexOf(aChild);
    2182             :     if (index == -1) {
    2183             :       MOZ_ASSERT_UNREACHABLE("No child was found");
    2184             :       return false;
    2185             :     }
    2186             :   }
    2187             : 
    2188           0 :   aChild->UnbindFromParent();
    2189           0 :   mChildren.RemoveElementAt(index);
    2190             : 
    2191           0 :   for (uint32_t idx = index; idx < mChildren.Length(); idx++) {
    2192           0 :     mChildren[idx]->mIndexInParent = idx;
    2193             :   }
    2194             : 
    2195           0 :   return true;
    2196             : }
    2197             : 
    2198             : void
    2199           0 : Accessible::MoveChild(uint32_t aNewIndex, Accessible* aChild)
    2200             : {
    2201           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild, "No child was given");
    2202           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "A child from different subtree was given");
    2203           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
    2204           0 :   MOZ_DIAGNOSTIC_ASSERT(aChild->mParent->GetChildAt(aChild->mIndexInParent) == aChild, "Wrong index in parent");
    2205           0 :   MOZ_DIAGNOSTIC_ASSERT(static_cast<uint32_t>(aChild->mIndexInParent) != aNewIndex,
    2206             :              "No move, same index");
    2207           0 :   MOZ_DIAGNOSTIC_ASSERT(aNewIndex <= mChildren.Length(), "Wrong new index was given");
    2208             : 
    2209           0 :   RefPtr<AccHideEvent> hideEvent = new AccHideEvent(aChild, false);
    2210           0 :   if (mDoc->Controller()->QueueMutationEvent(hideEvent)) {
    2211           0 :     aChild->SetHideEventTarget(true);
    2212             :   }
    2213             : 
    2214           0 :   mEmbeddedObjCollector = nullptr;
    2215           0 :   mChildren.RemoveElementAt(aChild->mIndexInParent);
    2216             : 
    2217           0 :   uint32_t startIdx = aNewIndex, endIdx = aChild->mIndexInParent;
    2218             : 
    2219             :   // If the child is moved after its current position.
    2220           0 :   if (static_cast<uint32_t>(aChild->mIndexInParent) < aNewIndex) {
    2221           0 :     startIdx = aChild->mIndexInParent;
    2222           0 :     if (aNewIndex == mChildren.Length() + 1) {
    2223             :       // The child is moved to the end.
    2224           0 :       mChildren.AppendElement(aChild);
    2225           0 :       endIdx = mChildren.Length() - 1;
    2226             :     }
    2227             :     else {
    2228           0 :       mChildren.InsertElementAt(aNewIndex - 1, aChild);
    2229           0 :       endIdx = aNewIndex;
    2230             :     }
    2231             :   }
    2232             :   else {
    2233             :     // The child is moved prior its current position.
    2234           0 :     mChildren.InsertElementAt(aNewIndex, aChild);
    2235             :   }
    2236             : 
    2237           0 :   for (uint32_t idx = startIdx; idx <= endIdx; idx++) {
    2238           0 :     mChildren[idx]->mIndexInParent = idx;
    2239           0 :     mChildren[idx]->mStateFlags |= eGroupInfoDirty;
    2240           0 :     mChildren[idx]->mInt.mIndexOfEmbeddedChild = -1;
    2241             :   }
    2242             : 
    2243           0 :   RefPtr<AccShowEvent> showEvent = new AccShowEvent(aChild);
    2244           0 :   DebugOnly<bool> added = mDoc->Controller()->QueueMutationEvent(showEvent);
    2245           0 :   MOZ_ASSERT(added);
    2246           0 :   aChild->SetShowEventTarget(true);
    2247           0 : }
    2248             : 
    2249             : Accessible*
    2250           0 : Accessible::GetChildAt(uint32_t aIndex) const
    2251             : {
    2252           0 :   Accessible* child = mChildren.SafeElementAt(aIndex, nullptr);
    2253           0 :   if (!child)
    2254           0 :     return nullptr;
    2255             : 
    2256             : #ifdef DEBUG
    2257           0 :   Accessible* realParent = child->mParent;
    2258           0 :   NS_ASSERTION(!realParent || realParent == this,
    2259             :                "Two accessibles have the same first child accessible!");
    2260             : #endif
    2261             : 
    2262           0 :   return child;
    2263             : }
    2264             : 
    2265             : uint32_t
    2266           0 : Accessible::ChildCount() const
    2267             : {
    2268           0 :   return mChildren.Length();
    2269             : }
    2270             : 
    2271             : int32_t
    2272           0 : Accessible::IndexInParent() const
    2273             : {
    2274           0 :   return mIndexInParent;
    2275             : }
    2276             : 
    2277             : uint32_t
    2278           0 : Accessible::EmbeddedChildCount()
    2279             : {
    2280           0 :   if (mStateFlags & eHasTextKids) {
    2281           0 :     if (!mEmbeddedObjCollector)
    2282           0 :       mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
    2283           0 :     return mEmbeddedObjCollector->Count();
    2284             :   }
    2285             : 
    2286           0 :   return ChildCount();
    2287             : }
    2288             : 
    2289             : Accessible*
    2290           0 : Accessible::GetEmbeddedChildAt(uint32_t aIndex)
    2291             : {
    2292           0 :   if (mStateFlags & eHasTextKids) {
    2293           0 :     if (!mEmbeddedObjCollector)
    2294           0 :       mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
    2295           0 :     return mEmbeddedObjCollector.get() ?
    2296           0 :       mEmbeddedObjCollector->GetAccessibleAt(aIndex) : nullptr;
    2297             :   }
    2298             : 
    2299           0 :   return GetChildAt(aIndex);
    2300             : }
    2301             : 
    2302             : int32_t
    2303           0 : Accessible::GetIndexOfEmbeddedChild(Accessible* aChild)
    2304             : {
    2305           0 :   if (mStateFlags & eHasTextKids) {
    2306           0 :     if (!mEmbeddedObjCollector)
    2307           0 :       mEmbeddedObjCollector.reset(new EmbeddedObjCollector(this));
    2308           0 :     return mEmbeddedObjCollector.get() ?
    2309           0 :       mEmbeddedObjCollector->GetIndexAt(aChild) : -1;
    2310             :   }
    2311             : 
    2312           0 :   return GetIndexOf(aChild);
    2313             : }
    2314             : 
    2315             : ////////////////////////////////////////////////////////////////////////////////
    2316             : // HyperLinkAccessible methods
    2317             : 
    2318             : bool
    2319           0 : Accessible::IsLink()
    2320             : {
    2321             :   // Every embedded accessible within hypertext accessible implements
    2322             :   // hyperlink interface.
    2323           0 :   return mParent && mParent->IsHyperText() && !IsText();
    2324             : }
    2325             : 
    2326             : uint32_t
    2327           0 : Accessible::StartOffset()
    2328             : {
    2329           0 :   NS_PRECONDITION(IsLink(), "StartOffset is called not on hyper link!");
    2330             : 
    2331           0 :   HyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nullptr;
    2332           0 :   return hyperText ? hyperText->GetChildOffset(this) : 0;
    2333             : }
    2334             : 
    2335             : uint32_t
    2336           0 : Accessible::EndOffset()
    2337             : {
    2338           0 :   NS_PRECONDITION(IsLink(), "EndOffset is called on not hyper link!");
    2339             : 
    2340           0 :   HyperTextAccessible* hyperText = mParent ? mParent->AsHyperText() : nullptr;
    2341           0 :   return hyperText ? (hyperText->GetChildOffset(this) + 1) : 0;
    2342             : }
    2343             : 
    2344             : uint32_t
    2345           0 : Accessible::AnchorCount()
    2346             : {
    2347           0 :   NS_PRECONDITION(IsLink(), "AnchorCount is called on not hyper link!");
    2348           0 :   return 1;
    2349             : }
    2350             : 
    2351             : Accessible*
    2352           0 : Accessible::AnchorAt(uint32_t aAnchorIndex)
    2353             : {
    2354           0 :   NS_PRECONDITION(IsLink(), "GetAnchor is called on not hyper link!");
    2355           0 :   return aAnchorIndex == 0 ? this : nullptr;
    2356             : }
    2357             : 
    2358             : already_AddRefed<nsIURI>
    2359           0 : Accessible::AnchorURIAt(uint32_t aAnchorIndex)
    2360             : {
    2361           0 :   NS_PRECONDITION(IsLink(), "AnchorURIAt is called on not hyper link!");
    2362           0 :   return nullptr;
    2363             : }
    2364             : 
    2365             : void
    2366           0 : Accessible::ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
    2367             :                         bool aIsBefore) const
    2368             : {
    2369           0 :   if (IsHyperText()) {
    2370           0 :     *aContainer = const_cast<Accessible*>(this)->AsHyperText();
    2371           0 :     *aOffset = aIsBefore ? 0 : (*aContainer)->CharacterCount();
    2372           0 :     return;
    2373             :   }
    2374             : 
    2375           0 :   const Accessible* child = nullptr;
    2376           0 :   const Accessible* parent = this;
    2377           0 :   do {
    2378           0 :     child = parent;
    2379           0 :     parent = parent->Parent();
    2380           0 :   } while (parent && !parent->IsHyperText());
    2381             : 
    2382           0 :   if (parent) {
    2383           0 :     *aContainer = const_cast<Accessible*>(parent)->AsHyperText();
    2384           0 :     *aOffset = (*aContainer)->GetChildOffset(
    2385           0 :       child->IndexInParent() + static_cast<int32_t>(!aIsBefore));
    2386             :   }
    2387             : }
    2388             : 
    2389             : 
    2390             : ////////////////////////////////////////////////////////////////////////////////
    2391             : // SelectAccessible
    2392             : 
    2393             : void
    2394           0 : Accessible::SelectedItems(nsTArray<Accessible*>* aItems)
    2395             : {
    2396           0 :   AccIterator iter(this, filters::GetSelected);
    2397           0 :   Accessible* selected = nullptr;
    2398           0 :   while ((selected = iter.Next()))
    2399           0 :     aItems->AppendElement(selected);
    2400           0 : }
    2401             : 
    2402             : uint32_t
    2403           0 : Accessible::SelectedItemCount()
    2404             : {
    2405           0 :   uint32_t count = 0;
    2406           0 :   AccIterator iter(this, filters::GetSelected);
    2407           0 :   Accessible* selected = nullptr;
    2408           0 :   while ((selected = iter.Next()))
    2409           0 :     ++count;
    2410             : 
    2411           0 :   return count;
    2412             : }
    2413             : 
    2414             : Accessible*
    2415           0 : Accessible::GetSelectedItem(uint32_t aIndex)
    2416             : {
    2417           0 :   AccIterator iter(this, filters::GetSelected);
    2418           0 :   Accessible* selected = nullptr;
    2419             : 
    2420           0 :   uint32_t index = 0;
    2421           0 :   while ((selected = iter.Next()) && index < aIndex)
    2422           0 :     index++;
    2423             : 
    2424           0 :   return selected;
    2425             : }
    2426             : 
    2427             : bool
    2428           0 : Accessible::IsItemSelected(uint32_t aIndex)
    2429             : {
    2430           0 :   uint32_t index = 0;
    2431           0 :   AccIterator iter(this, filters::GetSelectable);
    2432           0 :   Accessible* selected = nullptr;
    2433           0 :   while ((selected = iter.Next()) && index < aIndex)
    2434           0 :     index++;
    2435             : 
    2436           0 :   return selected &&
    2437           0 :     selected->State() & states::SELECTED;
    2438             : }
    2439             : 
    2440             : bool
    2441           0 : Accessible::AddItemToSelection(uint32_t aIndex)
    2442             : {
    2443           0 :   uint32_t index = 0;
    2444           0 :   AccIterator iter(this, filters::GetSelectable);
    2445           0 :   Accessible* selected = nullptr;
    2446           0 :   while ((selected = iter.Next()) && index < aIndex)
    2447           0 :     index++;
    2448             : 
    2449           0 :   if (selected)
    2450           0 :     selected->SetSelected(true);
    2451             : 
    2452           0 :   return static_cast<bool>(selected);
    2453             : }
    2454             : 
    2455             : bool
    2456           0 : Accessible::RemoveItemFromSelection(uint32_t aIndex)
    2457             : {
    2458           0 :   uint32_t index = 0;
    2459           0 :   AccIterator iter(this, filters::GetSelectable);
    2460           0 :   Accessible* selected = nullptr;
    2461           0 :   while ((selected = iter.Next()) && index < aIndex)
    2462           0 :     index++;
    2463             : 
    2464           0 :   if (selected)
    2465           0 :     selected->SetSelected(false);
    2466             : 
    2467           0 :   return static_cast<bool>(selected);
    2468             : }
    2469             : 
    2470             : bool
    2471           0 : Accessible::SelectAll()
    2472             : {
    2473           0 :   bool success = false;
    2474           0 :   Accessible* selectable = nullptr;
    2475             : 
    2476           0 :   AccIterator iter(this, filters::GetSelectable);
    2477           0 :   while((selectable = iter.Next())) {
    2478           0 :     success = true;
    2479           0 :     selectable->SetSelected(true);
    2480             :   }
    2481           0 :   return success;
    2482             : }
    2483             : 
    2484             : bool
    2485           0 : Accessible::UnselectAll()
    2486             : {
    2487           0 :   bool success = false;
    2488           0 :   Accessible* selected = nullptr;
    2489             : 
    2490           0 :   AccIterator iter(this, filters::GetSelected);
    2491           0 :   while ((selected = iter.Next())) {
    2492           0 :     success = true;
    2493           0 :     selected->SetSelected(false);
    2494             :   }
    2495           0 :   return success;
    2496             : }
    2497             : 
    2498             : ////////////////////////////////////////////////////////////////////////////////
    2499             : // Widgets
    2500             : 
    2501             : bool
    2502           0 : Accessible::IsWidget() const
    2503             : {
    2504           0 :   return false;
    2505             : }
    2506             : 
    2507             : bool
    2508           0 : Accessible::IsActiveWidget() const
    2509             : {
    2510           0 :   if (FocusMgr()->HasDOMFocus(mContent))
    2511           0 :     return true;
    2512             : 
    2513             :   // If text entry of combobox widget has a focus then the combobox widget is
    2514             :   // active.
    2515           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    2516           0 :   if (roleMapEntry && roleMapEntry->Is(nsGkAtoms::combobox)) {
    2517           0 :     uint32_t childCount = ChildCount();
    2518           0 :     for (uint32_t idx = 0; idx < childCount; idx++) {
    2519           0 :       Accessible* child = mChildren.ElementAt(idx);
    2520           0 :       if (child->Role() == roles::ENTRY)
    2521           0 :         return FocusMgr()->HasDOMFocus(child->GetContent());
    2522             :     }
    2523             :   }
    2524             : 
    2525           0 :   return false;
    2526             : }
    2527             : 
    2528             : bool
    2529           0 : Accessible::AreItemsOperable() const
    2530             : {
    2531           0 :   return HasOwnContent() &&
    2532           0 :     mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant);
    2533             : }
    2534             : 
    2535             : Accessible*
    2536           0 : Accessible::CurrentItem()
    2537             : {
    2538             :   // Check for aria-activedescendant, which changes which element has focus.
    2539             :   // For activedescendant, the ARIA spec does not require that the user agent
    2540             :   // checks whether pointed node is actually a DOM descendant of the element
    2541             :   // with the aria-activedescendant attribute.
    2542           0 :   nsAutoString id;
    2543           0 :   if (HasOwnContent() &&
    2544           0 :       mContent->GetAttr(kNameSpaceID_None,
    2545             :                         nsGkAtoms::aria_activedescendant, id)) {
    2546           0 :     nsIDocument* DOMDoc = mContent->OwnerDoc();
    2547           0 :     dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
    2548           0 :     if (activeDescendantElm) {
    2549           0 :       DocAccessible* document = Document();
    2550           0 :       if (document)
    2551           0 :         return document->GetAccessible(activeDescendantElm);
    2552             :     }
    2553             :   }
    2554           0 :   return nullptr;
    2555             : }
    2556             : 
    2557             : void
    2558           0 : Accessible::SetCurrentItem(Accessible* aItem)
    2559             : {
    2560           0 :   nsIAtom* id = aItem->GetContent()->GetID();
    2561           0 :   if (id) {
    2562           0 :     nsAutoString idStr;
    2563           0 :     id->ToString(idStr);
    2564           0 :     mContent->SetAttr(kNameSpaceID_None,
    2565           0 :                       nsGkAtoms::aria_activedescendant, idStr, true);
    2566             :   }
    2567           0 : }
    2568             : 
    2569             : Accessible*
    2570           0 : Accessible::ContainerWidget() const
    2571             : {
    2572           0 :   if (HasARIARole() && mContent->HasID()) {
    2573           0 :     for (Accessible* parent = Parent(); parent; parent = parent->Parent()) {
    2574           0 :       nsIContent* parentContent = parent->GetContent();
    2575           0 :       if (parentContent &&
    2576           0 :         parentContent->HasAttr(kNameSpaceID_None,
    2577             :                                nsGkAtoms::aria_activedescendant)) {
    2578           0 :         return parent;
    2579             :       }
    2580             : 
    2581             :       // Don't cross DOM document boundaries.
    2582           0 :       if (parent->IsDoc())
    2583           0 :         break;
    2584             :     }
    2585             :   }
    2586           0 :   return nullptr;
    2587             : }
    2588             : 
    2589             : void
    2590           0 : Accessible::SetARIAHidden(bool aIsDefined)
    2591             : {
    2592           0 :   if (aIsDefined)
    2593           0 :     mContextFlags |= eARIAHidden;
    2594             :   else
    2595           0 :     mContextFlags &= ~eARIAHidden;
    2596             : 
    2597           0 :   uint32_t length = mChildren.Length();
    2598           0 :   for (uint32_t i = 0; i < length; i++) {
    2599           0 :     mChildren[i]->SetARIAHidden(aIsDefined);
    2600             :   }
    2601           0 : }
    2602             : 
    2603             : ////////////////////////////////////////////////////////////////////////////////
    2604             : // Accessible protected methods
    2605             : 
    2606             : void
    2607           0 : Accessible::LastRelease()
    2608             : {
    2609             :   // First cleanup if needed...
    2610           0 :   if (mDoc) {
    2611           0 :     Shutdown();
    2612           0 :     NS_ASSERTION(!mDoc,
    2613             :                  "A Shutdown() impl forgot to call its parent's Shutdown?");
    2614             :   }
    2615             :   // ... then die.
    2616           0 :   delete this;
    2617           0 : }
    2618             : 
    2619             : Accessible*
    2620           0 : Accessible::GetSiblingAtOffset(int32_t aOffset, nsresult* aError) const
    2621             : {
    2622           0 :   if (!mParent || mIndexInParent == -1) {
    2623           0 :     if (aError)
    2624           0 :       *aError = NS_ERROR_UNEXPECTED;
    2625             : 
    2626           0 :     return nullptr;
    2627             :   }
    2628             : 
    2629           0 :   if (aError &&
    2630           0 :       mIndexInParent + aOffset >= static_cast<int32_t>(mParent->ChildCount())) {
    2631           0 :     *aError = NS_OK; // fail peacefully
    2632           0 :     return nullptr;
    2633             :   }
    2634             : 
    2635           0 :   Accessible* child = mParent->GetChildAt(mIndexInParent + aOffset);
    2636           0 :   if (aError && !child)
    2637           0 :     *aError = NS_ERROR_UNEXPECTED;
    2638             : 
    2639           0 :   return child;
    2640             : }
    2641             : 
    2642             : double
    2643           0 : Accessible::AttrNumericValue(nsIAtom* aAttr) const
    2644             : {
    2645           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    2646           0 :   if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
    2647           0 :     return UnspecifiedNaN<double>();
    2648             : 
    2649           0 :   nsAutoString attrValue;
    2650           0 :   if (!mContent->GetAttr(kNameSpaceID_None, aAttr, attrValue))
    2651           0 :     return UnspecifiedNaN<double>();
    2652             : 
    2653           0 :   nsresult error = NS_OK;
    2654           0 :   double value = attrValue.ToDouble(&error);
    2655           0 :   return NS_FAILED(error) ? UnspecifiedNaN<double>() : value;
    2656             : }
    2657             : 
    2658             : uint32_t
    2659           0 : Accessible::GetActionRule() const
    2660             : {
    2661           0 :   if (!HasOwnContent() || (InteractiveState() & states::UNAVAILABLE))
    2662           0 :     return eNoAction;
    2663             : 
    2664             :   // Return "click" action on elements that have an attached popup menu.
    2665           0 :   if (mContent->IsXULElement())
    2666           0 :     if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popup))
    2667           0 :       return eClickAction;
    2668             : 
    2669             :   // Has registered 'click' event handler.
    2670           0 :   bool isOnclick = nsCoreUtils::HasClickListener(mContent);
    2671             : 
    2672           0 :   if (isOnclick)
    2673           0 :     return eClickAction;
    2674             : 
    2675             :   // Get an action based on ARIA role.
    2676           0 :   const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
    2677           0 :   if (roleMapEntry &&
    2678           0 :       roleMapEntry->actionRule != eNoAction)
    2679           0 :     return roleMapEntry->actionRule;
    2680             : 
    2681             :   // Get an action based on ARIA attribute.
    2682           0 :   if (nsAccUtils::HasDefinedARIAToken(mContent,
    2683             :                                       nsGkAtoms::aria_expanded))
    2684           0 :     return eExpandAction;
    2685             : 
    2686           0 :   return eNoAction;
    2687             : }
    2688             : 
    2689             : AccGroupInfo*
    2690           0 : Accessible::GetGroupInfo()
    2691             : {
    2692           0 :   if (IsProxy())
    2693           0 :     MOZ_CRASH("This should never be called on proxy wrappers");
    2694             : 
    2695           0 :   if (mBits.groupInfo){
    2696           0 :     if (HasDirtyGroupInfo()) {
    2697           0 :       mBits.groupInfo->Update();
    2698           0 :       mStateFlags &= ~eGroupInfoDirty;
    2699             :     }
    2700             : 
    2701           0 :     return mBits.groupInfo;
    2702             :   }
    2703             : 
    2704           0 :   mBits.groupInfo = AccGroupInfo::CreateGroupInfo(this);
    2705           0 :   return mBits.groupInfo;
    2706             : }
    2707             : 
    2708             : void
    2709           0 : Accessible::GetPositionAndSizeInternal(int32_t *aPosInSet, int32_t *aSetSize)
    2710             : {
    2711           0 :   AccGroupInfo* groupInfo = GetGroupInfo();
    2712           0 :   if (groupInfo) {
    2713           0 :     *aPosInSet = groupInfo->PosInSet();
    2714           0 :     *aSetSize = groupInfo->SetSize();
    2715             :   }
    2716           0 : }
    2717             : 
    2718             : int32_t
    2719           0 : Accessible::GetLevelInternal()
    2720             : {
    2721           0 :   int32_t level = nsAccUtils::GetDefaultLevel(this);
    2722             : 
    2723           0 :   if (!IsBoundToParent())
    2724           0 :     return level;
    2725             : 
    2726           0 :   roles::Role role = Role();
    2727           0 :   if (role == roles::OUTLINEITEM) {
    2728             :     // Always expose 'level' attribute for 'outlineitem' accessible. The number
    2729             :     // of nested 'grouping' accessibles containing 'outlineitem' accessible is
    2730             :     // its level.
    2731           0 :     level = 1;
    2732             : 
    2733           0 :     Accessible* parent = this;
    2734           0 :     while ((parent = parent->Parent())) {
    2735           0 :       roles::Role parentRole = parent->Role();
    2736             : 
    2737           0 :       if (parentRole == roles::OUTLINE)
    2738           0 :         break;
    2739           0 :       if (parentRole == roles::GROUPING)
    2740           0 :         ++ level;
    2741             : 
    2742             :     }
    2743             : 
    2744           0 :   } else if (role == roles::LISTITEM) {
    2745             :     // Expose 'level' attribute on nested lists. We support two hierarchies:
    2746             :     // a) list -> listitem -> list -> listitem (nested list is a last child
    2747             :     //   of listitem of the parent list);
    2748             :     // b) list -> listitem -> group -> listitem (nested listitems are contained
    2749             :     //   by group that is a last child of the parent listitem).
    2750             : 
    2751             :     // Calculate 'level' attribute based on number of parent listitems.
    2752           0 :     level = 0;
    2753           0 :     Accessible* parent = this;
    2754           0 :     while ((parent = parent->Parent())) {
    2755           0 :       roles::Role parentRole = parent->Role();
    2756             : 
    2757           0 :       if (parentRole == roles::LISTITEM)
    2758           0 :         ++ level;
    2759           0 :       else if (parentRole != roles::LIST && parentRole != roles::GROUPING)
    2760           0 :         break;
    2761             :     }
    2762             : 
    2763           0 :     if (level == 0) {
    2764             :       // If this listitem is on top of nested lists then expose 'level'
    2765             :       // attribute.
    2766           0 :       parent = Parent();
    2767           0 :       uint32_t siblingCount = parent->ChildCount();
    2768           0 :       for (uint32_t siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
    2769           0 :         Accessible* sibling = parent->GetChildAt(siblingIdx);
    2770             : 
    2771           0 :         Accessible* siblingChild = sibling->LastChild();
    2772           0 :         if (siblingChild) {
    2773           0 :           roles::Role lastChildRole = siblingChild->Role();
    2774           0 :           if (lastChildRole == roles::LIST || lastChildRole == roles::GROUPING)
    2775           0 :             return 1;
    2776             :         }
    2777             :       }
    2778             :     } else {
    2779           0 :       ++ level; // level is 1-index based
    2780             :     }
    2781             :   }
    2782             : 
    2783           0 :   return level;
    2784             : }
    2785             : 
    2786             : void
    2787           0 : Accessible::StaticAsserts() const
    2788             : {
    2789             :   static_assert(eLastStateFlag <= (1 << kStateFlagsBits) - 1,
    2790             :                 "Accessible::mStateFlags was oversized by eLastStateFlag!");
    2791             :   static_assert(eLastAccType <= (1 << kTypeBits) - 1,
    2792             :                 "Accessible::mType was oversized by eLastAccType!");
    2793             :   static_assert(eLastContextFlag <= (1 << kContextFlagsBits) - 1,
    2794             :                 "Accessible::mContextFlags was oversized by eLastContextFlag!");
    2795             :   static_assert(eLastAccGenericType <= (1 << kGenericTypesBits) - 1,
    2796             :                 "Accessible::mGenericType was oversized by eLastAccGenericType!");
    2797           0 : }
    2798             : 
    2799             : ////////////////////////////////////////////////////////////////////////////////
    2800             : // KeyBinding class
    2801             : 
    2802             : // static
    2803             : uint32_t
    2804           0 : KeyBinding::AccelModifier()
    2805             : {
    2806           0 :   switch (WidgetInputEvent::AccelModifier()) {
    2807             :     case MODIFIER_ALT:
    2808           0 :       return kAlt;
    2809             :     case MODIFIER_CONTROL:
    2810           0 :       return kControl;
    2811             :     case MODIFIER_META:
    2812           0 :       return kMeta;
    2813             :     case MODIFIER_OS:
    2814           0 :       return kOS;
    2815             :     default:
    2816           0 :       MOZ_CRASH("Handle the new result of WidgetInputEvent::AccelModifier()");
    2817             :       return 0;
    2818             :   }
    2819             : }
    2820             : 
    2821             : void
    2822           0 : KeyBinding::ToPlatformFormat(nsAString& aValue) const
    2823             : {
    2824           0 :   nsCOMPtr<nsIStringBundle> keyStringBundle;
    2825             :   nsCOMPtr<nsIStringBundleService> stringBundleService =
    2826           0 :       mozilla::services::GetStringBundleService();
    2827           0 :   if (stringBundleService)
    2828           0 :     stringBundleService->CreateBundle(
    2829             :       "chrome://global-platform/locale/platformKeys.properties",
    2830           0 :       getter_AddRefs(keyStringBundle));
    2831             : 
    2832           0 :   if (!keyStringBundle)
    2833           0 :     return;
    2834             : 
    2835           0 :   nsAutoString separator;
    2836           0 :   keyStringBundle->GetStringFromName(u"MODIFIER_SEPARATOR",
    2837           0 :                                      getter_Copies(separator));
    2838             : 
    2839           0 :   nsAutoString modifierName;
    2840           0 :   if (mModifierMask & kControl) {
    2841           0 :     keyStringBundle->GetStringFromName(u"VK_CONTROL",
    2842           0 :                                        getter_Copies(modifierName));
    2843             : 
    2844           0 :     aValue.Append(modifierName);
    2845           0 :     aValue.Append(separator);
    2846             :   }
    2847             : 
    2848           0 :   if (mModifierMask & kAlt) {
    2849           0 :     keyStringBundle->GetStringFromName(u"VK_ALT",
    2850           0 :                                        getter_Copies(modifierName));
    2851             : 
    2852           0 :     aValue.Append(modifierName);
    2853           0 :     aValue.Append(separator);
    2854             :   }
    2855             : 
    2856           0 :   if (mModifierMask & kShift) {
    2857           0 :     keyStringBundle->GetStringFromName(u"VK_SHIFT",
    2858           0 :                                        getter_Copies(modifierName));
    2859             : 
    2860           0 :     aValue.Append(modifierName);
    2861           0 :     aValue.Append(separator);
    2862             :   }
    2863             : 
    2864           0 :   if (mModifierMask & kMeta) {
    2865           0 :     keyStringBundle->GetStringFromName(u"VK_META",
    2866           0 :                                        getter_Copies(modifierName));
    2867             : 
    2868           0 :     aValue.Append(modifierName);
    2869           0 :     aValue.Append(separator);
    2870             :   }
    2871             : 
    2872           0 :   aValue.Append(mKey);
    2873             : }
    2874             : 
    2875             : void
    2876           0 : KeyBinding::ToAtkFormat(nsAString& aValue) const
    2877             : {
    2878           0 :   nsAutoString modifierName;
    2879           0 :   if (mModifierMask & kControl)
    2880           0 :     aValue.AppendLiteral("<Control>");
    2881             : 
    2882           0 :   if (mModifierMask & kAlt)
    2883           0 :     aValue.AppendLiteral("<Alt>");
    2884             : 
    2885           0 :   if (mModifierMask & kShift)
    2886           0 :     aValue.AppendLiteral("<Shift>");
    2887             : 
    2888           0 :   if (mModifierMask & kMeta)
    2889           0 :       aValue.AppendLiteral("<Meta>");
    2890             : 
    2891           0 :   aValue.Append(mKey);
    2892           0 : }

Generated by: LCOV version 1.13