Diff
Modified: trunk/LayoutTests/ChangeLog (131870 => 131871)
--- trunk/LayoutTests/ChangeLog 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/LayoutTests/ChangeLog 2012-10-19 08:01:06 UTC (rev 131871)
@@ -1,3 +1,23 @@
+2012-10-18 Dominic Mazzoni <[email protected]>
+
+ AX: labelForElement is slow when there are a lot of DOM elements
+ https://bugs.webkit.org/show_bug.cgi?id=97825
+
+ Reviewed by Ryosuke Niwa.
+
+ Adds two new tests for titleUIElement that run on both Mac and
+ Chromium. One tests correctness, the other tests speed.
+
+ Fixes one test so that it passes on Chromium.
+ Enables other tests that now pass on Chromium.
+
+ * accessibility/secure-textfield-title-ui.html:
+ * accessibility/title-ui-element-correctness-expected.txt: Added.
+ * accessibility/title-ui-element-correctness.html: Added.
+ * perf/accessibility-title-ui-element-expected.txt: Added.
+ * perf/accessibility-title-ui-element.html: Added.
+ * platform/chromium/TestExpectations:
+
2012-10-18 Alexander Pavlov <[email protected]>
Web Inspector: [Styles] Property considered overridden if it is non-inherited important property in inherited style
Modified: trunk/LayoutTests/accessibility/secure-textfield-title-ui.html (131870 => 131871)
--- trunk/LayoutTests/accessibility/secure-textfield-title-ui.html 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/LayoutTests/accessibility/secure-textfield-title-ui.html 2012-10-19 08:01:06 UTC (rev 131871)
@@ -21,8 +21,7 @@
pass.focus();
var titleUIElement = accessibilityController.focusedElement.titleUIElement();
var titleText = titleUIElement.childAtIndex(0);
- var pattern = "AXValue: Password";
- if (titleText.allAttributes().indexOf(pattern) != -1) {
+ if (titleText.stringValue == "AXValue: Password") {
result.innerText += "Test passed\n";
}
else {
Added: trunk/LayoutTests/accessibility/title-ui-element-correctness-expected.txt (0 => 131871)
--- trunk/LayoutTests/accessibility/title-ui-element-correctness-expected.txt (rev 0)
+++ trunk/LayoutTests/accessibility/title-ui-element-correctness-expected.txt 2012-10-19 08:01:06 UTC (rev 131871)
@@ -0,0 +1,23 @@
+This tests that titleUIElement works correctly even when things change dynamically.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS axElement('control1').titleUIElement().isEqual(axElement('label1')) is true
+PASS axElement('control2').titleUIElement().isEqual(axElement('label2')) is true
+PASS hasTitleUIElement(axElement('control3')) is false
+PASS document.getElementById('label3').setAttribute('for', 'control3'); axElement('control3').titleUIElement().isEqual(axElement('label3')) is true
+PASS var label4Element = createLabelWithIdAndForAttribute('label4', 'control4'); hasTitleUIElement(axElement('control4')) is false
+PASS document.getElementById('container').appendChild(label4Element); hasTitleUIElement(axElement('control4')) is true
+PASS axElement('control4').titleUIElement().isEqual(axElement('label4')) is true
+PASS label4Element.parentElement.removeChild(label4Element); hasTitleUIElement(axElement('control4')) is false
+PASS hasTitleUIElement(axElement('control5')) is false
+PASS reparentNodeIntoContainer(document.getElementById('control5'), document.getElementById('label5')); axElement('control5').titleUIElement() != null is true
+PASS axElement('control5').titleUIElement().isEqual(axElement('label5')) is true
+PASS axElement('control6').titleUIElement().isEqual(axElement('label6b')) is true
+PASS newLabel6Element = createLabelWithIdAndForAttribute('label6a', 'control6'); document.body.insertBefore(newLabel6Element, document.body.firstChild); axElement('control6').titleUIElement().isEqual(axElement('label6a')) is true
+PASS document.body.removeChild(newLabel6Element); axElement('control6').titleUIElement().isEqual(axElement('label6b')) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/accessibility/title-ui-element-correctness-expected.txt
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/accessibility/title-ui-element-correctness.html (0 => 131871)
--- trunk/LayoutTests/accessibility/title-ui-element-correctness.html (rev 0)
+++ trunk/LayoutTests/accessibility/title-ui-element-correctness.html 2012-10-19 08:01:06 UTC (rev 131871)
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script src=""
+
+<div id="container">
+
+ <div>
+ <label id="label1" for="" 1</label>
+ <input id="control1" type="text">
+ </div>
+
+ <div>
+ <label id="label2">
+ Label 2
+ <input id="control2" type="text">
+ </label>
+ </div>
+
+ <div>
+ <label id="label3">Label 3</label>
+ <input id="control3" type="text">
+ </div>
+
+ <div>
+ <input id="control4" type="text">
+ </div>
+
+ <div>
+ <label id="label5">
+ Label 5
+ </label>
+ <input id="control5" type="text">
+ </div>
+
+ <div>
+ <label id="label6b" for="" 6b</label>
+ <label id="label6c" for="" 6c</label>
+ <input id="control6" type="text">
+ </div>
+</div>
+
+<div id="console"></div>
+<script>
+description("This tests that titleUIElement works correctly even when things change dynamically.");
+
+if (window.testRunner && window.accessibilityController) {
+ testRunner.dumpAsText();
+
+ function hasTitleUIElement(axElement) {
+ var label1 = accessibilityController.accessibleElementById("label1");
+ var titleUIElement = axElement.titleUIElement();
+ if (titleUIElement == null)
+ return false;
+ return titleUIElement.role == label1.role;
+ }
+
+ function createLabelWithIdAndForAttribute(id, forAttributeValue) {
+ var labelElement = document.createElement("label");
+ labelElement.id = id;
+ labelElement.setAttribute("for", forAttributeValue);
+ labelElement.innerText = "Label for " + forAttributeValue;
+ return labelElement;
+ }
+
+ function reparentNodeIntoContainer(node, container) {
+ node.parentElement.removeChild(node);
+ container.appendChild(node);
+ }
+
+ function axElement(id) {
+ return accessibilityController.accessibleElementById(id);
+ }
+
+ shouldBe("axElement('control1').titleUIElement().isEqual(axElement('label1'))", "true");
+
+ shouldBe("axElement('control2').titleUIElement().isEqual(axElement('label2'))", "true");
+
+ // Test changing the "for" attribute dynamically.
+ shouldBe("hasTitleUIElement(axElement('control3'))", "false");
+ shouldBe("document.getElementById('label3').setAttribute('for', 'control3'); axElement('control3').titleUIElement().isEqual(axElement('label3'))", "true");
+
+ // Test unattached label element that's subsequently attached.
+ var label4Element = document.createElement("label");
+ label4Element.id = "label4";
+ label4Element.setAttribute("for", "control4");
+ label4Element.innerText = "Label 4";
+ shouldBe("var label4Element = createLabelWithIdAndForAttribute('label4', 'control4'); hasTitleUIElement(axElement('control4'))", "false");
+ shouldBe("document.getElementById('container').appendChild(label4Element); hasTitleUIElement(axElement('control4'))", "true");
+ shouldBe("axElement('control4').titleUIElement().isEqual(axElement('label4'))", "true");
+
+ // Test what happens when the label is detached.
+ shouldBe("label4Element.parentElement.removeChild(label4Element); hasTitleUIElement(axElement('control4'))", "false");
+
+ // Test label that gets a control reparented into it.
+ shouldBe("hasTitleUIElement(axElement('control5'))", "false");
+
+ shouldBe("reparentNodeIntoContainer(document.getElementById('control5'), document.getElementById('label5')); axElement('control5').titleUIElement() != null", "true");
+ shouldBe("axElement('control5').titleUIElement().isEqual(axElement('label5'))", "true");
+
+ // Make sure the first label is returned, even as labels are added and removed.
+ shouldBe("axElement('control6').titleUIElement().isEqual(axElement('label6b'))", "true");
+ shouldBe("newLabel6Element = createLabelWithIdAndForAttribute('label6a', 'control6'); document.body.insertBefore(newLabel6Element, document.body.firstChild); axElement('control6').titleUIElement().isEqual(axElement('label6a'))", "true");
+ shouldBe("document.body.removeChild(newLabel6Element); axElement('control6').titleUIElement().isEqual(axElement('label6b'))", "true");
+
+ document.getElementById('container').style.display = 'none';
+}
+
+</script>
+
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/accessibility/title-ui-element-correctness.html
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/perf/accessibility-title-ui-element-expected.txt (0 => 131871)
--- trunk/LayoutTests/perf/accessibility-title-ui-element-expected.txt (rev 0)
+++ trunk/LayoutTests/perf/accessibility-title-ui-element-expected.txt 2012-10-19 08:01:06 UTC (rev 131871)
@@ -0,0 +1,3 @@
+Tests that titleUIElement on an accessibility element runs in amortized constant time.
+PASS
+
Property changes on: trunk/LayoutTests/perf/accessibility-title-ui-element-expected.txt
___________________________________________________________________
Added: svn:eol-style
Added: trunk/LayoutTests/perf/accessibility-title-ui-element.html (0 => 131871)
--- trunk/LayoutTests/perf/accessibility-title-ui-element.html (rev 0)
+++ trunk/LayoutTests/perf/accessibility-title-ui-element.html 2012-10-19 08:01:06 UTC (rev 131871)
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+
+var parentContainer;
+var axControl;
+
+function endsWith(str, suffix) {
+ return str.substr(str.length - suffix.length) == suffix;
+}
+
+function setup(magnitude) {
+ if (parentContainer)
+ document.body.removeChild(parentContainer);
+ parentContainer = document.createElement('div');
+ document.body.appendChild(parentContainer);
+
+ var junkContainer = document.createElement('div');
+ parentContainer.appendChild(junkContainer);
+
+ var label = document.createElement('label');
+ label.setAttribute('for', 'control');
+ label.innerText = 'Label';
+ parentContainer.appendChild(label);
+
+ var control = document.createElement('input');
+ control.type = 'text';
+ control.id = 'control';
+ parentContainer.appendChild(control);
+
+ parentContainer.offsetLeft;
+ axControl = accessibilityController.accessibleElementById('control');
+
+ for (var i = 0; i < 10 * magnitude; ++i) {
+ var div = document.createElement('div');
+ div.innerHTML = "<p></p><p></p><p></p><p></p><p></p>";
+ junkContainer.appendChild(div);
+ }
+ parentContainer.offsetLeft;
+}
+
+function test(magnitude) {
+ for (var i = 0; i < 100; i++) {
+ axControl.titleUIElement();
+ }
+}
+
+Magnitude.description("Tests that titleUIElement on an accessibility element runs in amortized constant time.");
+Magnitude.run(setup, test, Magnitude.CONSTANT);
+</script>
+</body>
+</html>
Property changes on: trunk/LayoutTests/perf/accessibility-title-ui-element.html
___________________________________________________________________
Added: svn:eol-style
Modified: trunk/LayoutTests/platform/chromium/TestExpectations (131870 => 131871)
--- trunk/LayoutTests/platform/chromium/TestExpectations 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/LayoutTests/platform/chromium/TestExpectations 2012-10-19 08:01:06 UTC (rev 131871)
@@ -1402,14 +1402,11 @@
crbug.com/10322 accessibility/legend.html [ Skip ]
crbug.com/10322 accessibility/lists.html [ Skip ]
crbug.com/10322 accessibility/media-element.html [ Skip ]
-crbug.com/10322 accessibility/non-data-table-cell-title-ui-element.html [ Skip ]
crbug.com/10322 accessibility/onclick-handlers.html [ Skip ]
crbug.com/10322 accessibility/placeholder.html [ Skip ]
crbug.com/10322 accessibility/plugin.html [ Skip ]
crbug.com/10322 accessibility/radio-button-checkbox-size.html [ Skip ]
crbug.com/10322 accessibility/radio-button-group-members.html [ Skip ]
-crbug.com/10322 accessibility/radio-button-title-label.html [ Skip ]
-crbug.com/10322 accessibility/secure-textfield-title-ui.html [ Skip ]
crbug.com/10322 accessibility/table-attributes.html [ Skip ]
crbug.com/10322 accessibility/table-cell-spans.html [ Skip ]
crbug.com/10322 accessibility/table-cells.html [ Skip ]
@@ -1418,7 +1415,6 @@
crbug.com/10322 accessibility/table-sections.html [ Skip ]
crbug.com/10322 accessibility/table-with-aria-role.html [ Skip ]
crbug.com/10322 accessibility/table-with-rules.html [ Skip ]
-crbug.com/10322 accessibility/th-as-title-ui.html [ Skip ]
crbug.com/10322 accessibility/transformed-element.html [ Skip ]
crbug.com/10322 accessibility/visible-elements.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (131870 => 131871)
--- trunk/Source/WebCore/ChangeLog 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/ChangeLog 2012-10-19 08:01:06 UTC (rev 131871)
@@ -1,3 +1,47 @@
+2012-10-18 Dominic Mazzoni <[email protected]>
+
+ AX: labelForElement is slow when there are a lot of DOM elements
+ https://bugs.webkit.org/show_bug.cgi?id=97825
+
+ Reviewed by Ryosuke Niwa.
+
+ Adds a DocumentOrderedMap to TreeScope that allows accessibility to
+ quickly map from an id to the label for that id. This speeds up
+ AccessibilityNode::labelForElement, which was a bottleneck in Chromium
+ when accessibility was on.
+
+ Tests: accessibility/title-ui-element-correctness.html
+ perf/accessibility-title-ui-element.html
+
+ * accessibility/AccessibilityNodeObject.cpp:
+ (WebCore::AccessibilityNodeObject::labelForElement):
+ * dom/DocumentOrderedMap.cpp:
+ (WebCore::keyMatchesLabelForAttribute):
+ (WebCore):
+ (WebCore::DocumentOrderedMap::get):
+ (WebCore::DocumentOrderedMap::getElementByLabelForAttribute):
+ * dom/DocumentOrderedMap.h:
+ (DocumentOrderedMap):
+ * dom/Element.cpp:
+ (WebCore::Element::insertedInto):
+ (WebCore::Element::removedFrom):
+ (WebCore::Element::updateLabel):
+ (WebCore):
+ (WebCore::Element::willModifyAttribute):
+ * dom/Element.h:
+ (Element):
+ * dom/TreeScope.cpp:
+ (WebCore::TreeScope::TreeScope):
+ (WebCore::TreeScope::destroyTreeScopeData):
+ (WebCore::TreeScope::addLabel):
+ (WebCore):
+ (WebCore::TreeScope::removeLabel):
+ (WebCore::TreeScope::labelElementForId):
+ * dom/TreeScope.h:
+ (WebCore):
+ (TreeScope):
+ (WebCore::TreeScope::shouldCacheLabelsByForAttribute):
+
2012-10-19 Eugene Klyuchnikov <[email protected]>
Web Inspector: Update localizedStrings.js
Modified: trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp (131870 => 131871)
--- trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -59,6 +59,7 @@
#include "HTMLTextFormControlElement.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
+#include "LabelableElement.h"
#include "LocalizedStrings.h"
#include "MathMLNames.h"
#include "NodeList.h"
@@ -1001,16 +1002,20 @@
HTMLLabelElement* AccessibilityNodeObject::labelForElement(Element* element) const
{
- RefPtr<NodeList> list = element->document()->getElementsByTagName("label");
- unsigned len = list->length();
- for (unsigned i = 0; i < len; i++) {
- if (list->item(i)->hasTagName(labelTag)) {
- HTMLLabelElement* label = static_cast<HTMLLabelElement*>(list->item(i));
- if (label->control() == element)
- return label;
- }
+ if (!element->isHTMLElement() || !toHTMLElement(element)->isLabelable())
+ return 0;
+
+ const AtomicString& id = element->getIdAttribute();
+ if (!id.isEmpty()) {
+ if (HTMLLabelElement* label = element->treeScope()->labelElementForId(id))
+ return label;
}
+ for (Element* parent = element->parentElement(); parent; parent = parent->parentElement()) {
+ if (parent->hasTagName(labelTag))
+ return static_cast<HTMLLabelElement*>(parent);
+ }
+
return 0;
}
Modified: trunk/Source/WebCore/dom/DocumentOrderedMap.cpp (131870 => 131871)
--- trunk/Source/WebCore/dom/DocumentOrderedMap.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/DocumentOrderedMap.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -55,6 +55,11 @@
return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().lower().impl() == key;
}
+inline bool keyMatchesLabelForAttribute(AtomicStringImpl* key, Element* element)
+{
+ return element->hasTagName(labelTag) && element->getAttribute(forAttr).impl() == key;
+}
+
void DocumentOrderedMap::clear()
{
m_map.clear();
@@ -149,5 +154,9 @@
return get<keyMatchesLowercasedMapName>(key, scope);
}
+Element* DocumentOrderedMap::getElementByLabelForAttribute(AtomicStringImpl* key, const TreeScope* scope) const
+{
+ return get<keyMatchesLabelForAttribute>(key, scope);
+}
+
} // namespace WebCore
-
Modified: trunk/Source/WebCore/dom/DocumentOrderedMap.h (131870 => 131871)
--- trunk/Source/WebCore/dom/DocumentOrderedMap.h 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/DocumentOrderedMap.h 2012-10-19 08:01:06 UTC (rev 131871)
@@ -52,6 +52,7 @@
Element* getElementById(AtomicStringImpl*, const TreeScope*) const;
Element* getElementByMapName(AtomicStringImpl*, const TreeScope*) const;
Element* getElementByLowercasedMapName(AtomicStringImpl*, const TreeScope*) const;
+ Element* getElementByLabelForAttribute(AtomicStringImpl*, const TreeScope*) const;
void checkConsistency() const;
@@ -80,4 +81,3 @@
} // namespace WebCore
#endif // DocumentOrderedMap_h
-
Modified: trunk/Source/WebCore/dom/Element.cpp (131870 => 131871)
--- trunk/Source/WebCore/dom/Element.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/Element.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -48,6 +48,7 @@
#include "HTMLElement.h"
#include "HTMLFormCollection.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTMLLabelElement.h"
#include "HTMLNames.h"
#include "HTMLOptionsCollection.h"
#include "HTMLParserIdioms.h"
@@ -959,6 +960,12 @@
if (!nameValue.isNull())
updateName(nullAtom, nameValue);
+ if (hasTagName(labelTag)) {
+ TreeScope* scope = treeScope();
+ if (scope->shouldCacheLabelsByForAttribute())
+ updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
+ }
+
return InsertionDone;
}
@@ -983,6 +990,12 @@
const AtomicString& nameValue = getNameAttribute();
if (!nameValue.isNull())
updateName(nameValue, nullAtom);
+
+ if (hasTagName(labelTag)) {
+ TreeScope* treeScope = insertionPoint->treeScope();
+ if (treeScope->shouldCacheLabelsByForAttribute())
+ updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
+ }
}
ContainerNode::removedFrom(insertionPoint);
@@ -2125,12 +2138,33 @@
}
#endif
+void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
+{
+ ASSERT(hasTagName(labelTag));
+
+ if (!inDocument())
+ return;
+
+ if (oldForAttributeValue == newForAttributeValue)
+ return;
+
+ if (!oldForAttributeValue.isEmpty())
+ scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
+ if (!newForAttributeValue.isEmpty())
+ scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
+}
+
void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
{
if (isIdAttributeName(name))
updateId(oldValue, newValue);
else if (name == HTMLNames::nameAttr)
updateName(oldValue, newValue);
+ else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
+ TreeScope* scope = treeScope();
+ if (scope->shouldCacheLabelsByForAttribute())
+ updateLabel(scope, oldValue, newValue);
+ }
#if ENABLE(MUTATION_OBSERVERS)
if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
Modified: trunk/Source/WebCore/dom/Element.h (131870 => 131871)
--- trunk/Source/WebCore/dom/Element.h 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/Element.h 2012-10-19 08:01:06 UTC (rev 131871)
@@ -315,6 +315,7 @@
void updateId(const AtomicString& oldId, const AtomicString& newId);
void updateId(TreeScope*, const AtomicString& oldId, const AtomicString& newId);
void updateName(const AtomicString& oldName, const AtomicString& newName);
+ void updateLabel(TreeScope*, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue);
void removeCachedHTMLCollection(HTMLCollection*, CollectionType);
Modified: trunk/Source/WebCore/dom/TreeScope.cpp (131870 => 131871)
--- trunk/Source/WebCore/dom/TreeScope.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/TreeScope.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -36,6 +36,7 @@
#include "Frame.h"
#include "HTMLAnchorElement.h"
#include "HTMLFrameOwnerElement.h"
+#include "HTMLLabelElement.h"
#include "HTMLMapElement.h"
#include "HTMLNames.h"
#include "IdTargetObserverRegistry.h"
@@ -55,6 +56,7 @@
TreeScope::TreeScope(ContainerNode* rootNode)
: m_rootNode(rootNode)
, m_parentTreeScope(0)
+ , m_shouldCacheLabelsByForAttribute(false)
, m_idTargetObserverRegistry(IdTargetObserverRegistry::create())
{
ASSERT(rootNode);
@@ -72,6 +74,7 @@
{
m_elementsById.clear();
m_imageMapsByName.clear();
+ m_labelsByForAttribute.clear();
}
void TreeScope::setParentTreeScope(TreeScope* newParentScope)
@@ -144,6 +147,36 @@
return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this));
}
+void TreeScope::addLabel(const AtomicString& forAttributeValue, HTMLLabelElement* element)
+{
+ m_labelsByForAttribute.add(forAttributeValue.impl(), element);
+}
+
+void TreeScope::removeLabel(const AtomicString& forAttributeValue, HTMLLabelElement* element)
+{
+ m_labelsByForAttribute.remove(forAttributeValue.impl(), element);
+}
+
+HTMLLabelElement* TreeScope::labelElementForId(const AtomicString& forAttributeValue)
+{
+ if (!m_shouldCacheLabelsByForAttribute) {
+ m_shouldCacheLabelsByForAttribute = true;
+ for (Node* node = rootNode(); node; node = node->traverseNextNode()) {
+ if (node->hasTagName(labelTag)) {
+ HTMLLabelElement* label = static_cast<HTMLLabelElement*>(node);
+ const AtomicString& forValue = label->fastGetAttribute(forAttr);
+ if (!forValue.isEmpty())
+ addLabel(forValue, label);
+ }
+ }
+ }
+
+ if (forAttributeValue.isEmpty())
+ return 0;
+
+ return static_cast<HTMLLabelElement*>(m_labelsByForAttribute.getElementByLabelForAttribute(forAttributeValue.impl(), this));
+}
+
DOMSelection* TreeScope::getSelection() const
{
if (!rootNode()->document()->frame())
Modified: trunk/Source/WebCore/dom/TreeScope.h (131870 => 131871)
--- trunk/Source/WebCore/dom/TreeScope.h 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Source/WebCore/dom/TreeScope.h 2012-10-19 08:01:06 UTC (rev 131871)
@@ -35,6 +35,7 @@
class ContainerNode;
class DOMSelection;
class Element;
+class HTMLLabelElement;
class HTMLMapElement;
class IdTargetObserverRegistry;
class Node;
@@ -62,6 +63,12 @@
void removeImageMap(HTMLMapElement*);
HTMLMapElement* getImageMap(const String& url) const;
+ // For accessibility.
+ bool shouldCacheLabelsByForAttribute() const { return m_shouldCacheLabelsByForAttribute; }
+ void addLabel(const AtomicString& forAttributeValue, HTMLLabelElement*);
+ void removeLabel(const AtomicString& forAttributeValue, HTMLLabelElement*);
+ HTMLLabelElement* labelElementForId(const AtomicString& forAttributeValue);
+
DOMSelection* getSelection() const;
// Find first anchor with the given name.
@@ -94,6 +101,9 @@
DocumentOrderedMap m_elementsById;
DocumentOrderedMap m_imageMapsByName;
+ DocumentOrderedMap m_labelsByForAttribute;
+ bool m_shouldCacheLabelsByForAttribute;
+
OwnPtr<IdTargetObserverRegistry> m_idTargetObserverRegistry;
mutable RefPtr<DOMSelection> m_selection;
Modified: trunk/Tools/ChangeLog (131870 => 131871)
--- trunk/Tools/ChangeLog 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Tools/ChangeLog 2012-10-19 08:01:06 UTC (rev 131871)
@@ -1,3 +1,19 @@
+2012-10-18 Dominic Mazzoni <[email protected]>
+
+ AX: labelForElement is slow when there are a lot of DOM elements
+ https://bugs.webkit.org/show_bug.cgi?id=97825
+
+ Reviewed by Ryosuke Niwa.
+
+ Implement titleUIElement in the chromium port of DRT, and
+ fix getAccessibleElementById so that it ensures the backing store
+ is up-to-date.
+
+ * DumpRenderTree/chromium/TestRunner/AccessibilityControllerChromium.cpp:
+ (AccessibilityController::getAccessibleElementById):
+ * DumpRenderTree/chromium/TestRunner/AccessibilityUIElementChromium.cpp:
+ (AccessibilityUIElement::titleUIElementCallback):
+
2012-10-17 Ilya Tikhonovsky <[email protected]>
Web Inspector: NMI provide data for mixing with tcmalloc heap dumps.
Modified: trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityControllerChromium.cpp (131870 => 131871)
--- trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityControllerChromium.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityControllerChromium.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -117,6 +117,9 @@
if (m_rootElement.isNull())
m_rootElement = m_webView->accessibilityObject();
+ if (!m_rootElement.updateBackingStoreAndCheckValidity())
+ return 0;
+
return findAccessibleElementByIdRecursive(m_rootElement, WebString::fromUTF8(id.c_str()));
}
Modified: trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityUIElementChromium.cpp (131870 => 131871)
--- trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityUIElementChromium.cpp 2012-10-19 07:51:24 UTC (rev 131870)
+++ trunk/Tools/DumpRenderTree/chromium/TestRunner/src/AccessibilityUIElementChromium.cpp 2012-10-19 08:01:06 UTC (rev 131871)
@@ -774,7 +774,13 @@
void AccessibilityUIElement::titleUIElementCallback(const CppArgumentList&, CppVariant* result)
{
- result->setNull();
+ WebAccessibilityObject obj = accessibilityObject().titleUIElement();
+ if (obj.isNull()) {
+ result->setNull();
+ return;
+ }
+
+ result->set(*(m_factory->getOrCreate(obj)->getAsCppVariant()));
}
void AccessibilityUIElement::setSelectedTextRangeCallback(const CppArgumentList&arguments, CppVariant* result)