The only nsGenericHTMLElement::GetEditor callers are HTMLInputElement::GetEditor/HTMLTextareaElement::GetEditor (the XPCOM-y versions), which are only called from C++ and only from two places: a11y code, which forces itself to look like system, and typeaheadfind, which would break badly if it could not get an editor. So that security check simply shouldn't exist. The script API doesn't call down into here _and_ is [ChromeOnly] in the webidl already.
837 lines
22 KiB
C++
837 lines
22 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "HTMLFormControlAccessible.h"
|
|
|
|
#include "Accessible-inl.h"
|
|
#include "nsAccUtils.h"
|
|
#include "nsEventShell.h"
|
|
#include "nsTextEquivUtils.h"
|
|
#include "Relation.h"
|
|
#include "Role.h"
|
|
#include "States.h"
|
|
|
|
#include "nsContentList.h"
|
|
#include "mozilla/dom/HTMLInputElement.h"
|
|
#include "nsIDOMNSEditableElement.h"
|
|
#include "nsIDOMHTMLTextAreaElement.h"
|
|
#include "nsIEditor.h"
|
|
#include "nsIFormControl.h"
|
|
#include "nsIPersistentProperties2.h"
|
|
#include "nsISelectionController.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsITextControlFrame.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "mozilla/dom/ScriptSettings.h"
|
|
|
|
#include "mozilla/EventStates.h"
|
|
#include "mozilla/FloatingPoint.h"
|
|
#include "mozilla/Preferences.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
using namespace mozilla::a11y;
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLCheckboxAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
role
|
|
HTMLCheckboxAccessible::NativeRole()
|
|
{
|
|
return roles::CHECKBUTTON;
|
|
}
|
|
|
|
uint8_t
|
|
HTMLCheckboxAccessible::ActionCount()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
HTMLCheckboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
|
|
{
|
|
if (aIndex == eAction_Click) { // 0 is the magic value for default action
|
|
uint64_t state = NativeState();
|
|
if (state & states::CHECKED)
|
|
aName.AssignLiteral("uncheck");
|
|
else if (state & states::MIXED)
|
|
aName.AssignLiteral("cycle");
|
|
else
|
|
aName.AssignLiteral("check");
|
|
}
|
|
}
|
|
|
|
bool
|
|
HTMLCheckboxAccessible::DoAction(uint8_t aIndex)
|
|
{
|
|
if (aIndex != 0)
|
|
return false;
|
|
|
|
DoCommand();
|
|
return true;
|
|
}
|
|
|
|
uint64_t
|
|
HTMLCheckboxAccessible::NativeState()
|
|
{
|
|
uint64_t state = LeafAccessible::NativeState();
|
|
|
|
state |= states::CHECKABLE;
|
|
HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
|
|
if (!input)
|
|
return state;
|
|
|
|
if (input->Indeterminate())
|
|
return state | states::MIXED;
|
|
|
|
if (input->Checked())
|
|
return state | states::CHECKED;
|
|
|
|
return state;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLCheckboxAccessible: Widgets
|
|
|
|
bool
|
|
HTMLCheckboxAccessible::IsWidget() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLRadioButtonAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
uint64_t
|
|
HTMLRadioButtonAccessible::NativeState()
|
|
{
|
|
uint64_t state = AccessibleWrap::NativeState();
|
|
|
|
state |= states::CHECKABLE;
|
|
|
|
HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
|
|
if (input && input->Checked())
|
|
state |= states::CHECKED;
|
|
|
|
return state;
|
|
}
|
|
|
|
void
|
|
HTMLRadioButtonAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
|
|
int32_t* aSetSize)
|
|
{
|
|
int32_t namespaceId = mContent->NodeInfo()->NamespaceID();
|
|
nsAutoString tagName;
|
|
mContent->NodeInfo()->GetName(tagName);
|
|
|
|
nsAutoString type;
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
|
|
nsAutoString name;
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
RefPtr<nsContentList> inputElms;
|
|
|
|
nsCOMPtr<nsIFormControl> formControlNode(do_QueryInterface(mContent));
|
|
dom::Element* formElm = formControlNode->GetFormElement();
|
|
if (formElm)
|
|
inputElms = NS_GetContentList(formElm, namespaceId, tagName);
|
|
else
|
|
inputElms = NS_GetContentList(mContent->OwnerDoc(), namespaceId, tagName);
|
|
NS_ENSURE_TRUE_VOID(inputElms);
|
|
|
|
uint32_t inputCount = inputElms->Length(false);
|
|
|
|
// Compute posinset and setsize.
|
|
int32_t indexOf = 0;
|
|
int32_t count = 0;
|
|
|
|
for (uint32_t index = 0; index < inputCount; index++) {
|
|
nsIContent* inputElm = inputElms->Item(index, false);
|
|
if (inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
|
type, eCaseMatters) &&
|
|
inputElm->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
|
|
name, eCaseMatters) && mDoc->HasAccessible(inputElm)) {
|
|
count++;
|
|
if (inputElm == mContent)
|
|
indexOf = count;
|
|
}
|
|
}
|
|
|
|
*aPosInSet = indexOf;
|
|
*aSetSize = count;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLButtonAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLButtonAccessible::
|
|
HTMLButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
mGenericTypes |= eButton;
|
|
}
|
|
|
|
uint8_t
|
|
HTMLButtonAccessible::ActionCount()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
HTMLButtonAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
|
|
{
|
|
if (aIndex == eAction_Click)
|
|
aName.AssignLiteral("press");
|
|
}
|
|
|
|
bool
|
|
HTMLButtonAccessible::DoAction(uint8_t aIndex)
|
|
{
|
|
if (aIndex != eAction_Click)
|
|
return false;
|
|
|
|
DoCommand();
|
|
return true;
|
|
}
|
|
|
|
uint64_t
|
|
HTMLButtonAccessible::State()
|
|
{
|
|
uint64_t state = HyperTextAccessibleWrap::State();
|
|
if (state == states::DEFUNCT)
|
|
return state;
|
|
|
|
// Inherit states from input@type="file" suitable for the button. Note,
|
|
// no special processing for unavailable state since inheritance is supplied
|
|
// other code paths.
|
|
if (mParent && mParent->IsHTMLFileInput()) {
|
|
uint64_t parentState = mParent->State();
|
|
state |= parentState & (states::BUSY | states::REQUIRED |
|
|
states::HASPOPUP | states::INVALID);
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
uint64_t
|
|
HTMLButtonAccessible::NativeState()
|
|
{
|
|
uint64_t state = HyperTextAccessibleWrap::NativeState();
|
|
|
|
EventStates elmState = mContent->AsElement()->State();
|
|
if (elmState.HasState(NS_EVENT_STATE_DEFAULT))
|
|
state |= states::DEFAULT;
|
|
|
|
return state;
|
|
}
|
|
|
|
role
|
|
HTMLButtonAccessible::NativeRole()
|
|
{
|
|
return roles::PUSHBUTTON;
|
|
}
|
|
|
|
ENameValueFlag
|
|
HTMLButtonAccessible::NativeName(nsString& aName)
|
|
{
|
|
// No need to check @value attribute for buttons since this attribute results
|
|
// in native anonymous text node and the name is calculated from subtree.
|
|
// The same magic works for @alt and @value attributes in case of type="image"
|
|
// element that has no valid @src (note if input@type="image" has an image
|
|
// then neither @alt nor @value attributes are used to generate a visual label
|
|
// and thus we need to obtain the accessible name directly from attribute
|
|
// value). Also the same algorithm works in case of default labels for
|
|
// type="submit"/"reset"/"image" elements.
|
|
|
|
ENameValueFlag nameFlag = Accessible::NativeName(aName);
|
|
if (!aName.IsEmpty() || !mContent->IsHTMLElement(nsGkAtoms::input) ||
|
|
!mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
|
nsGkAtoms::image, eCaseMatters))
|
|
return nameFlag;
|
|
|
|
if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::alt, aName))
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, aName);
|
|
|
|
aName.CompressWhitespace();
|
|
return eNameOK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLButtonAccessible: Widgets
|
|
|
|
bool
|
|
HTMLButtonAccessible::IsWidget() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLTextFieldAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLTextFieldAccessible::
|
|
HTMLTextFieldAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
mType = eHTMLTextFieldType;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED0(HTMLTextFieldAccessible,
|
|
HyperTextAccessible)
|
|
|
|
role
|
|
HTMLTextFieldAccessible::NativeRole()
|
|
{
|
|
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
|
nsGkAtoms::password, eIgnoreCase)) {
|
|
return roles::PASSWORD_TEXT;
|
|
}
|
|
|
|
return roles::ENTRY;
|
|
}
|
|
|
|
already_AddRefed<nsIPersistentProperties>
|
|
HTMLTextFieldAccessible::NativeAttributes()
|
|
{
|
|
nsCOMPtr<nsIPersistentProperties> attributes =
|
|
HyperTextAccessibleWrap::NativeAttributes();
|
|
|
|
// Expose type for text input elements as it gives some useful context,
|
|
// especially for mobile.
|
|
nsAutoString type;
|
|
if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
|
|
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::textInputType, type);
|
|
if (!ARIARoleMap() && type.EqualsLiteral("search")) {
|
|
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
|
|
NS_LITERAL_STRING("searchbox"));
|
|
}
|
|
}
|
|
|
|
return attributes.forget();
|
|
}
|
|
|
|
ENameValueFlag
|
|
HTMLTextFieldAccessible::NativeName(nsString& aName)
|
|
{
|
|
ENameValueFlag nameFlag = Accessible::NativeName(aName);
|
|
if (!aName.IsEmpty())
|
|
return nameFlag;
|
|
|
|
// If part of compound of XUL widget then grab a name from XUL widget element.
|
|
nsIContent* widgetElm = XULWidgetElm();
|
|
if (widgetElm)
|
|
XULElmName(mDoc, widgetElm, aName);
|
|
|
|
if (!aName.IsEmpty())
|
|
return eNameOK;
|
|
|
|
// text inputs and textareas might have useful placeholder text
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder, aName);
|
|
return eNameOK;
|
|
}
|
|
|
|
void
|
|
HTMLTextFieldAccessible::Value(nsString& aValue)
|
|
{
|
|
aValue.Truncate();
|
|
if (NativeState() & states::PROTECTED) // Don't return password text!
|
|
return;
|
|
|
|
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea(do_QueryInterface(mContent));
|
|
if (textArea) {
|
|
textArea->GetValue(aValue);
|
|
return;
|
|
}
|
|
|
|
HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
|
|
if (input)
|
|
input->GetValue(aValue);
|
|
}
|
|
|
|
void
|
|
HTMLTextFieldAccessible::ApplyARIAState(uint64_t* aState) const
|
|
{
|
|
HyperTextAccessibleWrap::ApplyARIAState(aState);
|
|
aria::MapToState(aria::eARIAAutoComplete, mContent->AsElement(), aState);
|
|
|
|
// If part of compound of XUL widget then pick up ARIA stuff from XUL widget
|
|
// element.
|
|
nsIContent* widgetElm = XULWidgetElm();
|
|
if (widgetElm)
|
|
aria::MapToState(aria::eARIAAutoComplete, widgetElm->AsElement(), aState);
|
|
}
|
|
|
|
uint64_t
|
|
HTMLTextFieldAccessible::NativeState()
|
|
{
|
|
uint64_t state = HyperTextAccessibleWrap::NativeState();
|
|
|
|
// Text fields are always editable, even if they are also read only or
|
|
// disabled.
|
|
state |= states::EDITABLE;
|
|
|
|
// can be focusable, focused, protected. readonly, unavailable, selected
|
|
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
|
nsGkAtoms::password, eIgnoreCase)) {
|
|
state |= states::PROTECTED;
|
|
}
|
|
|
|
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
|
|
state |= states::READONLY;
|
|
}
|
|
|
|
// Is it an <input> or a <textarea> ?
|
|
HTMLInputElement* input = HTMLInputElement::FromContent(mContent);
|
|
state |= input && input->IsSingleLineTextControl() ?
|
|
states::SINGLE_LINE : states::MULTI_LINE;
|
|
|
|
if (state & (states::PROTECTED | states::MULTI_LINE | states::READONLY |
|
|
states::UNAVAILABLE))
|
|
return state;
|
|
|
|
// Expose autocomplete states if this input is part of autocomplete widget.
|
|
Accessible* widget = ContainerWidget();
|
|
if (widget && widget-IsAutoComplete()) {
|
|
state |= states::HASPOPUP | states::SUPPORTS_AUTOCOMPLETION;
|
|
return state;
|
|
}
|
|
|
|
// Expose autocomplete state if it has associated autocomplete list.
|
|
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list))
|
|
return state | states::SUPPORTS_AUTOCOMPLETION | states::HASPOPUP;
|
|
|
|
// Ordinal XUL textboxes don't support autocomplete.
|
|
if (!XULWidgetElm() && Preferences::GetBool("browser.formfill.enable")) {
|
|
// Check to see if autocompletion is allowed on this input. We don't expose
|
|
// it for password fields even though the entire password can be remembered
|
|
// for a page if the user asks it to be. However, the kind of autocomplete
|
|
// we're talking here is based on what the user types, where a popup of
|
|
// possible choices comes up.
|
|
nsAutoString autocomplete;
|
|
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete,
|
|
autocomplete);
|
|
|
|
if (!autocomplete.LowerCaseEqualsLiteral("off")) {
|
|
nsIContent* formContent = input->GetFormElement();
|
|
if (formContent) {
|
|
formContent->GetAttr(kNameSpaceID_None,
|
|
nsGkAtoms::autocomplete, autocomplete);
|
|
}
|
|
|
|
if (!formContent || !autocomplete.LowerCaseEqualsLiteral("off"))
|
|
state |= states::SUPPORTS_AUTOCOMPLETION;
|
|
}
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
uint8_t
|
|
HTMLTextFieldAccessible::ActionCount()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
HTMLTextFieldAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
|
|
{
|
|
if (aIndex == eAction_Click)
|
|
aName.AssignLiteral("activate");
|
|
}
|
|
|
|
bool
|
|
HTMLTextFieldAccessible::DoAction(uint8_t aIndex)
|
|
{
|
|
if (aIndex != 0)
|
|
return false;
|
|
|
|
TakeFocus();
|
|
return true;
|
|
}
|
|
|
|
already_AddRefed<nsIEditor>
|
|
HTMLTextFieldAccessible::GetEditor() const
|
|
{
|
|
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mContent));
|
|
if (!editableElt)
|
|
return nullptr;
|
|
|
|
nsCOMPtr<nsIEditor> editor;
|
|
editableElt->GetEditor(getter_AddRefs(editor));
|
|
|
|
return editor.forget();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLTextFieldAccessible: Widgets
|
|
|
|
bool
|
|
HTMLTextFieldAccessible::IsWidget() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Accessible*
|
|
HTMLTextFieldAccessible::ContainerWidget() const
|
|
{
|
|
if (!mParent || mParent->Role() != roles::AUTOCOMPLETE) {
|
|
return nullptr;
|
|
}
|
|
return mParent;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLFileInputAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLFileInputAccessible::
|
|
HTMLFileInputAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
mType = eHTMLFileInputType;
|
|
}
|
|
|
|
role
|
|
HTMLFileInputAccessible::NativeRole()
|
|
{
|
|
// JAWS wants a text container, others don't mind. No specific role in
|
|
// AT APIs.
|
|
return roles::TEXT_CONTAINER;
|
|
}
|
|
|
|
nsresult
|
|
HTMLFileInputAccessible::HandleAccEvent(AccEvent* aEvent)
|
|
{
|
|
nsresult rv = HyperTextAccessibleWrap::HandleAccEvent(aEvent);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Redirect state change events for inherited states to child controls. Note,
|
|
// unavailable state is not redirected. That's a standard for unavailable
|
|
// state handling.
|
|
AccStateChangeEvent* event = downcast_accEvent(aEvent);
|
|
if (event &&
|
|
(event->GetState() == states::BUSY ||
|
|
event->GetState() == states::REQUIRED ||
|
|
event->GetState() == states::HASPOPUP ||
|
|
event->GetState() == states::INVALID)) {
|
|
Accessible* button = GetChildAt(0);
|
|
if (button && button->Role() == roles::PUSHBUTTON) {
|
|
RefPtr<AccStateChangeEvent> childEvent =
|
|
new AccStateChangeEvent(button, event->GetState(),
|
|
event->IsStateEnabled(), event->FromUserInput());
|
|
nsEventShell::FireEvent(childEvent);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLSpinnerAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
role
|
|
HTMLSpinnerAccessible::NativeRole()
|
|
{
|
|
return roles::SPINBUTTON;
|
|
}
|
|
|
|
void
|
|
HTMLSpinnerAccessible::Value(nsString& aValue)
|
|
{
|
|
AccessibleWrap::Value(aValue);
|
|
if (!aValue.IsEmpty())
|
|
return;
|
|
|
|
HTMLInputElement::FromContent(mContent)->GetValue(aValue);
|
|
}
|
|
|
|
double
|
|
HTMLSpinnerAccessible::MaxValue() const
|
|
{
|
|
double value = AccessibleWrap::MaxValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
|
|
}
|
|
|
|
|
|
double
|
|
HTMLSpinnerAccessible::MinValue() const
|
|
{
|
|
double value = AccessibleWrap::MinValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
|
|
}
|
|
|
|
double
|
|
HTMLSpinnerAccessible::Step() const
|
|
{
|
|
double value = AccessibleWrap::Step();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
|
|
}
|
|
|
|
double
|
|
HTMLSpinnerAccessible::CurValue() const
|
|
{
|
|
double value = AccessibleWrap::CurValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
|
|
}
|
|
|
|
bool
|
|
HTMLSpinnerAccessible::SetCurValue(double aValue)
|
|
{
|
|
ErrorResult er;
|
|
HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
|
|
return !er.Failed();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLRangeAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
role
|
|
HTMLRangeAccessible::NativeRole()
|
|
{
|
|
return roles::SLIDER;
|
|
}
|
|
|
|
bool
|
|
HTMLRangeAccessible::IsWidget() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void
|
|
HTMLRangeAccessible::Value(nsString& aValue)
|
|
{
|
|
LeafAccessible::Value(aValue);
|
|
if (!aValue.IsEmpty())
|
|
return;
|
|
|
|
HTMLInputElement::FromContent(mContent)->GetValue(aValue);
|
|
}
|
|
|
|
double
|
|
HTMLRangeAccessible::MaxValue() const
|
|
{
|
|
double value = LeafAccessible::MaxValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetMaximum().toDouble();
|
|
}
|
|
|
|
double
|
|
HTMLRangeAccessible::MinValue() const
|
|
{
|
|
double value = LeafAccessible::MinValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetMinimum().toDouble();
|
|
}
|
|
|
|
double
|
|
HTMLRangeAccessible::Step() const
|
|
{
|
|
double value = LeafAccessible::Step();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetStep().toDouble();
|
|
}
|
|
|
|
double
|
|
HTMLRangeAccessible::CurValue() const
|
|
{
|
|
double value = LeafAccessible::CurValue();
|
|
if (!IsNaN(value))
|
|
return value;
|
|
|
|
return HTMLInputElement::FromContent(mContent)->GetValueAsDecimal().toDouble();
|
|
}
|
|
|
|
bool
|
|
HTMLRangeAccessible::SetCurValue(double aValue)
|
|
{
|
|
ErrorResult er;
|
|
HTMLInputElement::FromContent(mContent)->SetValueAsNumber(aValue, er);
|
|
return !er.Failed();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLGroupboxAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLGroupboxAccessible::
|
|
HTMLGroupboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
}
|
|
|
|
role
|
|
HTMLGroupboxAccessible::NativeRole()
|
|
{
|
|
return roles::GROUPING;
|
|
}
|
|
|
|
nsIContent*
|
|
HTMLGroupboxAccessible::GetLegend() const
|
|
{
|
|
for (nsIContent* legendContent = mContent->GetFirstChild(); legendContent;
|
|
legendContent = legendContent->GetNextSibling()) {
|
|
if (legendContent->NodeInfo()->Equals(nsGkAtoms::legend,
|
|
mContent->GetNameSpaceID())) {
|
|
// Either XHTML namespace or no namespace
|
|
return legendContent;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ENameValueFlag
|
|
HTMLGroupboxAccessible::NativeName(nsString& aName)
|
|
{
|
|
ENameValueFlag nameFlag = Accessible::NativeName(aName);
|
|
if (!aName.IsEmpty())
|
|
return nameFlag;
|
|
|
|
nsIContent* legendContent = GetLegend();
|
|
if (legendContent)
|
|
nsTextEquivUtils::AppendTextEquivFromContent(this, legendContent, &aName);
|
|
|
|
return eNameOK;
|
|
}
|
|
|
|
Relation
|
|
HTMLGroupboxAccessible::RelationByType(RelationType aType)
|
|
{
|
|
Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
|
|
// No override for label, so use <legend> for this <fieldset>
|
|
if (aType == RelationType::LABELLED_BY)
|
|
rel.AppendTarget(mDoc, GetLegend());
|
|
|
|
return rel;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLLegendAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLLegendAccessible::
|
|
HTMLLegendAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
}
|
|
|
|
Relation
|
|
HTMLLegendAccessible::RelationByType(RelationType aType)
|
|
{
|
|
Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
|
|
if (aType != RelationType::LABEL_FOR)
|
|
return rel;
|
|
|
|
Accessible* groupbox = Parent();
|
|
if (groupbox && groupbox->Role() == roles::GROUPING)
|
|
rel.AppendTarget(groupbox);
|
|
|
|
return rel;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLFigureAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLFigureAccessible::
|
|
HTMLFigureAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
}
|
|
|
|
ENameValueFlag
|
|
HTMLFigureAccessible::NativeName(nsString& aName)
|
|
{
|
|
ENameValueFlag nameFlag = HyperTextAccessibleWrap::NativeName(aName);
|
|
if (!aName.IsEmpty())
|
|
return nameFlag;
|
|
|
|
nsIContent* captionContent = Caption();
|
|
if (captionContent)
|
|
nsTextEquivUtils::AppendTextEquivFromContent(this, captionContent, &aName);
|
|
|
|
return eNameOK;
|
|
}
|
|
|
|
Relation
|
|
HTMLFigureAccessible::RelationByType(RelationType aType)
|
|
{
|
|
Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
|
|
if (aType == RelationType::LABELLED_BY)
|
|
rel.AppendTarget(mDoc, Caption());
|
|
|
|
return rel;
|
|
}
|
|
|
|
nsIContent*
|
|
HTMLFigureAccessible::Caption() const
|
|
{
|
|
for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
|
|
childContent = childContent->GetNextSibling()) {
|
|
if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
|
|
mContent->GetNameSpaceID())) {
|
|
return childContent;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HTMLFigcaptionAccessible
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HTMLFigcaptionAccessible::
|
|
HTMLFigcaptionAccessible(nsIContent* aContent, DocAccessible* aDoc) :
|
|
HyperTextAccessibleWrap(aContent, aDoc)
|
|
{
|
|
}
|
|
|
|
Relation
|
|
HTMLFigcaptionAccessible::RelationByType(RelationType aType)
|
|
{
|
|
Relation rel = HyperTextAccessibleWrap::RelationByType(aType);
|
|
if (aType != RelationType::LABEL_FOR)
|
|
return rel;
|
|
|
|
Accessible* figure = Parent();
|
|
if (figure &&
|
|
figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
|
|
mContent->GetNameSpaceID())) {
|
|
rel.AppendTarget(figure);
|
|
}
|
|
|
|
return rel;
|
|
}
|