gecko-dev/accessible/generic/FormControlAccessible.cpp

270 lines
6.1 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/. */
// NOTE: alphabetically ordered
#include "FormControlAccessible.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/FloatingPoint.h"
#include "Role.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// ProgressMeterAccessible
////////////////////////////////////////////////////////////////////////////////
template class mozilla::a11y::ProgressMeterAccessible<1>;
template class mozilla::a11y::ProgressMeterAccessible<100>;
////////////////////////////////////////////////////////////////////////////////
// Accessible
template<int Max>
role
ProgressMeterAccessible<Max>::NativeRole() const
{
return roles::PROGRESSBAR;
}
template<int Max>
uint64_t
ProgressMeterAccessible<Max>::NativeState() const
{
uint64_t state = LeafAccessible::NativeState();
// An undetermined progressbar (i.e. without a value) has a mixed state.
nsAutoString attrValue;
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue);
if (attrValue.IsEmpty())
state |= states::MIXED;
return state;
}
////////////////////////////////////////////////////////////////////////////////
// ProgressMeterAccessible<Max>: Widgets
template<int Max>
bool
ProgressMeterAccessible<Max>::IsWidget() const
{
return true;
}
////////////////////////////////////////////////////////////////////////////////
// ProgressMeterAccessible<Max>: Value
template<int Max>
void
ProgressMeterAccessible<Max>::Value(nsString& aValue) const
{
LeafAccessible::Value(aValue);
if (!aValue.IsEmpty())
return;
double maxValue = MaxValue();
if (IsNaN(maxValue) || maxValue == 0)
return;
double curValue = CurValue();
if (IsNaN(curValue))
return;
// Treat the current value bigger than maximum as 100%.
double percentValue = (curValue < maxValue) ?
(curValue / maxValue) * 100 : 100;
aValue.AppendFloat(percentValue);
aValue.Append('%');
}
template<int Max>
double
ProgressMeterAccessible<Max>::MaxValue() const
{
double value = LeafAccessible::MaxValue();
if (!IsNaN(value))
return value;
nsAutoString strValue;
if (mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::max, strValue)) {
nsresult result = NS_OK;
value = strValue.ToDouble(&result);
if (NS_SUCCEEDED(result))
return value;
}
return Max;
}
template<int Max>
double
ProgressMeterAccessible<Max>::MinValue() const
{
double value = LeafAccessible::MinValue();
return IsNaN(value) ? 0 : value;
}
template<int Max>
double
ProgressMeterAccessible<Max>::Step() const
{
double value = LeafAccessible::Step();
return IsNaN(value) ? 0 : value;
}
template<int Max>
double
ProgressMeterAccessible<Max>::CurValue() const
{
double value = LeafAccessible::CurValue();
if (!IsNaN(value))
return value;
nsAutoString attrValue;
if (!mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::value, attrValue))
return UnspecifiedNaN<double>();
nsresult error = NS_OK;
value = attrValue.ToDouble(&error);
return NS_FAILED(error) ? UnspecifiedNaN<double>() : value;
}
template<int Max>
bool
ProgressMeterAccessible<Max>::SetCurValue(double aValue)
{
return false; // progress meters are readonly.
}
////////////////////////////////////////////////////////////////////////////////
// CheckboxAccessible
////////////////////////////////////////////////////////////////////////////////
role
CheckboxAccessible::NativeRole() const
{
return roles::CHECKBUTTON;
}
uint8_t
CheckboxAccessible::ActionCount() const
{
return 1;
}
void
CheckboxAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
{
if (aIndex == eAction_Click) {
uint64_t state = NativeState();
if (state & states::CHECKED) {
aName.AssignLiteral("uncheck");
} else if (state & states::MIXED) {
aName.AssignLiteral("cycle");
} else {
aName.AssignLiteral("check");
}
}
}
bool
CheckboxAccessible::DoAction(uint8_t aIndex) const
{
if (aIndex != eAction_Click) {
return false;
}
DoCommand();
return true;
}
uint64_t
CheckboxAccessible::NativeState() const
{
uint64_t state = LeafAccessible::NativeState();
state |= states::CHECKABLE;
dom::HTMLInputElement* input = dom::HTMLInputElement::FromNode(mContent);
if (input) { // HTML:input@type="checkbox"
if (input->Indeterminate()) {
return state | states::MIXED;
}
if (input->Checked()) {
return state | states::CHECKED;
}
} else if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::checked,
nsGkAtoms::_true,
eCaseMatters)) { // XUL checkbox
return state | states::CHECKED;
}
return state;
}
////////////////////////////////////////////////////////////////////////////////
// CheckboxAccessible: Widgets
bool
CheckboxAccessible::IsWidget() const
{
return true;
}
////////////////////////////////////////////////////////////////////////////////
// RadioButtonAccessible
////////////////////////////////////////////////////////////////////////////////
RadioButtonAccessible::
RadioButtonAccessible(nsIContent* aContent, DocAccessible* aDoc) :
LeafAccessible(aContent, aDoc)
{
}
uint8_t
RadioButtonAccessible::ActionCount() const
{
return 1;
}
void
RadioButtonAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
{
if (aIndex == eAction_Click)
aName.AssignLiteral("select");
}
bool
RadioButtonAccessible::DoAction(uint8_t aIndex) const
{
if (aIndex != eAction_Click)
return false;
DoCommand();
return true;
}
role
RadioButtonAccessible::NativeRole() const
{
return roles::RADIOBUTTON;
}
////////////////////////////////////////////////////////////////////////////////
// RadioButtonAccessible: Widgets
bool
RadioButtonAccessible::IsWidget() const
{
return true;
}