1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/accessibility/AXRadioInput.h"
#include "core/InputTypeNames.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/forms/RadioInputType.h"
#include "core/layout/LayoutObject.h"
#include "modules/accessibility/AXObjectCacheImpl.h"
namespace blink {
using namespace HTMLNames;
AXRadioInput::AXRadioInput(LayoutObject* layoutObject,
AXObjectCacheImpl& axObjectCache)
: AXLayoutObject(layoutObject, axObjectCache) {
// Updates posInSet and setSize for the current object and the next objects.
if (!calculatePosInSet())
return;
// When a new object is inserted, it needs to update setSize for the previous
// objects.
requestUpdateToNextNode(false);
}
AXRadioInput* AXRadioInput::create(LayoutObject* layoutObject,
AXObjectCacheImpl& axObjectCache) {
return new AXRadioInput(layoutObject, axObjectCache);
}
void AXRadioInput::updatePosAndSetSize(int position) {
if (position)
m_posInSet = position;
m_setSize = sizeOfRadioGroup();
}
void AXRadioInput::requestUpdateToNextNode(bool forward) {
HTMLInputElement* nextElement =
RadioInputType::nextRadioButtonInGroup(element(), forward);
AXObject* nextAXobject = axObjectCache().get(nextElement);
if (!nextAXobject || !nextAXobject->isAXRadioInput())
return;
int position = 0;
if (forward)
position = posInSet() + 1;
// If it is backward, it keeps position as positions are already assigned for
// previous objects. updatePosAndSetSize() is called with '0' and it doesn't
// modify m_posInSet and updates m_setSize as size is increased.
toAXRadioInput(nextAXobject)->updatePosAndSetSize(position);
axObjectCache().postNotification(nextAXobject,
AXObjectCacheImpl::AXAriaAttributeChanged);
toAXRadioInput(nextAXobject)->requestUpdateToNextNode(forward);
}
HTMLInputElement* AXRadioInput::findFirstRadioButtonInGroup(
HTMLInputElement* current) const {
while (HTMLInputElement* prevElement =
RadioInputType::nextRadioButtonInGroup(current, false))
current = prevElement;
return current;
}
int AXRadioInput::posInSet() const {
if (hasAttribute(aria_posinsetAttr))
return getAttribute(aria_posinsetAttr).toInt();
return m_posInSet;
}
int AXRadioInput::setSize() const {
if (hasAttribute(aria_setsizeAttr))
return getAttribute(aria_setsizeAttr).toInt();
return m_setSize;
}
bool AXRadioInput::calculatePosInSet() {
// Calculate 'posInSet' attribute when AXRadioInputs need to be updated
// as a new AXRadioInput Object is added or one of objects from RadioGroup is
// removed.
bool needToUpdatePrev = false;
int position = 1;
HTMLInputElement* prevElement =
RadioInputType::nextRadioButtonInGroup(element(), false);
if (prevElement) {
AXObject* object = axObjectCache().get(prevElement);
// If the previous element doesn't have AXObject yet, caculate position from
// the first element. Otherwise, get position from the previous AXObject.
if (!object || !object->isAXRadioInput()) {
position = countFromFirstElement();
} else {
position = object->posInSet() + 1;
// It returns true if previous objects need to be updated.
// When AX tree exists already and a new node is inserted,
// as updating is started from the inserted node,
// we need to update setSize for previous nodes.
if (setSize() != object->setSize())
needToUpdatePrev = true;
}
}
updatePosAndSetSize(position);
// If it is not the last element, request update to the next node.
if (position != setSize())
requestUpdateToNextNode(true);
return needToUpdatePrev;
}
int AXRadioInput::countFromFirstElement() const {
int count = 1;
HTMLInputElement* current = element();
while (HTMLInputElement* prevElement =
RadioInputType::nextRadioButtonInGroup(current, false)) {
current = prevElement;
count++;
}
return count;
}
HTMLInputElement* AXRadioInput::element() const {
return toHTMLInputElement(m_layoutObject->node());
}
int AXRadioInput::sizeOfRadioGroup() const {
int size = element()->sizeOfRadioGroup();
// If it has no size in Group, it means that there is only itself.
if (!size)
return 1;
return size;
}
} // namespace blink
|