accessible/src/html/HTMLFormControlAccessible.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial