HTMLFormControlAccessible.cpp 22 KB

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