accessible/generic/FormControlAccessible.cpp
author Cameron McCormack <cam@mcc.id.au>
Tue, 09 Oct 2018 08:49:51 +0000
changeset 499661 18a3482ffcbac7c1b7c1b4f16246665baeab2971
parent 491558 0af181b51b7638ea9990717ace6c09436a955607
child 506617 0f64862fa1c318d5efd7005a4fb45854351023c7
permissions -rw-r--r--
Bug 1497406 - Use helper function to set length and copy into nsTArrays of PODs from Rust r=boris Differential Revision: https://phabricator.services.mozilla.com/D8058

/* -*- 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;
}