1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/src/html/HTMLFormControlAccessible.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,876 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "HTMLFormControlAccessible.h" 1.10 + 1.11 +#include "Accessible-inl.h" 1.12 +#include "nsAccUtils.h" 1.13 +#include "nsEventShell.h" 1.14 +#include "nsTextEquivUtils.h" 1.15 +#include "Relation.h" 1.16 +#include "Role.h" 1.17 +#include "States.h" 1.18 + 1.19 +#include "nsContentList.h" 1.20 +#include "mozilla/dom/HTMLInputElement.h" 1.21 +#include "nsIAccessibleRelation.h" 1.22 +#include "nsIDOMNSEditableElement.h" 1.23 +#include "nsIDOMHTMLTextAreaElement.h" 1.24 +#include "nsIEditor.h" 1.25 +#include "nsIFormControl.h" 1.26 +#include "nsIPersistentProperties2.h" 1.27 +#include "nsISelectionController.h" 1.28 +#include "nsIServiceManager.h" 1.29 +#include "nsITextControlFrame.h" 1.30 +#include "nsNameSpaceManager.h" 1.31 +#include "mozilla/dom/ScriptSettings.h" 1.32 + 1.33 +#include "mozilla/EventStates.h" 1.34 +#include "mozilla/FloatingPoint.h" 1.35 +#include "mozilla/Preferences.h" 1.36 + 1.37 +using namespace mozilla; 1.38 +using namespace mozilla::dom; 1.39 +using namespace mozilla::a11y; 1.40 + 1.41 +//////////////////////////////////////////////////////////////////////////////// 1.42 +// HTMLCheckboxAccessible 1.43 +//////////////////////////////////////////////////////////////////////////////// 1.44 + 1.45 +role 1.46 +HTMLCheckboxAccessible::NativeRole() 1.47 +{ 1.48 + return roles::CHECKBUTTON; 1.49 +} 1.50 + 1.51 +uint8_t 1.52 +HTMLCheckboxAccessible::ActionCount() 1.53 +{ 1.54 + return 1; 1.55 +} 1.56 + 1.57 +NS_IMETHODIMP 1.58 +HTMLCheckboxAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.59 +{ 1.60 + if (aIndex == eAction_Click) { // 0 is the magic value for default action 1.61 + // cycle, check or uncheck 1.62 + uint64_t state = NativeState(); 1.63 + 1.64 + if (state & states::CHECKED) 1.65 + aName.AssignLiteral("uncheck"); 1.66 + else if (state & states::MIXED) 1.67 + aName.AssignLiteral("cycle"); 1.68 + else 1.69 + aName.AssignLiteral("check"); 1.70 + 1.71 + return NS_OK; 1.72 + } 1.73 + return NS_ERROR_INVALID_ARG; 1.74 +} 1.75 + 1.76 +NS_IMETHODIMP 1.77 +HTMLCheckboxAccessible::DoAction(uint8_t aIndex) 1.78 +{ 1.79 + if (aIndex != 0) 1.80 + return NS_ERROR_INVALID_ARG; 1.81 + 1.82 + DoCommand(); 1.83 + return NS_OK; 1.84 +} 1.85 + 1.86 +uint64_t 1.87 +HTMLCheckboxAccessible::NativeState() 1.88 +{ 1.89 + uint64_t state = LeafAccessible::NativeState(); 1.90 + 1.91 + state |= states::CHECKABLE; 1.92 + HTMLInputElement* input = HTMLInputElement::FromContent(mContent); 1.93 + if (!input) 1.94 + return state; 1.95 + 1.96 + if (input->Indeterminate()) 1.97 + return state | states::MIXED; 1.98 + 1.99 + if (input->Checked()) 1.100 + return state | states::CHECKED; 1.101 + 1.102 + return state; 1.103 +} 1.104 + 1.105 +//////////////////////////////////////////////////////////////////////////////// 1.106 +// HTMLCheckboxAccessible: Widgets 1.107 + 1.108 +bool 1.109 +HTMLCheckboxAccessible::IsWidget() const 1.110 +{ 1.111 + return true; 1.112 +} 1.113 + 1.114 + 1.115 +//////////////////////////////////////////////////////////////////////////////// 1.116 +// HTMLRadioButtonAccessible 1.117 +//////////////////////////////////////////////////////////////////////////////// 1.118 + 1.119 +uint64_t 1.120 +HTMLRadioButtonAccessible::NativeState() 1.121 +{ 1.122 + uint64_t state = AccessibleWrap::NativeState(); 1.123 + 1.124 + state |= states::CHECKABLE; 1.125 + 1.126 + HTMLInputElement* input = HTMLInputElement::FromContent(mContent); 1.127 + if (input && input->Checked()) 1.128 + state |= states::CHECKED; 1.129 + 1.130 + return state; 1.131 +} 1.132 + 1.133 +void 1.134 +HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet, 1.135 + int32_t* aSetSize) 1.136 +{ 1.137 + int32_t namespaceId = mContent->NodeInfo()->NamespaceID(); 1.138 + nsAutoString tagName; 1.139 + mContent->NodeInfo()->GetName(tagName); 1.140 + 1.141 + nsAutoString type; 1.142 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type); 1.143 + nsAutoString name; 1.144 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name); 1.145 + 1.146 + nsRefPtr<nsContentList> inputElms; 1.147 + 1.148 + nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent)); 1.149 + dom::Element* formElm = formControlNode->GetFormElement(); 1.150 + if (formElm) 1.151 + inputElms = NS_GetContentList(formElm, namespaceId, tagName); 1.152 + else 1.153 + inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName); 1.154 + NS_ENSURE_TRUE_VOID(inputElms); 1.155 + 1.156 + uint32_t inputCount = inputElms->Length(false); 1.157 + 1.158 + // Compute posinset and setsize. 1.159 + int32_t indexOf = 0; 1.160 + int32_t count = 0; 1.161 + 1.162 + for (uint32_t index = 0; index < inputCount; index++) { 1.163 + nsIContent* inputElm = inputElms->Item(index, false); 1.164 + if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 1.165 + type, eCaseMatters) && 1.166 + inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, 1.167 + name, eCaseMatters) && mDoc->HasAccessible(inputElm)) { 1.168 + count++; 1.169 + if (inputElm == mContent) 1.170 + indexOf = count; 1.171 + } 1.172 + } 1.173 + 1.174 + *aPosInSet = indexOf; 1.175 + *aSetSize = count; 1.176 +} 1.177 + 1.178 +//////////////////////////////////////////////////////////////////////////////// 1.179 +// HTMLButtonAccessible 1.180 +//////////////////////////////////////////////////////////////////////////////// 1.181 + 1.182 +HTMLButtonAccessible:: 1.183 + HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.184 + HyperTextAccessibleWrap(aContent, aDoc) 1.185 +{ 1.186 + mGenericTypes |= eButton; 1.187 +} 1.188 + 1.189 +uint8_t 1.190 +HTMLButtonAccessible::ActionCount() 1.191 +{ 1.192 + return 1; 1.193 +} 1.194 + 1.195 +NS_IMETHODIMP 1.196 +HTMLButtonAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.197 +{ 1.198 + if (aIndex == eAction_Click) { 1.199 + aName.AssignLiteral("press"); 1.200 + return NS_OK; 1.201 + } 1.202 + return NS_ERROR_INVALID_ARG; 1.203 +} 1.204 + 1.205 +NS_IMETHODIMP 1.206 +HTMLButtonAccessible::DoAction(uint8_t aIndex) 1.207 +{ 1.208 + if (aIndex != eAction_Click) 1.209 + return NS_ERROR_INVALID_ARG; 1.210 + 1.211 + DoCommand(); 1.212 + return NS_OK; 1.213 +} 1.214 + 1.215 +uint64_t 1.216 +HTMLButtonAccessible::State() 1.217 +{ 1.218 + uint64_t state = HyperTextAccessibleWrap::State(); 1.219 + if (state == states::DEFUNCT) 1.220 + return state; 1.221 + 1.222 + // Inherit states from input@type="file" suitable for the button. Note, 1.223 + // no special processing for unavailable state since inheritance is supplied 1.224 + // other code paths. 1.225 + if (mParent && mParent->IsHTMLFileInput()) { 1.226 + uint64_t parentState = mParent->State(); 1.227 + state |= parentState & (states::BUSY | states::REQUIRED | 1.228 + states::HASPOPUP | states::INVALID); 1.229 + } 1.230 + 1.231 + return state; 1.232 +} 1.233 + 1.234 +uint64_t 1.235 +HTMLButtonAccessible::NativeState() 1.236 +{ 1.237 + uint64_t state = HyperTextAccessibleWrap::NativeState(); 1.238 + 1.239 + EventStates elmState = mContent->AsElement()->State(); 1.240 + if (elmState.HasState(NS_EVENT_STATE_DEFAULT)) 1.241 + state |= states::DEFAULT; 1.242 + 1.243 + return state; 1.244 +} 1.245 + 1.246 +role 1.247 +HTMLButtonAccessible::NativeRole() 1.248 +{ 1.249 + return roles::PUSHBUTTON; 1.250 +} 1.251 + 1.252 +ENameValueFlag 1.253 +HTMLButtonAccessible::NativeName(nsString& aName) 1.254 +{ 1.255 + // No need to check @value attribute for buttons since this attribute results 1.256 + // in native anonymous text node and the name is calculated from subtree. 1.257 + // The same magic works for @alt and @value attributes in case of type="image" 1.258 + // element that has no valid @src (note if input@type="image" has an image 1.259 + // then neither @alt nor @value attributes are used to generate a visual label 1.260 + // and thus we need to obtain the accessible name directly from attribute 1.261 + // value). Also the same algorithm works in case of default labels for 1.262 + // type="submit"/"reset"/"image" elements. 1.263 + 1.264 + ENameValueFlag nameFlag = Accessible::NativeName(aName); 1.265 + if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input || 1.266 + !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 1.267 + nsGkAtoms::image, eCaseMatters)) 1.268 + return nameFlag; 1.269 + 1.270 + if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName)) 1.271 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName); 1.272 + 1.273 + aName.CompressWhitespace(); 1.274 + return eNameOK; 1.275 +} 1.276 + 1.277 +//////////////////////////////////////////////////////////////////////////////// 1.278 +// HTMLButtonAccessible: Widgets 1.279 + 1.280 +bool 1.281 +HTMLButtonAccessible::IsWidget() const 1.282 +{ 1.283 + return true; 1.284 +} 1.285 + 1.286 + 1.287 +//////////////////////////////////////////////////////////////////////////////// 1.288 +// HTMLTextFieldAccessible 1.289 +//////////////////////////////////////////////////////////////////////////////// 1.290 + 1.291 +HTMLTextFieldAccessible:: 1.292 + HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.293 + HyperTextAccessibleWrap(aContent, aDoc) 1.294 +{ 1.295 + mType = eHTMLTextFieldType; 1.296 +} 1.297 + 1.298 +NS_IMPL_ISUPPORTS_INHERITED(HTMLTextFieldAccessible, 1.299 + Accessible, 1.300 + nsIAccessibleText, 1.301 + nsIAccessibleEditableText) 1.302 + 1.303 +role 1.304 +HTMLTextFieldAccessible::NativeRole() 1.305 +{ 1.306 + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 1.307 + nsGkAtoms::password, eIgnoreCase)) { 1.308 + return roles::PASSWORD_TEXT; 1.309 + } 1.310 + 1.311 + return roles::ENTRY; 1.312 +} 1.313 + 1.314 +already_AddRefed<nsIPersistentProperties> 1.315 +HTMLTextFieldAccessible::NativeAttributes() 1.316 +{ 1.317 + nsCOMPtr<nsIPersistentProperties> attributes = 1.318 + HyperTextAccessibleWrap::NativeAttributes(); 1.319 + 1.320 + // Expose type for text input elements as it gives some useful context, 1.321 + // especially for mobile. 1.322 + nsAutoString type; 1.323 + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) 1.324 + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type); 1.325 + 1.326 + return attributes.forget(); 1.327 +} 1.328 + 1.329 +ENameValueFlag 1.330 +HTMLTextFieldAccessible::NativeName(nsString& aName) 1.331 +{ 1.332 + ENameValueFlag nameFlag = Accessible::NativeName(aName); 1.333 + if (!aName.IsEmpty()) 1.334 + return nameFlag; 1.335 + 1.336 + // If part of compound of XUL widget then grab a name from XUL widget element. 1.337 + nsIContent* widgetElm = XULWidgetElm(); 1.338 + if (widgetElm) 1.339 + XULElmName(mDoc, widgetElm, aName); 1.340 + 1.341 + if (!aName.IsEmpty()) 1.342 + return eNameOK; 1.343 + 1.344 + // text inputs and textareas might have useful placeholder text 1.345 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName); 1.346 + return eNameOK; 1.347 +} 1.348 + 1.349 +void 1.350 +HTMLTextFieldAccessible::Value(nsString& aValue) 1.351 +{ 1.352 + aValue.Truncate(); 1.353 + if (NativeState() & states::PROTECTED) // Don't return password text! 1.354 + return; 1.355 + 1.356 + nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent)); 1.357 + if (textArea) { 1.358 + textArea->GetValue(aValue); 1.359 + return; 1.360 + } 1.361 + 1.362 + HTMLInputElement* input = HTMLInputElement::FromContent(mContent); 1.363 + if (input) 1.364 + input->GetValue(aValue); 1.365 +} 1.366 + 1.367 +void 1.368 +HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const 1.369 +{ 1.370 + HyperTextAccessibleWrap::ApplyARIAState(aState); 1.371 + aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState); 1.372 + 1.373 + // If part of compound of XUL widget then pick up ARIA stuff from XUL widget 1.374 + // element. 1.375 + nsIContent* widgetElm = XULWidgetElm(); 1.376 + if (widgetElm) 1.377 + aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState); 1.378 +} 1.379 + 1.380 +uint64_t 1.381 +HTMLTextFieldAccessible::NativeState() 1.382 +{ 1.383 + uint64_t state = HyperTextAccessibleWrap::NativeState(); 1.384 + 1.385 + // Text fields are always editable, even if they are also read only or 1.386 + // disabled. 1.387 + state |= states::EDITABLE; 1.388 + 1.389 + // can be focusable, focused, protected. readonly, unavailable, selected 1.390 + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, 1.391 + nsGkAtoms::password, eIgnoreCase)) { 1.392 + state |= states::PROTECTED; 1.393 + } 1.394 + 1.395 + if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) { 1.396 + state |= states::READONLY; 1.397 + } 1.398 + 1.399 + // Is it an <input> or a <textarea> ? 1.400 + HTMLInputElement* input = HTMLInputElement::FromContent(mContent); 1.401 + state |= input && input->IsSingleLineTextControl() ? 1.402 + states::SINGLE_LINE : states::MULTI_LINE; 1.403 + 1.404 + if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY | 1.405 + states::UNAVAILABLE)) 1.406 + return state; 1.407 + 1.408 + // Expose autocomplete states if this input is part of autocomplete widget. 1.409 + Accessible* widget = ContainerWidget(); 1.410 + if (widget && widget-IsAutoComplete()) { 1.411 + state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION; 1.412 + return state; 1.413 + } 1.414 + 1.415 + // Expose autocomplete state if it has associated autocomplete list. 1.416 + if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list)) 1.417 + return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP; 1.418 + 1.419 + // Ordinal XUL textboxes don't support autocomplete. 1.420 + if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) { 1.421 + // Check to see if autocompletion is allowed on this input. We don't expose 1.422 + // it for password fields even though the entire password can be remembered 1.423 + // for a page if the user asks it to be. However, the kind of autocomplete 1.424 + // we're talking here is based on what the user types, where a popup of 1.425 + // possible choices comes up. 1.426 + nsAutoString autocomplete; 1.427 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, 1.428 + autocomplete); 1.429 + 1.430 + if (!autocomplete.LowerCaseEqualsLiteral("off")) { 1.431 + nsIContent* formContent = input->GetFormElement(); 1.432 + if (formContent) { 1.433 + formContent->GetAttr(kNameSpaceID_None, 1.434 + nsGkAtoms::autocomplete, autocomplete); 1.435 + } 1.436 + 1.437 + if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off")) 1.438 + state |= states::SUPPORTS_AUTOCOMPLETION; 1.439 + } 1.440 + } 1.441 + 1.442 + return state; 1.443 +} 1.444 + 1.445 +uint8_t 1.446 +HTMLTextFieldAccessible::ActionCount() 1.447 +{ 1.448 + return 1; 1.449 +} 1.450 + 1.451 +NS_IMETHODIMP 1.452 +HTMLTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName) 1.453 +{ 1.454 + if (aIndex == eAction_Click) { 1.455 + aName.AssignLiteral("activate"); 1.456 + return NS_OK; 1.457 + } 1.458 + return NS_ERROR_INVALID_ARG; 1.459 +} 1.460 + 1.461 +NS_IMETHODIMP 1.462 +HTMLTextFieldAccessible::DoAction(uint8_t aIndex) 1.463 +{ 1.464 + if (aIndex == 0) 1.465 + return TakeFocus(); 1.466 + 1.467 + return NS_ERROR_INVALID_ARG; 1.468 +} 1.469 + 1.470 +already_AddRefed<nsIEditor> 1.471 +HTMLTextFieldAccessible::GetEditor() const 1.472 +{ 1.473 + nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent)); 1.474 + if (!editableElt) 1.475 + return nullptr; 1.476 + 1.477 + // nsGenericHTMLElement::GetEditor has a security check. 1.478 + // Make sure we're not restricted by the permissions of 1.479 + // whatever script is currently running. 1.480 + mozilla::dom::AutoNoJSAPI nojsapi; 1.481 + 1.482 + nsCOMPtr<nsIEditor> editor; 1.483 + editableElt->GetEditor(getter_AddRefs(editor)); 1.484 + 1.485 + return editor.forget(); 1.486 +} 1.487 + 1.488 +//////////////////////////////////////////////////////////////////////////////// 1.489 +// HTMLTextFieldAccessible: Widgets 1.490 + 1.491 +bool 1.492 +HTMLTextFieldAccessible::IsWidget() const 1.493 +{ 1.494 + return true; 1.495 +} 1.496 + 1.497 +Accessible* 1.498 +HTMLTextFieldAccessible::ContainerWidget() const 1.499 +{ 1.500 + return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr; 1.501 +} 1.502 + 1.503 + 1.504 +//////////////////////////////////////////////////////////////////////////////// 1.505 +// HTMLFileInputAccessible 1.506 +//////////////////////////////////////////////////////////////////////////////// 1.507 + 1.508 +HTMLFileInputAccessible:: 1.509 +HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.510 + HyperTextAccessibleWrap(aContent, aDoc) 1.511 +{ 1.512 + mType = eHTMLFileInputType; 1.513 +} 1.514 + 1.515 +role 1.516 +HTMLFileInputAccessible::NativeRole() 1.517 +{ 1.518 + // JAWS wants a text container, others don't mind. No specific role in 1.519 + // AT APIs. 1.520 + return roles::TEXT_CONTAINER; 1.521 +} 1.522 + 1.523 +nsresult 1.524 +HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent) 1.525 +{ 1.526 + nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent); 1.527 + NS_ENSURE_SUCCESS(rv, rv); 1.528 + 1.529 + // Redirect state change events for inherited states to child controls. Note, 1.530 + // unavailable state is not redirected. That's a standard for unavailable 1.531 + // state handling. 1.532 + AccStateChangeEvent* event = downcast_accEvent(aEvent); 1.533 + if (event && 1.534 + (event->GetState() == states::BUSY || 1.535 + event->GetState() == states::REQUIRED || 1.536 + event->GetState() == states::HASPOPUP || 1.537 + event->GetState() == states::INVALID)) { 1.538 + Accessible* button = GetChildAt(0); 1.539 + if (button && button->Role() == roles::PUSHBUTTON) { 1.540 + nsRefPtr<AccStateChangeEvent> childEvent = 1.541 + new AccStateChangeEvent(button, event->GetState(), 1.542 + event->IsStateEnabled(), event->FromUserInput()); 1.543 + nsEventShell::FireEvent(childEvent); 1.544 + } 1.545 + } 1.546 + 1.547 + return NS_OK; 1.548 +} 1.549 + 1.550 + 1.551 +//////////////////////////////////////////////////////////////////////////////// 1.552 +// HTMLSpinnerAccessible 1.553 +//////////////////////////////////////////////////////////////////////////////// 1.554 + 1.555 +role 1.556 +HTMLSpinnerAccessible::NativeRole() 1.557 +{ 1.558 + return roles::SPINBUTTON; 1.559 +} 1.560 + 1.561 +void 1.562 +HTMLSpinnerAccessible::Value(nsString& aValue) 1.563 +{ 1.564 + AccessibleWrap::Value(aValue); 1.565 + if (!aValue.IsEmpty()) 1.566 + return; 1.567 + 1.568 + HTMLInputElement::FromContent(mContent)->GetValue(aValue); 1.569 +} 1.570 + 1.571 +double 1.572 +HTMLSpinnerAccessible::MaxValue() const 1.573 +{ 1.574 + double value = AccessibleWrap::MaxValue(); 1.575 + if (!IsNaN(value)) 1.576 + return value; 1.577 + 1.578 + return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble(); 1.579 +} 1.580 + 1.581 + 1.582 +double 1.583 +HTMLSpinnerAccessible::MinValue() const 1.584 +{ 1.585 + double value = AccessibleWrap::MinValue(); 1.586 + if (!IsNaN(value)) 1.587 + return value; 1.588 + 1.589 + return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble(); 1.590 +} 1.591 + 1.592 +double 1.593 +HTMLSpinnerAccessible::Step() const 1.594 +{ 1.595 + double value = AccessibleWrap::Step(); 1.596 + if (!IsNaN(value)) 1.597 + return value; 1.598 + 1.599 + return HTMLInputElement::FromContent(mContent)->GetStep().toDouble(); 1.600 +} 1.601 + 1.602 +double 1.603 +HTMLSpinnerAccessible::CurValue() const 1.604 +{ 1.605 + double value = AccessibleWrap::CurValue(); 1.606 + if (!IsNaN(value)) 1.607 + return value; 1.608 + 1.609 + return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble(); 1.610 +} 1.611 + 1.612 +bool 1.613 +HTMLSpinnerAccessible::SetCurValue(double aValue) 1.614 +{ 1.615 + ErrorResult er; 1.616 + HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er); 1.617 + return !er.Failed(); 1.618 +} 1.619 + 1.620 + 1.621 +//////////////////////////////////////////////////////////////////////////////// 1.622 +// HTMLRangeAccessible 1.623 +//////////////////////////////////////////////////////////////////////////////// 1.624 + 1.625 +role 1.626 +HTMLRangeAccessible::NativeRole() 1.627 +{ 1.628 + return roles::SLIDER; 1.629 +} 1.630 + 1.631 +bool 1.632 +HTMLRangeAccessible::IsWidget() const 1.633 +{ 1.634 + return true; 1.635 +} 1.636 + 1.637 +void 1.638 +HTMLRangeAccessible::Value(nsString& aValue) 1.639 +{ 1.640 + LeafAccessible::Value(aValue); 1.641 + if (!aValue.IsEmpty()) 1.642 + return; 1.643 + 1.644 + HTMLInputElement::FromContent(mContent)->GetValue(aValue); 1.645 +} 1.646 + 1.647 +double 1.648 +HTMLRangeAccessible::MaxValue() const 1.649 +{ 1.650 + double value = LeafAccessible::MaxValue(); 1.651 + if (!IsNaN(value)) 1.652 + return value; 1.653 + 1.654 + return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble(); 1.655 +} 1.656 + 1.657 +double 1.658 +HTMLRangeAccessible::MinValue() const 1.659 +{ 1.660 + double value = LeafAccessible::MinValue(); 1.661 + if (!IsNaN(value)) 1.662 + return value; 1.663 + 1.664 + return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble(); 1.665 +} 1.666 + 1.667 +double 1.668 +HTMLRangeAccessible::Step() const 1.669 +{ 1.670 + double value = LeafAccessible::Step(); 1.671 + if (!IsNaN(value)) 1.672 + return value; 1.673 + 1.674 + return HTMLInputElement::FromContent(mContent)->GetStep().toDouble(); 1.675 +} 1.676 + 1.677 +double 1.678 +HTMLRangeAccessible::CurValue() const 1.679 +{ 1.680 + double value = LeafAccessible::CurValue(); 1.681 + if (!IsNaN(value)) 1.682 + return value; 1.683 + 1.684 + return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble(); 1.685 +} 1.686 + 1.687 +bool 1.688 +HTMLRangeAccessible::SetCurValue(double aValue) 1.689 +{ 1.690 + ErrorResult er; 1.691 + HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er); 1.692 + return !er.Failed(); 1.693 +} 1.694 + 1.695 + 1.696 +//////////////////////////////////////////////////////////////////////////////// 1.697 +// HTMLGroupboxAccessible 1.698 +//////////////////////////////////////////////////////////////////////////////// 1.699 + 1.700 +HTMLGroupboxAccessible:: 1.701 + HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.702 + HyperTextAccessibleWrap(aContent, aDoc) 1.703 +{ 1.704 +} 1.705 + 1.706 +role 1.707 +HTMLGroupboxAccessible::NativeRole() 1.708 +{ 1.709 + return roles::GROUPING; 1.710 +} 1.711 + 1.712 +nsIContent* 1.713 +HTMLGroupboxAccessible::GetLegend() 1.714 +{ 1.715 + for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent; 1.716 + legendContent = legendContent->GetNextSibling()) { 1.717 + if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend, 1.718 + mContent->GetNameSpaceID())) { 1.719 + // Either XHTML namespace or no namespace 1.720 + return legendContent; 1.721 + } 1.722 + } 1.723 + 1.724 + return nullptr; 1.725 +} 1.726 + 1.727 +ENameValueFlag 1.728 +HTMLGroupboxAccessible::NativeName(nsString& aName) 1.729 +{ 1.730 + ENameValueFlag nameFlag = Accessible::NativeName(aName); 1.731 + if (!aName.IsEmpty()) 1.732 + return nameFlag; 1.733 + 1.734 + nsIContent* legendContent = GetLegend(); 1.735 + if (legendContent) 1.736 + nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName); 1.737 + 1.738 + return eNameOK; 1.739 +} 1.740 + 1.741 +Relation 1.742 +HTMLGroupboxAccessible::RelationByType(RelationType aType) 1.743 +{ 1.744 + Relation rel = HyperTextAccessibleWrap::RelationByType(aType); 1.745 + // No override for label, so use <legend> for this <fieldset> 1.746 + if (aType == RelationType::LABELLED_BY) 1.747 + rel.AppendTarget(mDoc, GetLegend()); 1.748 + 1.749 + return rel; 1.750 +} 1.751 + 1.752 +//////////////////////////////////////////////////////////////////////////////// 1.753 +// HTMLLegendAccessible 1.754 +//////////////////////////////////////////////////////////////////////////////// 1.755 + 1.756 +HTMLLegendAccessible:: 1.757 + HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.758 + HyperTextAccessibleWrap(aContent, aDoc) 1.759 +{ 1.760 +} 1.761 + 1.762 +Relation 1.763 +HTMLLegendAccessible::RelationByType(RelationType aType) 1.764 +{ 1.765 + Relation rel = HyperTextAccessibleWrap::RelationByType(aType); 1.766 + if (aType != RelationType::LABEL_FOR) 1.767 + return rel; 1.768 + 1.769 + Accessible* groupbox = Parent(); 1.770 + if (groupbox && groupbox->Role() == roles::GROUPING) 1.771 + rel.AppendTarget(groupbox); 1.772 + 1.773 + return rel; 1.774 +} 1.775 + 1.776 +role 1.777 +HTMLLegendAccessible::NativeRole() 1.778 +{ 1.779 + return roles::LABEL; 1.780 +} 1.781 + 1.782 +//////////////////////////////////////////////////////////////////////////////// 1.783 +// HTMLFigureAccessible 1.784 +//////////////////////////////////////////////////////////////////////////////// 1.785 + 1.786 +HTMLFigureAccessible:: 1.787 + HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.788 + HyperTextAccessibleWrap(aContent, aDoc) 1.789 +{ 1.790 +} 1.791 + 1.792 +already_AddRefed<nsIPersistentProperties> 1.793 +HTMLFigureAccessible::NativeAttributes() 1.794 +{ 1.795 + nsCOMPtr<nsIPersistentProperties> attributes = 1.796 + HyperTextAccessibleWrap::NativeAttributes(); 1.797 + 1.798 + // Expose figure xml-role. 1.799 + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, 1.800 + NS_LITERAL_STRING("figure")); 1.801 + return attributes.forget(); 1.802 +} 1.803 + 1.804 +role 1.805 +HTMLFigureAccessible::NativeRole() 1.806 +{ 1.807 + return roles::FIGURE; 1.808 +} 1.809 + 1.810 +ENameValueFlag 1.811 +HTMLFigureAccessible::NativeName(nsString& aName) 1.812 +{ 1.813 + ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName); 1.814 + if (!aName.IsEmpty()) 1.815 + return nameFlag; 1.816 + 1.817 + nsIContent* captionContent = Caption(); 1.818 + if (captionContent) 1.819 + nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName); 1.820 + 1.821 + return eNameOK; 1.822 +} 1.823 + 1.824 +Relation 1.825 +HTMLFigureAccessible::RelationByType(RelationType aType) 1.826 +{ 1.827 + Relation rel = HyperTextAccessibleWrap::RelationByType(aType); 1.828 + if (aType == RelationType::LABELLED_BY) 1.829 + rel.AppendTarget(mDoc, Caption()); 1.830 + 1.831 + return rel; 1.832 +} 1.833 + 1.834 +nsIContent* 1.835 +HTMLFigureAccessible::Caption() const 1.836 +{ 1.837 + for (nsIContent* childContent = mContent->GetFirstChild(); childContent; 1.838 + childContent = childContent->GetNextSibling()) { 1.839 + if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption, 1.840 + mContent->GetNameSpaceID())) { 1.841 + return childContent; 1.842 + } 1.843 + } 1.844 + 1.845 + return nullptr; 1.846 +} 1.847 + 1.848 +//////////////////////////////////////////////////////////////////////////////// 1.849 +// HTMLFigcaptionAccessible 1.850 +//////////////////////////////////////////////////////////////////////////////// 1.851 + 1.852 +HTMLFigcaptionAccessible:: 1.853 + HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) : 1.854 + HyperTextAccessibleWrap(aContent, aDoc) 1.855 +{ 1.856 +} 1.857 + 1.858 +role 1.859 +HTMLFigcaptionAccessible::NativeRole() 1.860 +{ 1.861 + return roles::CAPTION; 1.862 +} 1.863 + 1.864 +Relation 1.865 +HTMLFigcaptionAccessible::RelationByType(RelationType aType) 1.866 +{ 1.867 + Relation rel = HyperTextAccessibleWrap::RelationByType(aType); 1.868 + if (aType != RelationType::LABEL_FOR) 1.869 + return rel; 1.870 + 1.871 + Accessible* figure = Parent(); 1.872 + if (figure && 1.873 + figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure, 1.874 + mContent->GetNameSpaceID())) { 1.875 + rel.AppendTarget(figure); 1.876 + } 1.877 + 1.878 + return rel; 1.879 +}