1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/html/HTMLSelectAccessible.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,675 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "HTMLSelectAccessible.h" 1.10 + 1.11 +#include "Accessible-inl.h" 1.12 +#include "nsAccessibilityService.h" 1.13 +#include "nsAccUtils.h" 1.14 +#include "DocAccessible.h" 1.15 +#include "nsEventShell.h" 1.16 +#include "nsIAccessibleEvent.h" 1.17 +#include "nsTextEquivUtils.h" 1.18 +#include "Role.h" 1.19 +#include "States.h" 1.20 + 1.21 +#include "nsCOMPtr.h" 1.22 +#include "mozilla/dom/HTMLOptionElement.h" 1.23 +#include "nsIComboboxControlFrame.h" 1.24 +#include "nsIFrame.h" 1.25 +#include "nsIListControlFrame.h" 1.26 + 1.27 +using namespace mozilla::a11y; 1.28 +using namespace mozilla::dom; 1.29 + 1.30 +//////////////////////////////////////////////////////////////////////////////// 1.31 +// HTMLSelectListAccessible 1.32 +//////////////////////////////////////////////////////////////////////////////// 1.33 + 1.34 +HTMLSelectListAccessible:: 1.35 + HTMLSelectListAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.36 + AccessibleWrap(aContent, aDoc) 1.37 +{ 1.38 + mGenericTypes |= eListControl | eSelect; 1.39 +} 1.40 + 1.41 +//////////////////////////////////////////////////////////////////////////////// 1.42 +// HTMLSelectListAccessible: Accessible public 1.43 + 1.44 +uint64_t 1.45 +HTMLSelectListAccessible::NativeState() 1.46 +{ 1.47 + uint64_t state = AccessibleWrap::NativeState(); 1.48 + if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) 1.49 + state |= states::MULTISELECTABLE | states::EXTSELECTABLE; 1.50 + 1.51 + return state; 1.52 +} 1.53 + 1.54 +role 1.55 +HTMLSelectListAccessible::NativeRole() 1.56 +{ 1.57 + return roles::LISTBOX; 1.58 +} 1.59 + 1.60 +//////////////////////////////////////////////////////////////////////////////// 1.61 +// HTMLSelectListAccessible: SelectAccessible 1.62 + 1.63 +bool 1.64 +HTMLSelectListAccessible::SelectAll() 1.65 +{ 1.66 + return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ? 1.67 + AccessibleWrap::SelectAll() : false; 1.68 +} 1.69 + 1.70 +bool 1.71 +HTMLSelectListAccessible::UnselectAll() 1.72 +{ 1.73 + return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple) ? 1.74 + AccessibleWrap::UnselectAll() : false; 1.75 +} 1.76 + 1.77 +//////////////////////////////////////////////////////////////////////////////// 1.78 +// HTMLSelectListAccessible: Widgets 1.79 + 1.80 +bool 1.81 +HTMLSelectListAccessible::IsWidget() const 1.82 +{ 1.83 + return true; 1.84 +} 1.85 + 1.86 +bool 1.87 +HTMLSelectListAccessible::IsActiveWidget() const 1.88 +{ 1.89 + return FocusMgr()->HasDOMFocus(mContent); 1.90 +} 1.91 + 1.92 +bool 1.93 +HTMLSelectListAccessible::AreItemsOperable() const 1.94 +{ 1.95 + return true; 1.96 +} 1.97 + 1.98 +Accessible* 1.99 +HTMLSelectListAccessible::CurrentItem() 1.100 +{ 1.101 + nsIListControlFrame* listControlFrame = do_QueryFrame(GetFrame()); 1.102 + if (listControlFrame) { 1.103 + nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption(); 1.104 + if (activeOptionNode) { 1.105 + DocAccessible* document = Document(); 1.106 + if (document) 1.107 + return document->GetAccessible(activeOptionNode); 1.108 + } 1.109 + } 1.110 + return nullptr; 1.111 +} 1.112 + 1.113 +void 1.114 +HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem) 1.115 +{ 1.116 + aItem->GetContent()->SetAttr(kNameSpaceID_None, 1.117 + nsGkAtoms::selected, NS_LITERAL_STRING("true"), 1.118 + true); 1.119 +} 1.120 + 1.121 +//////////////////////////////////////////////////////////////////////////////// 1.122 +// HTMLSelectListAccessible: Accessible protected 1.123 + 1.124 +void 1.125 +HTMLSelectListAccessible::CacheChildren() 1.126 +{ 1.127 + // Cache accessibles for <optgroup> and <option> DOM decendents as children, 1.128 + // as well as the accessibles for them. Avoid whitespace text nodes. We want 1.129 + // to count all the <optgroup>s and <option>s as children because we want 1.130 + // a flat tree under the Select List. 1.131 + for (nsIContent* childContent = mContent->GetFirstChild(); childContent; 1.132 + childContent = childContent->GetNextSibling()) { 1.133 + if (!childContent->IsHTML()) { 1.134 + continue; 1.135 + } 1.136 + 1.137 + nsIAtom* tag = childContent->Tag(); 1.138 + if (tag == nsGkAtoms::option || 1.139 + tag == nsGkAtoms::optgroup) { 1.140 + 1.141 + // Get an accessible for option or optgroup and cache it. 1.142 + nsRefPtr<Accessible> accessible = 1.143 + GetAccService()->GetOrCreateAccessible(childContent, this); 1.144 + if (accessible) 1.145 + AppendChild(accessible); 1.146 + } 1.147 + } 1.148 +} 1.149 + 1.150 + 1.151 +//////////////////////////////////////////////////////////////////////////////// 1.152 +// HTMLSelectOptionAccessible 1.153 +//////////////////////////////////////////////////////////////////////////////// 1.154 + 1.155 +HTMLSelectOptionAccessible:: 1.156 + HTMLSelectOptionAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.157 + HyperTextAccessibleWrap(aContent, aDoc) 1.158 +{ 1.159 +} 1.160 + 1.161 +//////////////////////////////////////////////////////////////////////////////// 1.162 +// HTMLSelectOptionAccessible: Accessible public 1.163 + 1.164 +role 1.165 +HTMLSelectOptionAccessible::NativeRole() 1.166 +{ 1.167 + if (GetCombobox()) 1.168 + return roles::COMBOBOX_OPTION; 1.169 + 1.170 + return roles::OPTION; 1.171 +} 1.172 + 1.173 +ENameValueFlag 1.174 +HTMLSelectOptionAccessible::NativeName(nsString& aName) 1.175 +{ 1.176 + // CASE #1 -- great majority of the cases 1.177 + // find the label attribute - this is what the W3C says we should use 1.178 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName); 1.179 + if (!aName.IsEmpty()) 1.180 + return eNameOK; 1.181 + 1.182 + // CASE #2 -- no label parameter, get the first child, 1.183 + // use it if it is a text node 1.184 + nsIContent* text = mContent->GetFirstChild(); 1.185 + if (text && text->IsNodeOfType(nsINode::eTEXT)) { 1.186 + nsTextEquivUtils::AppendTextEquivFromTextContent(text, &aName); 1.187 + aName.CompressWhitespace(); 1.188 + return aName.IsEmpty() ? eNameOK : eNameFromSubtree; 1.189 + } 1.190 + 1.191 + return eNameOK; 1.192 +} 1.193 + 1.194 +uint64_t 1.195 +HTMLSelectOptionAccessible::NativeState() 1.196 +{ 1.197 + // As a HTMLSelectOptionAccessible we can have the following states: 1.198 + // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN 1.199 + // Upcall to Accessible, but skip HyperTextAccessible impl 1.200 + // because we don't want EDITABLE or SELECTABLE_TEXT 1.201 + uint64_t state = Accessible::NativeState(); 1.202 + 1.203 + Accessible* select = GetSelect(); 1.204 + if (!select) 1.205 + return state; 1.206 + 1.207 + uint64_t selectState = select->State(); 1.208 + if (selectState & states::INVISIBLE) 1.209 + return state; 1.210 + 1.211 + // Are we selected? 1.212 + HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent); 1.213 + bool selected = option && option->Selected(); 1.214 + if (selected) 1.215 + state |= states::SELECTED; 1.216 + 1.217 + if (selectState & states::OFFSCREEN) { 1.218 + state |= states::OFFSCREEN; 1.219 + } else if (selectState & states::COLLAPSED) { 1.220 + // <select> is COLLAPSED: add OFFSCREEN, if not the currently 1.221 + // visible option 1.222 + if (!selected) { 1.223 + state |= states::OFFSCREEN; 1.224 + state ^= states::INVISIBLE; 1.225 + } else { 1.226 + // Clear offscreen and invisible for currently showing option 1.227 + state &= ~(states::OFFSCREEN | states::INVISIBLE); 1.228 + state |= selectState & states::OPAQUE1; 1.229 + } 1.230 + } else { 1.231 + // XXX list frames are weird, don't rely on Accessible's general 1.232 + // visibility implementation unless they get reimplemented in layout 1.233 + state &= ~states::OFFSCREEN; 1.234 + // <select> is not collapsed: compare bounds to calculate OFFSCREEN 1.235 + Accessible* listAcc = Parent(); 1.236 + if (listAcc) { 1.237 + int32_t optionX, optionY, optionWidth, optionHeight; 1.238 + int32_t listX, listY, listWidth, listHeight; 1.239 + GetBounds(&optionX, &optionY, &optionWidth, &optionHeight); 1.240 + listAcc->GetBounds(&listX, &listY, &listWidth, &listHeight); 1.241 + if (optionY < listY || optionY + optionHeight > listY + listHeight) { 1.242 + state |= states::OFFSCREEN; 1.243 + } 1.244 + } 1.245 + } 1.246 + 1.247 + return state; 1.248 +} 1.249 + 1.250 +uint64_t 1.251 +HTMLSelectOptionAccessible::NativeInteractiveState() const 1.252 +{ 1.253 + return NativelyUnavailable() ? 1.254 + states::UNAVAILABLE : states::FOCUSABLE | states::SELECTABLE; 1.255 +} 1.256 + 1.257 +int32_t 1.258 +HTMLSelectOptionAccessible::GetLevelInternal() 1.259 +{ 1.260 + nsIContent* parentContent = mContent->GetParent(); 1.261 + 1.262 + int32_t level = 1.263 + parentContent->NodeInfo()->Equals(nsGkAtoms::optgroup) ? 2 : 1; 1.264 + 1.265 + if (level == 1 && Role() != roles::HEADING) 1.266 + level = 0; // In a single level list, the level is irrelevant 1.267 + 1.268 + return level; 1.269 +} 1.270 + 1.271 +void 1.272 +HTMLSelectOptionAccessible::GetBoundsRect(nsRect& aTotalBounds, 1.273 + nsIFrame** aBoundingFrame) 1.274 +{ 1.275 + Accessible* combobox = GetCombobox(); 1.276 + if (combobox && (combobox->State() & states::COLLAPSED)) 1.277 + combobox->GetBoundsRect(aTotalBounds, aBoundingFrame); 1.278 + else 1.279 + HyperTextAccessibleWrap::GetBoundsRect(aTotalBounds, aBoundingFrame); 1.280 +} 1.281 + 1.282 +NS_IMETHODIMP 1.283 +HTMLSelectOptionAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.284 +{ 1.285 + if (aIndex == eAction_Select) { 1.286 + aName.AssignLiteral("select"); 1.287 + return NS_OK; 1.288 + } 1.289 + return NS_ERROR_INVALID_ARG; 1.290 +} 1.291 + 1.292 +uint8_t 1.293 +HTMLSelectOptionAccessible::ActionCount() 1.294 +{ 1.295 + return 1; 1.296 +} 1.297 + 1.298 +NS_IMETHODIMP 1.299 +HTMLSelectOptionAccessible::DoAction(uint8_t aIndex) 1.300 +{ 1.301 + if (aIndex != eAction_Select) 1.302 + return NS_ERROR_INVALID_ARG; 1.303 + 1.304 + if (IsDefunct()) 1.305 + return NS_ERROR_FAILURE; 1.306 + 1.307 + DoCommand(); 1.308 + return NS_OK; 1.309 +} 1.310 + 1.311 +NS_IMETHODIMP 1.312 +HTMLSelectOptionAccessible::SetSelected(bool aSelect) 1.313 +{ 1.314 + if (IsDefunct()) 1.315 + return NS_ERROR_FAILURE; 1.316 + 1.317 + HTMLOptionElement* option = HTMLOptionElement::FromContent(mContent); 1.318 + return option ? option->SetSelected(aSelect) : NS_ERROR_FAILURE; 1.319 +} 1.320 + 1.321 +//////////////////////////////////////////////////////////////////////////////// 1.322 +// HTMLSelectOptionAccessible: Widgets 1.323 + 1.324 +Accessible* 1.325 +HTMLSelectOptionAccessible::ContainerWidget() const 1.326 +{ 1.327 + Accessible* parent = Parent(); 1.328 + if (parent && parent->IsHTMLOptGroup()) 1.329 + parent = parent->Parent(); 1.330 + 1.331 + return parent && parent->IsListControl() ? parent : nullptr; 1.332 +} 1.333 + 1.334 +//////////////////////////////////////////////////////////////////////////////// 1.335 +// HTMLSelectOptGroupAccessible 1.336 +//////////////////////////////////////////////////////////////////////////////// 1.337 + 1.338 +role 1.339 +HTMLSelectOptGroupAccessible::NativeRole() 1.340 +{ 1.341 + return roles::GROUPING; 1.342 +} 1.343 + 1.344 +uint64_t 1.345 +HTMLSelectOptGroupAccessible::NativeInteractiveState() const 1.346 +{ 1.347 + return NativelyUnavailable() ? states::UNAVAILABLE : 0; 1.348 +} 1.349 + 1.350 +NS_IMETHODIMP 1.351 +HTMLSelectOptGroupAccessible::DoAction(uint8_t index) 1.352 +{ 1.353 + return NS_ERROR_NOT_IMPLEMENTED; 1.354 +} 1.355 + 1.356 +NS_IMETHODIMP 1.357 +HTMLSelectOptGroupAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.358 +{ 1.359 + return NS_ERROR_NOT_IMPLEMENTED; 1.360 +} 1.361 + 1.362 +uint8_t 1.363 +HTMLSelectOptGroupAccessible::ActionCount() 1.364 +{ 1.365 + return 0; 1.366 +} 1.367 + 1.368 +//////////////////////////////////////////////////////////////////////////////// 1.369 +// HTMLComboboxAccessible 1.370 +//////////////////////////////////////////////////////////////////////////////// 1.371 + 1.372 +HTMLComboboxAccessible:: 1.373 + HTMLComboboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.374 + AccessibleWrap(aContent, aDoc) 1.375 +{ 1.376 + mGenericTypes |= eCombobox; 1.377 +} 1.378 + 1.379 +//////////////////////////////////////////////////////////////////////////////// 1.380 +// HTMLComboboxAccessible: Accessible 1.381 + 1.382 +role 1.383 +HTMLComboboxAccessible::NativeRole() 1.384 +{ 1.385 + return roles::COMBOBOX; 1.386 +} 1.387 + 1.388 +void 1.389 +HTMLComboboxAccessible::InvalidateChildren() 1.390 +{ 1.391 + AccessibleWrap::InvalidateChildren(); 1.392 + 1.393 + if (mListAccessible) 1.394 + mListAccessible->InvalidateChildren(); 1.395 +} 1.396 + 1.397 +void 1.398 +HTMLComboboxAccessible::CacheChildren() 1.399 +{ 1.400 + nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame()); 1.401 + if (!comboFrame) 1.402 + return; 1.403 + 1.404 + nsIFrame* listFrame = comboFrame->GetDropDown(); 1.405 + if (!listFrame) 1.406 + return; 1.407 + 1.408 + if (!mListAccessible) { 1.409 + mListAccessible = 1.410 + new HTMLComboboxListAccessible(mParent, mContent, mDoc); 1.411 + 1.412 + // Initialize and put into cache. 1.413 + Document()->BindToDocument(mListAccessible, nullptr); 1.414 + } 1.415 + 1.416 + if (AppendChild(mListAccessible)) { 1.417 + // Cache combobox option accessibles so that we build complete accessible 1.418 + // tree for combobox. 1.419 + mListAccessible->EnsureChildren(); 1.420 + } 1.421 +} 1.422 + 1.423 +void 1.424 +HTMLComboboxAccessible::Shutdown() 1.425 +{ 1.426 + AccessibleWrap::Shutdown(); 1.427 + 1.428 + if (mListAccessible) { 1.429 + mListAccessible->Shutdown(); 1.430 + mListAccessible = nullptr; 1.431 + } 1.432 +} 1.433 + 1.434 +uint64_t 1.435 +HTMLComboboxAccessible::NativeState() 1.436 +{ 1.437 + // As a HTMLComboboxAccessible we can have the following states: 1.438 + // FOCUSED, FOCUSABLE, HASPOPUP, EXPANDED, COLLAPSED 1.439 + // Get focus status from base class 1.440 + uint64_t state = Accessible::NativeState(); 1.441 + 1.442 + nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame()); 1.443 + if (comboFrame && comboFrame->IsDroppedDown()) 1.444 + state |= states::EXPANDED; 1.445 + else 1.446 + state |= states::COLLAPSED; 1.447 + 1.448 + state |= states::HASPOPUP; 1.449 + return state; 1.450 +} 1.451 + 1.452 +void 1.453 +HTMLComboboxAccessible::Description(nsString& aDescription) 1.454 +{ 1.455 + aDescription.Truncate(); 1.456 + // First check to see if combo box itself has a description, perhaps through 1.457 + // tooltip (title attribute) or via aria-describedby 1.458 + Accessible::Description(aDescription); 1.459 + if (!aDescription.IsEmpty()) 1.460 + return; 1.461 + 1.462 + // Otherwise use description of selected option. 1.463 + Accessible* option = SelectedOption(); 1.464 + if (option) 1.465 + option->Description(aDescription); 1.466 +} 1.467 + 1.468 +void 1.469 +HTMLComboboxAccessible::Value(nsString& aValue) 1.470 +{ 1.471 + // Use accessible name of selected option. 1.472 + Accessible* option = SelectedOption(); 1.473 + if (option) 1.474 + option->Name(aValue); 1.475 +} 1.476 + 1.477 +uint8_t 1.478 +HTMLComboboxAccessible::ActionCount() 1.479 +{ 1.480 + return 1; 1.481 +} 1.482 + 1.483 +NS_IMETHODIMP 1.484 +HTMLComboboxAccessible::DoAction(uint8_t aIndex) 1.485 +{ 1.486 + if (aIndex != eAction_Click) 1.487 + return NS_ERROR_INVALID_ARG; 1.488 + 1.489 + if (IsDefunct()) 1.490 + return NS_ERROR_FAILURE; 1.491 + 1.492 + DoCommand(); 1.493 + return NS_OK; 1.494 +} 1.495 + 1.496 +/** 1.497 + * Our action name is the reverse of our state: 1.498 + * if we are closed -> open is our name. 1.499 + * if we are open -> closed is our name. 1.500 + * Uses the frame to get the state, updated on every click 1.501 + */ 1.502 +NS_IMETHODIMP 1.503 +HTMLComboboxAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.504 +{ 1.505 + if (aIndex != HTMLComboboxAccessible::eAction_Click) { 1.506 + return NS_ERROR_INVALID_ARG; 1.507 + } 1.508 + nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame()); 1.509 + if (!comboFrame) { 1.510 + return NS_ERROR_FAILURE; 1.511 + } 1.512 + if (comboFrame->IsDroppedDown()) 1.513 + aName.AssignLiteral("close"); 1.514 + else 1.515 + aName.AssignLiteral("open"); 1.516 + 1.517 + return NS_OK; 1.518 +} 1.519 + 1.520 +//////////////////////////////////////////////////////////////////////////////// 1.521 +// HTMLComboboxAccessible: Widgets 1.522 + 1.523 +bool 1.524 +HTMLComboboxAccessible::IsWidget() const 1.525 +{ 1.526 + return true; 1.527 +} 1.528 + 1.529 +bool 1.530 +HTMLComboboxAccessible::IsActiveWidget() const 1.531 +{ 1.532 + return FocusMgr()->HasDOMFocus(mContent); 1.533 +} 1.534 + 1.535 +bool 1.536 +HTMLComboboxAccessible::AreItemsOperable() const 1.537 +{ 1.538 + nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(GetFrame()); 1.539 + return comboboxFrame && comboboxFrame->IsDroppedDown(); 1.540 +} 1.541 + 1.542 +Accessible* 1.543 +HTMLComboboxAccessible::CurrentItem() 1.544 +{ 1.545 + return AreItemsOperable() ? mListAccessible->CurrentItem() : nullptr; 1.546 +} 1.547 + 1.548 +void 1.549 +HTMLComboboxAccessible::SetCurrentItem(Accessible* aItem) 1.550 +{ 1.551 + if (AreItemsOperable()) 1.552 + mListAccessible->SetCurrentItem(aItem); 1.553 +} 1.554 + 1.555 +//////////////////////////////////////////////////////////////////////////////// 1.556 +// HTMLComboboxAccessible: protected 1.557 + 1.558 +Accessible* 1.559 +HTMLComboboxAccessible::SelectedOption() const 1.560 +{ 1.561 + nsIFrame* frame = GetFrame(); 1.562 + nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(frame); 1.563 + if (!comboboxFrame) 1.564 + return nullptr; 1.565 + 1.566 + nsIListControlFrame* listControlFrame = 1.567 + do_QueryFrame(comboboxFrame->GetDropDown()); 1.568 + if (listControlFrame) { 1.569 + nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption(); 1.570 + if (activeOptionNode) { 1.571 + DocAccessible* document = Document(); 1.572 + if (document) 1.573 + return document->GetAccessible(activeOptionNode); 1.574 + } 1.575 + } 1.576 + 1.577 + return nullptr; 1.578 +} 1.579 + 1.580 + 1.581 +//////////////////////////////////////////////////////////////////////////////// 1.582 +// HTMLComboboxListAccessible 1.583 +//////////////////////////////////////////////////////////////////////////////// 1.584 + 1.585 +HTMLComboboxListAccessible:: 1.586 + HTMLComboboxListAccessible(nsIAccessible* aParent, nsIContent* aContent, 1.587 + DocAccessible* aDoc) : 1.588 + HTMLSelectListAccessible(aContent, aDoc) 1.589 +{ 1.590 + mStateFlags |= eSharedNode; 1.591 +} 1.592 + 1.593 +//////////////////////////////////////////////////////////////////////////////// 1.594 +// HTMLComboboxAccessible: Accessible 1.595 + 1.596 +nsIFrame* 1.597 +HTMLComboboxListAccessible::GetFrame() const 1.598 +{ 1.599 + nsIFrame* frame = HTMLSelectListAccessible::GetFrame(); 1.600 + nsIComboboxControlFrame* comboBox = do_QueryFrame(frame); 1.601 + if (comboBox) { 1.602 + return comboBox->GetDropDown(); 1.603 + } 1.604 + 1.605 + return nullptr; 1.606 +} 1.607 + 1.608 +role 1.609 +HTMLComboboxListAccessible::NativeRole() 1.610 +{ 1.611 + return roles::COMBOBOX_LIST; 1.612 +} 1.613 + 1.614 +uint64_t 1.615 +HTMLComboboxListAccessible::NativeState() 1.616 +{ 1.617 + // As a HTMLComboboxListAccessible we can have the following states: 1.618 + // FOCUSED, FOCUSABLE, FLOATING, INVISIBLE 1.619 + // Get focus status from base class 1.620 + uint64_t state = Accessible::NativeState(); 1.621 + 1.622 + nsIComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame()); 1.623 + if (comboFrame && comboFrame->IsDroppedDown()) 1.624 + state |= states::FLOATING; 1.625 + else 1.626 + state |= states::INVISIBLE; 1.627 + 1.628 + return state; 1.629 +} 1.630 + 1.631 +/** 1.632 + * Gets the bounds for the areaFrame. 1.633 + * Walks the Frame tree and checks for proper frames. 1.634 + */ 1.635 +void 1.636 +HTMLComboboxListAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame) 1.637 +{ 1.638 + *aBoundingFrame = nullptr; 1.639 + 1.640 + Accessible* comboAcc = Parent(); 1.641 + if (!comboAcc) 1.642 + return; 1.643 + 1.644 + if (0 == (comboAcc->State() & states::COLLAPSED)) { 1.645 + HTMLSelectListAccessible::GetBoundsRect(aBounds, aBoundingFrame); 1.646 + return; 1.647 + } 1.648 + 1.649 + // Get the first option. 1.650 + nsIContent* content = mContent->GetFirstChild(); 1.651 + if (!content) { 1.652 + return; 1.653 + } 1.654 + nsIFrame* frame = content->GetPrimaryFrame(); 1.655 + if (!frame) { 1.656 + *aBoundingFrame = nullptr; 1.657 + return; 1.658 + } 1.659 + 1.660 + *aBoundingFrame = frame->GetParent(); 1.661 + aBounds = (*aBoundingFrame)->GetRect(); 1.662 +} 1.663 + 1.664 +//////////////////////////////////////////////////////////////////////////////// 1.665 +// HTMLComboboxListAccessible: Widgets 1.666 + 1.667 +bool 1.668 +HTMLComboboxListAccessible::IsActiveWidget() const 1.669 +{ 1.670 + return mParent && mParent->IsActiveWidget(); 1.671 +} 1.672 + 1.673 +bool 1.674 +HTMLComboboxListAccessible::AreItemsOperable() const 1.675 +{ 1.676 + return mParent && mParent->AreItemsOperable(); 1.677 +} 1.678 +