accessible/src/html/HTMLFormControlAccessible.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "HTMLFormControlAccessible.h"
michael@0 7
michael@0 8 #include "Accessible-inl.h"
michael@0 9 #include "nsAccUtils.h"
michael@0 10 #include "nsEventShell.h"
michael@0 11 #include "nsTextEquivUtils.h"
michael@0 12 #include "Relation.h"
michael@0 13 #include "Role.h"
michael@0 14 #include "States.h"
michael@0 15
michael@0 16 #include "nsContentList.h"
michael@0 17 #include "mozilla/dom/HTMLInputElement.h"
michael@0 18 #include "nsIAccessibleRelation.h"
michael@0 19 #include "nsIDOMNSEditableElement.h"
michael@0 20 #include "nsIDOMHTMLTextAreaElement.h"
michael@0 21 #include "nsIEditor.h"
michael@0 22 #include "nsIFormControl.h"
michael@0 23 #include "nsIPersistentProperties2.h"
michael@0 24 #include "nsISelectionController.h"
michael@0 25 #include "nsIServiceManager.h"
michael@0 26 #include "nsITextControlFrame.h"
michael@0 27 #include "nsNameSpaceManager.h"
michael@0 28 #include "mozilla/dom/ScriptSettings.h"
michael@0 29
michael@0 30 #include "mozilla/EventStates.h"
michael@0 31 #include "mozilla/FloatingPoint.h"
michael@0 32 #include "mozilla/Preferences.h"
michael@0 33
michael@0 34 using namespace mozilla;
michael@0 35 using namespace mozilla::dom;
michael@0 36 using namespace mozilla::a11y;
michael@0 37
michael@0 38 ////////////////////////////////////////////////////////////////////////////////
michael@0 39 // HTMLCheckboxAccessible
michael@0 40 ////////////////////////////////////////////////////////////////////////////////
michael@0 41
michael@0 42 role
michael@0 43 HTMLCheckboxAccessible::NativeRole()
michael@0 44 {
michael@0 45 return roles::CHECKBUTTON;
michael@0 46 }
michael@0 47
michael@0 48 uint8_t
michael@0 49 HTMLCheckboxAccessible::ActionCount()
michael@0 50 {
michael@0 51 return 1;
michael@0 52 }
michael@0 53
michael@0 54 NS_IMETHODIMP
michael@0 55 HTMLCheckboxAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
michael@0 56 {
michael@0 57 if (aIndex == eAction_Click) { // 0 is the magic value for default action
michael@0 58 // cycle, check or uncheck
michael@0 59 uint64_t state = NativeState();
michael@0 60
michael@0 61 if (state & states::CHECKED)
michael@0 62 aName.AssignLiteral("uncheck");
michael@0 63 else if (state & states::MIXED)
michael@0 64 aName.AssignLiteral("cycle");
michael@0 65 else
michael@0 66 aName.AssignLiteral("check");
michael@0 67
michael@0 68 return NS_OK;
michael@0 69 }
michael@0 70 return NS_ERROR_INVALID_ARG;
michael@0 71 }
michael@0 72
michael@0 73 NS_IMETHODIMP
michael@0 74 HTMLCheckboxAccessible::DoAction(uint8_t aIndex)
michael@0 75 {
michael@0 76 if (aIndex != 0)
michael@0 77 return NS_ERROR_INVALID_ARG;
michael@0 78
michael@0 79 DoCommand();
michael@0 80 return NS_OK;
michael@0 81 }
michael@0 82
michael@0 83 uint64_t
michael@0 84 HTMLCheckboxAccessible::NativeState()
michael@0 85 {
michael@0 86 uint64_t state = LeafAccessible::NativeState();
michael@0 87
michael@0 88 state |= states::CHECKABLE;
michael@0 89 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
michael@0 90 if (!input)
michael@0 91 return state;
michael@0 92
michael@0 93 if (input->Indeterminate())
michael@0 94 return state | states::MIXED;
michael@0 95
michael@0 96 if (input->Checked())
michael@0 97 return state | states::CHECKED;
michael@0 98
michael@0 99 return state;
michael@0 100 }
michael@0 101
michael@0 102 ////////////////////////////////////////////////////////////////////////////////
michael@0 103 // HTMLCheckboxAccessible: Widgets
michael@0 104
michael@0 105 bool
michael@0 106 HTMLCheckboxAccessible::IsWidget() const
michael@0 107 {
michael@0 108 return true;
michael@0 109 }
michael@0 110
michael@0 111
michael@0 112 ////////////////////////////////////////////////////////////////////////////////
michael@0 113 // HTMLRadioButtonAccessible
michael@0 114 ////////////////////////////////////////////////////////////////////////////////
michael@0 115
michael@0 116 uint64_t
michael@0 117 HTMLRadioButtonAccessible::NativeState()
michael@0 118 {
michael@0 119 uint64_t state = AccessibleWrap::NativeState();
michael@0 120
michael@0 121 state |= states::CHECKABLE;
michael@0 122
michael@0 123 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
michael@0 124 if (input && input->Checked())
michael@0 125 state |= states::CHECKED;
michael@0 126
michael@0 127 return state;
michael@0 128 }
michael@0 129
michael@0 130 void
michael@0 131 HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
michael@0 132 int32_t* aSetSize)
michael@0 133 {
michael@0 134 int32_t namespaceId = mContent->NodeInfo()->NamespaceID();
michael@0 135 nsAutoString tagName;
michael@0 136 mContent->NodeInfo()->GetName(tagName);
michael@0 137
michael@0 138 nsAutoString type;
michael@0 139 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
michael@0 140 nsAutoString name;
michael@0 141 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
michael@0 142
michael@0 143 nsRefPtr<nsContentList> inputElms;
michael@0 144
michael@0 145 nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
michael@0 146 dom::Element* formElm = formControlNode->GetFormElement();
michael@0 147 if (formElm)
michael@0 148 inputElms = NS_GetContentList(formElm, namespaceId, tagName);
michael@0 149 else
michael@0 150 inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
michael@0 151 NS_ENSURE_TRUE_VOID(inputElms);
michael@0 152
michael@0 153 uint32_t inputCount = inputElms->Length(false);
michael@0 154
michael@0 155 // Compute posinset and setsize.
michael@0 156 int32_t indexOf = 0;
michael@0 157 int32_t count = 0;
michael@0 158
michael@0 159 for (uint32_t index = 0; index < inputCount; index++) {
michael@0 160 nsIContent* inputElm = inputElms->Item(index, false);
michael@0 161 if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
michael@0 162 type, eCaseMatters) &&
michael@0 163 inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
michael@0 164 name, eCaseMatters) && mDoc->HasAccessible(inputElm)) {
michael@0 165 count++;
michael@0 166 if (inputElm == mContent)
michael@0 167 indexOf = count;
michael@0 168 }
michael@0 169 }
michael@0 170
michael@0 171 *aPosInSet = indexOf;
michael@0 172 *aSetSize = count;
michael@0 173 }
michael@0 174
michael@0 175 ////////////////////////////////////////////////////////////////////////////////
michael@0 176 // HTMLButtonAccessible
michael@0 177 ////////////////////////////////////////////////////////////////////////////////
michael@0 178
michael@0 179 HTMLButtonAccessible::
michael@0 180 HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 181 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 182 {
michael@0 183 mGenericTypes |= eButton;
michael@0 184 }
michael@0 185
michael@0 186 uint8_t
michael@0 187 HTMLButtonAccessible::ActionCount()
michael@0 188 {
michael@0 189 return 1;
michael@0 190 }
michael@0 191
michael@0 192 NS_IMETHODIMP
michael@0 193 HTMLButtonAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
michael@0 194 {
michael@0 195 if (aIndex == eAction_Click) {
michael@0 196 aName.AssignLiteral("press");
michael@0 197 return NS_OK;
michael@0 198 }
michael@0 199 return NS_ERROR_INVALID_ARG;
michael@0 200 }
michael@0 201
michael@0 202 NS_IMETHODIMP
michael@0 203 HTMLButtonAccessible::DoAction(uint8_t aIndex)
michael@0 204 {
michael@0 205 if (aIndex != eAction_Click)
michael@0 206 return NS_ERROR_INVALID_ARG;
michael@0 207
michael@0 208 DoCommand();
michael@0 209 return NS_OK;
michael@0 210 }
michael@0 211
michael@0 212 uint64_t
michael@0 213 HTMLButtonAccessible::State()
michael@0 214 {
michael@0 215 uint64_t state = HyperTextAccessibleWrap::State();
michael@0 216 if (state == states::DEFUNCT)
michael@0 217 return state;
michael@0 218
michael@0 219 // Inherit states from input@type="file" suitable for the button. Note,
michael@0 220 // no special processing for unavailable state since inheritance is supplied
michael@0 221 // other code paths.
michael@0 222 if (mParent && mParent->IsHTMLFileInput()) {
michael@0 223 uint64_t parentState = mParent->State();
michael@0 224 state |= parentState & (states::BUSY | states::REQUIRED |
michael@0 225 states::HASPOPUP | states::INVALID);
michael@0 226 }
michael@0 227
michael@0 228 return state;
michael@0 229 }
michael@0 230
michael@0 231 uint64_t
michael@0 232 HTMLButtonAccessible::NativeState()
michael@0 233 {
michael@0 234 uint64_t state = HyperTextAccessibleWrap::NativeState();
michael@0 235
michael@0 236 EventStates elmState = mContent->AsElement()->State();
michael@0 237 if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
michael@0 238 state |= states::DEFAULT;
michael@0 239
michael@0 240 return state;
michael@0 241 }
michael@0 242
michael@0 243 role
michael@0 244 HTMLButtonAccessible::NativeRole()
michael@0 245 {
michael@0 246 return roles::PUSHBUTTON;
michael@0 247 }
michael@0 248
michael@0 249 ENameValueFlag
michael@0 250 HTMLButtonAccessible::NativeName(nsString& aName)
michael@0 251 {
michael@0 252 // No need to check @value attribute for buttons since this attribute results
michael@0 253 // in native anonymous text node and the name is calculated from subtree.
michael@0 254 // The same magic works for @alt and @value attributes in case of type="image"
michael@0 255 // element that has no valid @src (note if input@type="image" has an image
michael@0 256 // then neither @alt nor @value attributes are used to generate a visual label
michael@0 257 // and thus we need to obtain the accessible name directly from attribute
michael@0 258 // value). Also the same algorithm works in case of default labels for
michael@0 259 // type="submit"/"reset"/"image" elements.
michael@0 260
michael@0 261 ENameValueFlag nameFlag = Accessible::NativeName(aName);
michael@0 262 if (!aName.IsEmpty() || mContent->Tag() != nsGkAtoms::input ||
michael@0 263 !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
michael@0 264 nsGkAtoms::image, eCaseMatters))
michael@0 265 return nameFlag;
michael@0 266
michael@0 267 if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
michael@0 268 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
michael@0 269
michael@0 270 aName.CompressWhitespace();
michael@0 271 return eNameOK;
michael@0 272 }
michael@0 273
michael@0 274 ////////////////////////////////////////////////////////////////////////////////
michael@0 275 // HTMLButtonAccessible: Widgets
michael@0 276
michael@0 277 bool
michael@0 278 HTMLButtonAccessible::IsWidget() const
michael@0 279 {
michael@0 280 return true;
michael@0 281 }
michael@0 282
michael@0 283
michael@0 284 ////////////////////////////////////////////////////////////////////////////////
michael@0 285 // HTMLTextFieldAccessible
michael@0 286 ////////////////////////////////////////////////////////////////////////////////
michael@0 287
michael@0 288 HTMLTextFieldAccessible::
michael@0 289 HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 290 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 291 {
michael@0 292 mType = eHTMLTextFieldType;
michael@0 293 }
michael@0 294
michael@0 295 NS_IMPL_ISUPPORTS_INHERITED(HTMLTextFieldAccessible,
michael@0 296 Accessible,
michael@0 297 nsIAccessibleText,
michael@0 298 nsIAccessibleEditableText)
michael@0 299
michael@0 300 role
michael@0 301 HTMLTextFieldAccessible::NativeRole()
michael@0 302 {
michael@0 303 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
michael@0 304 nsGkAtoms::password, eIgnoreCase)) {
michael@0 305 return roles::PASSWORD_TEXT;
michael@0 306 }
michael@0 307
michael@0 308 return roles::ENTRY;
michael@0 309 }
michael@0 310
michael@0 311 already_AddRefed<nsIPersistentProperties>
michael@0 312 HTMLTextFieldAccessible::NativeAttributes()
michael@0 313 {
michael@0 314 nsCOMPtr<nsIPersistentProperties> attributes =
michael@0 315 HyperTextAccessibleWrap::NativeAttributes();
michael@0 316
michael@0 317 // Expose type for text input elements as it gives some useful context,
michael@0 318 // especially for mobile.
michael@0 319 nsAutoString type;
michael@0 320 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type))
michael@0 321 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
michael@0 322
michael@0 323 return attributes.forget();
michael@0 324 }
michael@0 325
michael@0 326 ENameValueFlag
michael@0 327 HTMLTextFieldAccessible::NativeName(nsString& aName)
michael@0 328 {
michael@0 329 ENameValueFlag nameFlag = Accessible::NativeName(aName);
michael@0 330 if (!aName.IsEmpty())
michael@0 331 return nameFlag;
michael@0 332
michael@0 333 // If part of compound of XUL widget then grab a name from XUL widget element.
michael@0 334 nsIContent* widgetElm = XULWidgetElm();
michael@0 335 if (widgetElm)
michael@0 336 XULElmName(mDoc, widgetElm, aName);
michael@0 337
michael@0 338 if (!aName.IsEmpty())
michael@0 339 return eNameOK;
michael@0 340
michael@0 341 // text inputs and textareas might have useful placeholder text
michael@0 342 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
michael@0 343 return eNameOK;
michael@0 344 }
michael@0 345
michael@0 346 void
michael@0 347 HTMLTextFieldAccessible::Value(nsString& aValue)
michael@0 348 {
michael@0 349 aValue.Truncate();
michael@0 350 if (NativeState() & states::PROTECTED) // Don't return password text!
michael@0 351 return;
michael@0 352
michael@0 353 nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
michael@0 354 if (textArea) {
michael@0 355 textArea->GetValue(aValue);
michael@0 356 return;
michael@0 357 }
michael@0 358
michael@0 359 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
michael@0 360 if (input)
michael@0 361 input->GetValue(aValue);
michael@0 362 }
michael@0 363
michael@0 364 void
michael@0 365 HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
michael@0 366 {
michael@0 367 HyperTextAccessibleWrap::ApplyARIAState(aState);
michael@0 368 aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
michael@0 369
michael@0 370 // If part of compound of XUL widget then pick up ARIA stuff from XUL widget
michael@0 371 // element.
michael@0 372 nsIContent* widgetElm = XULWidgetElm();
michael@0 373 if (widgetElm)
michael@0 374 aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
michael@0 375 }
michael@0 376
michael@0 377 uint64_t
michael@0 378 HTMLTextFieldAccessible::NativeState()
michael@0 379 {
michael@0 380 uint64_t state = HyperTextAccessibleWrap::NativeState();
michael@0 381
michael@0 382 // Text fields are always editable, even if they are also read only or
michael@0 383 // disabled.
michael@0 384 state |= states::EDITABLE;
michael@0 385
michael@0 386 // can be focusable, focused, protected. readonly, unavailable, selected
michael@0 387 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
michael@0 388 nsGkAtoms::password, eIgnoreCase)) {
michael@0 389 state |= states::PROTECTED;
michael@0 390 }
michael@0 391
michael@0 392 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
michael@0 393 state |= states::READONLY;
michael@0 394 }
michael@0 395
michael@0 396 // Is it an <input> or a <textarea> ?
michael@0 397 HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
michael@0 398 state |= input && input->IsSingleLineTextControl() ?
michael@0 399 states::SINGLE_LINE : states::MULTI_LINE;
michael@0 400
michael@0 401 if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY |
michael@0 402 states::UNAVAILABLE))
michael@0 403 return state;
michael@0 404
michael@0 405 // Expose autocomplete states if this input is part of autocomplete widget.
michael@0 406 Accessible* widget = ContainerWidget();
michael@0 407 if (widget && widget-IsAutoComplete()) {
michael@0 408 state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
michael@0 409 return state;
michael@0 410 }
michael@0 411
michael@0 412 // Expose autocomplete state if it has associated autocomplete list.
michael@0 413 if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
michael@0 414 return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
michael@0 415
michael@0 416 // Ordinal XUL textboxes don't support autocomplete.
michael@0 417 if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
michael@0 418 // Check to see if autocompletion is allowed on this input. We don't expose
michael@0 419 // it for password fields even though the entire password can be remembered
michael@0 420 // for a page if the user asks it to be. However, the kind of autocomplete
michael@0 421 // we're talking here is based on what the user types, where a popup of
michael@0 422 // possible choices comes up.
michael@0 423 nsAutoString autocomplete;
michael@0 424 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
michael@0 425 autocomplete);
michael@0 426
michael@0 427 if (!autocomplete.LowerCaseEqualsLiteral("off")) {
michael@0 428 nsIContent* formContent = input->GetFormElement();
michael@0 429 if (formContent) {
michael@0 430 formContent->GetAttr(kNameSpaceID_None,
michael@0 431 nsGkAtoms::autocomplete, autocomplete);
michael@0 432 }
michael@0 433
michael@0 434 if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
michael@0 435 state |= states::SUPPORTS_AUTOCOMPLETION;
michael@0 436 }
michael@0 437 }
michael@0 438
michael@0 439 return state;
michael@0 440 }
michael@0 441
michael@0 442 uint8_t
michael@0 443 HTMLTextFieldAccessible::ActionCount()
michael@0 444 {
michael@0 445 return 1;
michael@0 446 }
michael@0 447
michael@0 448 NS_IMETHODIMP
michael@0 449 HTMLTextFieldAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
michael@0 450 {
michael@0 451 if (aIndex == eAction_Click) {
michael@0 452 aName.AssignLiteral("activate");
michael@0 453 return NS_OK;
michael@0 454 }
michael@0 455 return NS_ERROR_INVALID_ARG;
michael@0 456 }
michael@0 457
michael@0 458 NS_IMETHODIMP
michael@0 459 HTMLTextFieldAccessible::DoAction(uint8_t aIndex)
michael@0 460 {
michael@0 461 if (aIndex == 0)
michael@0 462 return TakeFocus();
michael@0 463
michael@0 464 return NS_ERROR_INVALID_ARG;
michael@0 465 }
michael@0 466
michael@0 467 already_AddRefed<nsIEditor>
michael@0 468 HTMLTextFieldAccessible::GetEditor() const
michael@0 469 {
michael@0 470 nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
michael@0 471 if (!editableElt)
michael@0 472 return nullptr;
michael@0 473
michael@0 474 // nsGenericHTMLElement::GetEditor has a security check.
michael@0 475 // Make sure we're not restricted by the permissions of
michael@0 476 // whatever script is currently running.
michael@0 477 mozilla::dom::AutoNoJSAPI nojsapi;
michael@0 478
michael@0 479 nsCOMPtr<nsIEditor> editor;
michael@0 480 editableElt->GetEditor(getter_AddRefs(editor));
michael@0 481
michael@0 482 return editor.forget();
michael@0 483 }
michael@0 484
michael@0 485 ////////////////////////////////////////////////////////////////////////////////
michael@0 486 // HTMLTextFieldAccessible: Widgets
michael@0 487
michael@0 488 bool
michael@0 489 HTMLTextFieldAccessible::IsWidget() const
michael@0 490 {
michael@0 491 return true;
michael@0 492 }
michael@0 493
michael@0 494 Accessible*
michael@0 495 HTMLTextFieldAccessible::ContainerWidget() const
michael@0 496 {
michael@0 497 return mParent && mParent->Role() == roles::AUTOCOMPLETE ? mParent : nullptr;
michael@0 498 }
michael@0 499
michael@0 500
michael@0 501 ////////////////////////////////////////////////////////////////////////////////
michael@0 502 // HTMLFileInputAccessible
michael@0 503 ////////////////////////////////////////////////////////////////////////////////
michael@0 504
michael@0 505 HTMLFileInputAccessible::
michael@0 506 HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 507 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 508 {
michael@0 509 mType = eHTMLFileInputType;
michael@0 510 }
michael@0 511
michael@0 512 role
michael@0 513 HTMLFileInputAccessible::NativeRole()
michael@0 514 {
michael@0 515 // JAWS wants a text container, others don't mind. No specific role in
michael@0 516 // AT APIs.
michael@0 517 return roles::TEXT_CONTAINER;
michael@0 518 }
michael@0 519
michael@0 520 nsresult
michael@0 521 HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
michael@0 522 {
michael@0 523 nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent);
michael@0 524 NS_ENSURE_SUCCESS(rv, rv);
michael@0 525
michael@0 526 // Redirect state change events for inherited states to child controls. Note,
michael@0 527 // unavailable state is not redirected. That's a standard for unavailable
michael@0 528 // state handling.
michael@0 529 AccStateChangeEvent* event = downcast_accEvent(aEvent);
michael@0 530 if (event &&
michael@0 531 (event->GetState() == states::BUSY ||
michael@0 532 event->GetState() == states::REQUIRED ||
michael@0 533 event->GetState() == states::HASPOPUP ||
michael@0 534 event->GetState() == states::INVALID)) {
michael@0 535 Accessible* button = GetChildAt(0);
michael@0 536 if (button && button->Role() == roles::PUSHBUTTON) {
michael@0 537 nsRefPtr<AccStateChangeEvent> childEvent =
michael@0 538 new AccStateChangeEvent(button, event->GetState(),
michael@0 539 event->IsStateEnabled(), event->FromUserInput());
michael@0 540 nsEventShell::FireEvent(childEvent);
michael@0 541 }
michael@0 542 }
michael@0 543
michael@0 544 return NS_OK;
michael@0 545 }
michael@0 546
michael@0 547
michael@0 548 ////////////////////////////////////////////////////////////////////////////////
michael@0 549 // HTMLSpinnerAccessible
michael@0 550 ////////////////////////////////////////////////////////////////////////////////
michael@0 551
michael@0 552 role
michael@0 553 HTMLSpinnerAccessible::NativeRole()
michael@0 554 {
michael@0 555 return roles::SPINBUTTON;
michael@0 556 }
michael@0 557
michael@0 558 void
michael@0 559 HTMLSpinnerAccessible::Value(nsString& aValue)
michael@0 560 {
michael@0 561 AccessibleWrap::Value(aValue);
michael@0 562 if (!aValue.IsEmpty())
michael@0 563 return;
michael@0 564
michael@0 565 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
michael@0 566 }
michael@0 567
michael@0 568 double
michael@0 569 HTMLSpinnerAccessible::MaxValue() const
michael@0 570 {
michael@0 571 double value = AccessibleWrap::MaxValue();
michael@0 572 if (!IsNaN(value))
michael@0 573 return value;
michael@0 574
michael@0 575 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
michael@0 576 }
michael@0 577
michael@0 578
michael@0 579 double
michael@0 580 HTMLSpinnerAccessible::MinValue() const
michael@0 581 {
michael@0 582 double value = AccessibleWrap::MinValue();
michael@0 583 if (!IsNaN(value))
michael@0 584 return value;
michael@0 585
michael@0 586 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
michael@0 587 }
michael@0 588
michael@0 589 double
michael@0 590 HTMLSpinnerAccessible::Step() const
michael@0 591 {
michael@0 592 double value = AccessibleWrap::Step();
michael@0 593 if (!IsNaN(value))
michael@0 594 return value;
michael@0 595
michael@0 596 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
michael@0 597 }
michael@0 598
michael@0 599 double
michael@0 600 HTMLSpinnerAccessible::CurValue() const
michael@0 601 {
michael@0 602 double value = AccessibleWrap::CurValue();
michael@0 603 if (!IsNaN(value))
michael@0 604 return value;
michael@0 605
michael@0 606 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
michael@0 607 }
michael@0 608
michael@0 609 bool
michael@0 610 HTMLSpinnerAccessible::SetCurValue(double aValue)
michael@0 611 {
michael@0 612 ErrorResult er;
michael@0 613 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
michael@0 614 return !er.Failed();
michael@0 615 }
michael@0 616
michael@0 617
michael@0 618 ////////////////////////////////////////////////////////////////////////////////
michael@0 619 // HTMLRangeAccessible
michael@0 620 ////////////////////////////////////////////////////////////////////////////////
michael@0 621
michael@0 622 role
michael@0 623 HTMLRangeAccessible::NativeRole()
michael@0 624 {
michael@0 625 return roles::SLIDER;
michael@0 626 }
michael@0 627
michael@0 628 bool
michael@0 629 HTMLRangeAccessible::IsWidget() const
michael@0 630 {
michael@0 631 return true;
michael@0 632 }
michael@0 633
michael@0 634 void
michael@0 635 HTMLRangeAccessible::Value(nsString& aValue)
michael@0 636 {
michael@0 637 LeafAccessible::Value(aValue);
michael@0 638 if (!aValue.IsEmpty())
michael@0 639 return;
michael@0 640
michael@0 641 HTMLInputElement::FromContent(mContent)->GetValue(aValue);
michael@0 642 }
michael@0 643
michael@0 644 double
michael@0 645 HTMLRangeAccessible::MaxValue() const
michael@0 646 {
michael@0 647 double value = LeafAccessible::MaxValue();
michael@0 648 if (!IsNaN(value))
michael@0 649 return value;
michael@0 650
michael@0 651 return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
michael@0 652 }
michael@0 653
michael@0 654 double
michael@0 655 HTMLRangeAccessible::MinValue() const
michael@0 656 {
michael@0 657 double value = LeafAccessible::MinValue();
michael@0 658 if (!IsNaN(value))
michael@0 659 return value;
michael@0 660
michael@0 661 return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
michael@0 662 }
michael@0 663
michael@0 664 double
michael@0 665 HTMLRangeAccessible::Step() const
michael@0 666 {
michael@0 667 double value = LeafAccessible::Step();
michael@0 668 if (!IsNaN(value))
michael@0 669 return value;
michael@0 670
michael@0 671 return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
michael@0 672 }
michael@0 673
michael@0 674 double
michael@0 675 HTMLRangeAccessible::CurValue() const
michael@0 676 {
michael@0 677 double value = LeafAccessible::CurValue();
michael@0 678 if (!IsNaN(value))
michael@0 679 return value;
michael@0 680
michael@0 681 return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
michael@0 682 }
michael@0 683
michael@0 684 bool
michael@0 685 HTMLRangeAccessible::SetCurValue(double aValue)
michael@0 686 {
michael@0 687 ErrorResult er;
michael@0 688 HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
michael@0 689 return !er.Failed();
michael@0 690 }
michael@0 691
michael@0 692
michael@0 693 ////////////////////////////////////////////////////////////////////////////////
michael@0 694 // HTMLGroupboxAccessible
michael@0 695 ////////////////////////////////////////////////////////////////////////////////
michael@0 696
michael@0 697 HTMLGroupboxAccessible::
michael@0 698 HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 699 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 700 {
michael@0 701 }
michael@0 702
michael@0 703 role
michael@0 704 HTMLGroupboxAccessible::NativeRole()
michael@0 705 {
michael@0 706 return roles::GROUPING;
michael@0 707 }
michael@0 708
michael@0 709 nsIContent*
michael@0 710 HTMLGroupboxAccessible::GetLegend()
michael@0 711 {
michael@0 712 for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
michael@0 713 legendContent = legendContent->GetNextSibling()) {
michael@0 714 if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
michael@0 715 mContent->GetNameSpaceID())) {
michael@0 716 // Either XHTML namespace or no namespace
michael@0 717 return legendContent;
michael@0 718 }
michael@0 719 }
michael@0 720
michael@0 721 return nullptr;
michael@0 722 }
michael@0 723
michael@0 724 ENameValueFlag
michael@0 725 HTMLGroupboxAccessible::NativeName(nsString& aName)
michael@0 726 {
michael@0 727 ENameValueFlag nameFlag = Accessible::NativeName(aName);
michael@0 728 if (!aName.IsEmpty())
michael@0 729 return nameFlag;
michael@0 730
michael@0 731 nsIContent* legendContent = GetLegend();
michael@0 732 if (legendContent)
michael@0 733 nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
michael@0 734
michael@0 735 return eNameOK;
michael@0 736 }
michael@0 737
michael@0 738 Relation
michael@0 739 HTMLGroupboxAccessible::RelationByType(RelationType aType)
michael@0 740 {
michael@0 741 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
michael@0 742 // No override for label, so use <legend> for this <fieldset>
michael@0 743 if (aType == RelationType::LABELLED_BY)
michael@0 744 rel.AppendTarget(mDoc, GetLegend());
michael@0 745
michael@0 746 return rel;
michael@0 747 }
michael@0 748
michael@0 749 ////////////////////////////////////////////////////////////////////////////////
michael@0 750 // HTMLLegendAccessible
michael@0 751 ////////////////////////////////////////////////////////////////////////////////
michael@0 752
michael@0 753 HTMLLegendAccessible::
michael@0 754 HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 755 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 756 {
michael@0 757 }
michael@0 758
michael@0 759 Relation
michael@0 760 HTMLLegendAccessible::RelationByType(RelationType aType)
michael@0 761 {
michael@0 762 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
michael@0 763 if (aType != RelationType::LABEL_FOR)
michael@0 764 return rel;
michael@0 765
michael@0 766 Accessible* groupbox = Parent();
michael@0 767 if (groupbox && groupbox->Role() == roles::GROUPING)
michael@0 768 rel.AppendTarget(groupbox);
michael@0 769
michael@0 770 return rel;
michael@0 771 }
michael@0 772
michael@0 773 role
michael@0 774 HTMLLegendAccessible::NativeRole()
michael@0 775 {
michael@0 776 return roles::LABEL;
michael@0 777 }
michael@0 778
michael@0 779 ////////////////////////////////////////////////////////////////////////////////
michael@0 780 // HTMLFigureAccessible
michael@0 781 ////////////////////////////////////////////////////////////////////////////////
michael@0 782
michael@0 783 HTMLFigureAccessible::
michael@0 784 HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 785 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 786 {
michael@0 787 }
michael@0 788
michael@0 789 already_AddRefed<nsIPersistentProperties>
michael@0 790 HTMLFigureAccessible::NativeAttributes()
michael@0 791 {
michael@0 792 nsCOMPtr<nsIPersistentProperties> attributes =
michael@0 793 HyperTextAccessibleWrap::NativeAttributes();
michael@0 794
michael@0 795 // Expose figure xml-role.
michael@0 796 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
michael@0 797 NS_LITERAL_STRING("figure"));
michael@0 798 return attributes.forget();
michael@0 799 }
michael@0 800
michael@0 801 role
michael@0 802 HTMLFigureAccessible::NativeRole()
michael@0 803 {
michael@0 804 return roles::FIGURE;
michael@0 805 }
michael@0 806
michael@0 807 ENameValueFlag
michael@0 808 HTMLFigureAccessible::NativeName(nsString& aName)
michael@0 809 {
michael@0 810 ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
michael@0 811 if (!aName.IsEmpty())
michael@0 812 return nameFlag;
michael@0 813
michael@0 814 nsIContent* captionContent = Caption();
michael@0 815 if (captionContent)
michael@0 816 nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
michael@0 817
michael@0 818 return eNameOK;
michael@0 819 }
michael@0 820
michael@0 821 Relation
michael@0 822 HTMLFigureAccessible::RelationByType(RelationType aType)
michael@0 823 {
michael@0 824 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
michael@0 825 if (aType == RelationType::LABELLED_BY)
michael@0 826 rel.AppendTarget(mDoc, Caption());
michael@0 827
michael@0 828 return rel;
michael@0 829 }
michael@0 830
michael@0 831 nsIContent*
michael@0 832 HTMLFigureAccessible::Caption() const
michael@0 833 {
michael@0 834 for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
michael@0 835 childContent = childContent->GetNextSibling()) {
michael@0 836 if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
michael@0 837 mContent->GetNameSpaceID())) {
michael@0 838 return childContent;
michael@0 839 }
michael@0 840 }
michael@0 841
michael@0 842 return nullptr;
michael@0 843 }
michael@0 844
michael@0 845 ////////////////////////////////////////////////////////////////////////////////
michael@0 846 // HTMLFigcaptionAccessible
michael@0 847 ////////////////////////////////////////////////////////////////////////////////
michael@0 848
michael@0 849 HTMLFigcaptionAccessible::
michael@0 850 HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
michael@0 851 HyperTextAccessibleWrap(aContent, aDoc)
michael@0 852 {
michael@0 853 }
michael@0 854
michael@0 855 role
michael@0 856 HTMLFigcaptionAccessible::NativeRole()
michael@0 857 {
michael@0 858 return roles::CAPTION;
michael@0 859 }
michael@0 860
michael@0 861 Relation
michael@0 862 HTMLFigcaptionAccessible::RelationByType(RelationType aType)
michael@0 863 {
michael@0 864 Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
michael@0 865 if (aType != RelationType::LABEL_FOR)
michael@0 866 return rel;
michael@0 867
michael@0 868 Accessible* figure = Parent();
michael@0 869 if (figure &&
michael@0 870 figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
michael@0 871 mContent->GetNameSpaceID())) {
michael@0 872 rel.AppendTarget(figure);
michael@0 873 }
michael@0 874
michael@0 875 return rel;
michael@0 876 }

mercurial