AX: MathML types need to be semantically identified in AX tree
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2012 23:29:09 +0000 (23:29 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Nov 2012 23:29:09 +0000 (23:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=101263

Reviewed by Beth Dakin.

Source/WebCore:

Semantically identify various MathML elements within the AX tree. This will allow
screen readers to identify math types so that equations can be output more accurately.

Test: platform/mac/accessibility/mathml-elements.html

* accessibility/AccessibilityObject.h:
(AccessibilityObject):
(WebCore::AccessibilityObject::isMathElement):
(WebCore::AccessibilityObject::isMathFraction):
(WebCore::AccessibilityObject::isMathFenced):
(WebCore::AccessibilityObject::isMathSubscriptSuperscript):
(WebCore::AccessibilityObject::isMathRow):
(WebCore::AccessibilityObject::isMathUnderOver):
(WebCore::AccessibilityObject::isMathRoot):
(WebCore::AccessibilityObject::isMathSquareRoot):
(WebCore::AccessibilityObject::isMathText):
(WebCore::AccessibilityObject::isMathNumber):
(WebCore::AccessibilityObject::isMathOperator):
(WebCore::AccessibilityObject::isMathFenceOperator):
(WebCore::AccessibilityObject::isMathSeparatorOperator):
(WebCore::AccessibilityObject::isMathIdentifier):
(WebCore::AccessibilityObject::isMathTable):
(WebCore::AccessibilityObject::isMathTableRow):
(WebCore::AccessibilityObject::isMathTableCell):
(WebCore::AccessibilityObject::mathRadicandObject):
(WebCore::AccessibilityObject::mathRootIndexObject):
(WebCore::AccessibilityObject::mathUnderObject):
(WebCore::AccessibilityObject::mathOverObject):
(WebCore::AccessibilityObject::mathNumeratorObject):
(WebCore::AccessibilityObject::mathDenominatorObject):
(WebCore::AccessibilityObject::mathBaseObject):
(WebCore::AccessibilityObject::mathSubscriptObject):
(WebCore::AccessibilityObject::mathSuperscriptObject):
(WebCore::AccessibilityObject::mathFencedOpenString):
(WebCore::AccessibilityObject::mathFencedCloseString):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::startOfContinuations):
    Handle a case where a MathML render element is created with the node of their parent (which could lead to an assert).
(WebCore::AccessibilityRenderObject::textUnderElement):
    Handle the cases for RenderMathMLOperators which use the node of their parent, which confuses the normal textUnderElement() routine.
(WebCore::AccessibilityRenderObject::accessibilityIsIgnored):
    Handle ignored cases for math elements
(WebCore::AccessibilityRenderObject::determineAccessibilityRole):
(WebCore::AccessibilityRenderObject::isMathElement):
(WebCore::AccessibilityRenderObject::isMathFraction):
(WebCore::AccessibilityRenderObject::isMathFenced):
(WebCore::AccessibilityRenderObject::isMathSubscriptSuperscript):
(WebCore::AccessibilityRenderObject::isMathRow):
(WebCore::AccessibilityRenderObject::isMathUnderOver):
(WebCore::AccessibilityRenderObject::isMathSquareRoot):
(WebCore::AccessibilityRenderObject::isMathRoot):
(WebCore::AccessibilityRenderObject::isMathOperator):
(WebCore::AccessibilityRenderObject::isMathFenceOperator):
(WebCore::AccessibilityRenderObject::isMathSeparatorOperator):
(WebCore::AccessibilityRenderObject::isMathText):
(WebCore::AccessibilityRenderObject::isMathNumber):
(WebCore::AccessibilityRenderObject::isMathIdentifier):
(WebCore::AccessibilityRenderObject::isMathTable):
(WebCore::AccessibilityRenderObject::isMathTableRow):
(WebCore::AccessibilityRenderObject::isMathTableCell):
(WebCore::AccessibilityRenderObject::isIgnoredElementWithinMathTree):
    Make sure anonymouse blocks are ignored within math tree; make sure non-element type objects are ignored (like <mstyle>).
(WebCore::AccessibilityRenderObject::mathRadicandObject):
(WebCore::AccessibilityRenderObject::mathRootIndexObject):
(WebCore::AccessibilityRenderObject::mathNumeratorObject):
(WebCore::AccessibilityRenderObject::mathDenominatorObject):
(WebCore::AccessibilityRenderObject::mathUnderObject):
(WebCore::AccessibilityRenderObject::mathOverObject):
(WebCore::AccessibilityRenderObject::mathBaseObject):
(WebCore::AccessibilityRenderObject::mathSubscriptObject):
(WebCore::AccessibilityRenderObject::mathSuperscriptObject):
(WebCore::AccessibilityRenderObject::mathFencedOpenString):
(WebCore::AccessibilityRenderObject::mathFencedCloseString):
* accessibility/AccessibilityRenderObject.h:
(AccessibilityRenderObject):
* accessibility/mac/WebAccessibilityObjectWrapper.mm:
(-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]):
(createAccessibilityRoleMap):
(-[WebAccessibilityObjectWrapper subrole]):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
* rendering/mathml/RenderMathMLBlock.cpp:
(WebCore::RenderMathMLBlock::RenderMathMLBlock):
* rendering/mathml/RenderMathMLBlock.h:
(WebCore::RenderMathMLBlock::isRenderMathMLFenced):
(WebCore::RenderMathMLBlock::isRenderMathMLFraction):
(WebCore::RenderMathMLBlock::isRenderMathMLRoot):
(WebCore::RenderMathMLBlock::isRenderMathMLSquareRoot):
(WebCore::RenderMathMLBlock::isRenderMathMLSubSup):
(WebCore::RenderMathMLBlock::isRenderMathMLUnderOver):
(WebCore::RenderMathMLBlock::setIgnoreInAccessibilityTree):
(WebCore::RenderMathMLBlock::ignoreInAccessibilityTree):
    Add ability to identify anonymous render blocks as items that AX should ignore.
(RenderMathMLBlock):
* rendering/mathml/RenderMathMLFenced.cpp:
(WebCore::RenderMathMLFenced::createMathMLOperator):
    Identify which kind of math operator is being created on the fly (Fence or Separator)
(WebCore::RenderMathMLFenced::makeFences):
(WebCore::RenderMathMLFenced::addChild):
* rendering/mathml/RenderMathMLFenced.h:
(WebCore::RenderMathMLFenced::isRenderMathMLFenced):
(RenderMathMLFenced):
* rendering/mathml/RenderMathMLFraction.h:
(WebCore::RenderMathMLFraction::isRenderMathMLFraction):
* rendering/mathml/RenderMathMLOperator.cpp:
(WebCore::RenderMathMLOperator::RenderMathMLOperator):
(WebCore::RenderMathMLOperator::updateFromElement):
(WebCore::RenderMathMLOperator::createGlyph):
     Mark anonymous render blocks as AX ignored.
* rendering/mathml/RenderMathMLOperator.h:
(WebCore::RenderMathMLOperator::setOperatorType):
(WebCore::RenderMathMLOperator::operatorType):
(RenderMathMLOperator):
* rendering/mathml/RenderMathMLRoot.h:
(WebCore::RenderMathMLRoot::isRenderMathMLRoot):
* rendering/mathml/RenderMathMLSquareRoot.h:
(WebCore::RenderMathMLSquareRoot::isRenderMathMLSquareRoot):
* rendering/mathml/RenderMathMLSubSup.h:
(WebCore::RenderMathMLSubSup::isRenderMathMLSubSup):
* rendering/mathml/RenderMathMLUnderOver.h:
(WebCore::RenderMathMLUnderOver::isRenderMathMLUnderOver):

Source/WebKit/chromium:

* public/WebAccessibilityRole.h:
* src/AssertMatchingEnums.cpp:
    Add new accessibility role.

LayoutTests:

* platform/mac/accessibility/mathml-elements-expected.txt: Added.
* platform/mac/accessibility/mathml-elements.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@134496 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/accessibility/mathml-elements-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/mathml-elements.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapper.mm
Source/WebCore/rendering/mathml/RenderMathMLBlock.cpp
Source/WebCore/rendering/mathml/RenderMathMLBlock.h
Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp
Source/WebCore/rendering/mathml/RenderMathMLFenced.h
Source/WebCore/rendering/mathml/RenderMathMLFraction.h
Source/WebCore/rendering/mathml/RenderMathMLOperator.cpp
Source/WebCore/rendering/mathml/RenderMathMLOperator.h
Source/WebCore/rendering/mathml/RenderMathMLRoot.h
Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h
Source/WebCore/rendering/mathml/RenderMathMLSubSup.h
Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/public/WebAccessibilityRole.h
Source/WebKit/chromium/src/AssertMatchingEnums.cpp

index 48323e9..5ea5e78 100644 (file)
@@ -1,3 +1,13 @@
+2012-11-13  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: MathML types need to be semantically identified in AX tree
+        https://bugs.webkit.org/show_bug.cgi?id=101263
+
+        Reviewed by Beth Dakin.
+
+        * platform/mac/accessibility/mathml-elements-expected.txt: Added.
+        * platform/mac/accessibility/mathml-elements.html: Added.
+
 2012-11-13  Dimitri Glazkov  <dglazkov@chromium.org>
 
         [Chromium] Fix media/video-empty-source.html lint error.
diff --git a/LayoutTests/platform/mac/accessibility/mathml-elements-expected.txt b/LayoutTests/platform/mac/accessibility/mathml-elements-expected.txt
new file mode 100644 (file)
index 0000000..ba459c5
--- /dev/null
@@ -0,0 +1,124 @@
+a
+2
+
+a
+2
+
+a
+
+3
+a
+
+2
+a
+e
+
+2
+sub
+
+2
+sup
+
+2
+sub
+sup
+
+3
+under
+
+3
+over
+
+3
+under
+over
+
+3
+2
+1
+This tests ensures that Mac specific attributes and roles for MathML elements work as expected.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS row.role is 'AXRole: AXGroup'
+PASS row.subrole is 'AXSubrole: AXMathRow'
+PASS row.childAtIndex(0).subrole is 'AXSubrole: AXMathIdentifier'
+PASS row.childAtIndex(0).childAtIndex(0).stringValue is 'AXValue: a'
+PASS row.childAtIndex(1).subrole is 'AXSubrole: AXMathNumber'
+PASS row.childAtIndex(1).childAtIndex(0).stringValue is 'AXValue: 2'
+PASS fraction.subrole is 'AXSubrole: AXMathFraction'
+PASS fractionDenominator.subrole is 'AXSubrole: AXMathNumber'
+PASS fractionDenominator.childAtIndex(0).stringValue is 'AXValue: 2'
+PASS fractionDenominator.isEqual(accessibilityController.accessibleElementById('fractionDenominator')) is true
+PASS fractionNumerator.subrole is 'AXSubrole: AXMathIdentifier'
+PASS fractionNumerator.childAtIndex(0).stringValue is 'AXValue: a'
+PASS fractionNumerator.isEqual(accessibilityController.accessibleElementById('fractionNumerator')) is true
+PASS sqrt.role is 'AXRole: AXGroup'
+PASS sqrt.subrole is 'AXSubrole: AXMathSquareRoot'
+PASS sqrtRadicand.subrole is 'AXSubrole: AXMathIdentifier'
+PASS sqrtRadicand.childAtIndex(0).stringValue is 'AXValue: a'
+PASS sqrtRadicand.isEqual(accessibilityController.accessibleElementById('sqrtRadicand')) is true
+PASS root.role is 'AXRole: AXGroup'
+PASS root.subrole is 'AXSubrole: AXMathRoot'
+PASS rootIndex.isEqual(accessibilityController.accessibleElementById('rootIndex')) is true
+PASS rootRadicand.isEqual(accessibilityController.accessibleElementById('rootRadicand')) is true
+PASS fenced.role is 'AXRole: AXGroup'
+PASS fenced.subrole is 'AXSubrole: AXMathFenced'
+PASS fenced.stringAttributeValue('AXMathFencedOpen') is '{'
+PASS fenced.stringAttributeValue('AXMathFencedClose') is '}'
+PASS child.childAtIndex(0).stringValue is 'AXValue: {'
+PASS child.childAtIndex(0).stringValue is 'AXValue: 2'
+PASS child.childAtIndex(0).stringValue is 'AXValue: ,'
+PASS child.childAtIndex(0).stringValue is 'AXValue: a'
+PASS child.childAtIndex(0).stringValue is 'AXValue: ,'
+PASS child.childAtIndex(0).stringValue is 'AXValue: e'
+PASS child.childAtIndex(0).stringValue is 'AXValue: }'
+PASS sub.role is 'AXRole: AXGroup'
+PASS sub.subrole is 'AXSubrole: AXMathSubscriptSuperscript'
+PASS subBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS subSub.subrole is 'AXSubrole: AXMathText'
+PASS subBase.isEqual(accessibilityController.accessibleElementById('subBase')) is true
+PASS subSub.isEqual(accessibilityController.accessibleElementById('subSub')) is true
+PASS sup.role is 'AXRole: AXGroup'
+PASS sup.subrole is 'AXSubrole: AXMathSubscriptSuperscript'
+PASS supBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS supSup.subrole is 'AXSubrole: AXMathText'
+PASS supBase.isEqual(accessibilityController.accessibleElementById('supBase')) is true
+PASS supSup.isEqual(accessibilityController.accessibleElementById('supSup')) is true
+PASS subsup.role is 'AXRole: AXGroup'
+PASS subsup.subrole is 'AXSubrole: AXMathSubscriptSuperscript'
+PASS subsupBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS subsupSup.subrole is 'AXSubrole: AXMathText'
+PASS subsupSub.subrole is 'AXSubrole: AXMathText'
+PASS subsupBase.isEqual(accessibilityController.accessibleElementById('subsupBase')) is true
+PASS subsupSub.isEqual(accessibilityController.accessibleElementById('subsupSub')) is true
+PASS subsupSup.isEqual(accessibilityController.accessibleElementById('subsupSup')) is true
+PASS under.role is 'AXRole: AXGroup'
+PASS under.subrole is 'AXSubrole: AXMathUnderOver'
+PASS underBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS underUnder.subrole is 'AXSubrole: AXMathText'
+PASS underUnder.isEqual(accessibilityController.accessibleElementById('underUnder')) is true
+PASS over.role is 'AXRole: AXGroup'
+PASS over.subrole is 'AXSubrole: AXMathUnderOver'
+PASS overBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS overOver.subrole is 'AXSubrole: AXMathText'
+PASS overBase.isEqual(accessibilityController.accessibleElementById('overBase')) is true
+PASS overOver.isEqual(accessibilityController.accessibleElementById('overOver')) is true
+PASS underover.role is 'AXRole: AXGroup'
+PASS underover.subrole is 'AXSubrole: AXMathUnderOver'
+PASS underOverBase.subrole is 'AXSubrole: AXMathIdentifier'
+PASS underOverUnder.subrole is 'AXSubrole: AXMathText'
+PASS underOverOver.subrole is 'AXSubrole: AXMathText'
+PASS underOverBase.isEqual(accessibilityController.accessibleElementById('underOverBase')) is true
+PASS underOverUnder.isEqual(accessibilityController.accessibleElementById('underOverUnder')) is true
+PASS underOverOver.isEqual(accessibilityController.accessibleElementById('underOverOver')) is true
+PASS table.role is 'AXRole: AXGroup'
+PASS table.subrole is 'AXSubrole: AXMathTable'
+PASS row.subrole is 'AXSubrole: AXMathTableRow'
+PASS cell.subrole is 'AXSubrole: AXMathTableCell'
+PASS cell.childAtIndex(0).subrole is 'AXSubrole: AXMathIdentifier'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/mathml-elements.html b/LayoutTests/platform/mac/accessibility/mathml-elements.html
new file mode 100644 (file)
index 0000000..bcbda67
--- /dev/null
@@ -0,0 +1,203 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+
+<math id="row">
+<mrow><mi>a</mi><mn>2</mn></mrow>
+</math><br>
+
+<math id="fraction">
+<mfrac><mi id="fractionNumerator">a</mi><mn id="fractionDenominator">2</mn></mfrac>
+</math><br>
+
+<math id="sqrt">
+<msqrt><mi id="sqrtRadicand">a</mi></msqrt>
+</math><br>
+
+<math id="root">
+<mroot><mn id="rootRadicand">3</mn><mi id="rootIndex">a</mi></mroot>
+</math><br>
+
+<math id="fenced">
+<mfenced open="{" close="}" separators=",,"><mi>2</mi><mi>a</mi><mi>e</mi></mroot>
+</math><br>
+
+<math id="sub">
+<msub><mi id="subBase">2</mi><mtext id="subSub">sub</mtext></msub>
+</math><br>
+
+<math id="sup">
+<msup><mi id="supBase">2</mi><mtext id="supSup">sup</mtext></msup>
+</math><br>
+
+<math id="subsup">
+<msubsup><mi id="subsupBase">2</mi><mtext id="subsupSub">sub</mtext><mtext id="subsupSup">sup</mtext></msubsup>
+</math><br>
+       
+<math id="under">
+<munder><mi id="underBase">3</mi><mtext id="underUnder">under</mtext></munder>
+</math><br>
+
+<math id="over">
+<mover><mi id="overBase">3</mi><mtext id="overOver">over</mtext></mover>
+</math><br>
+
+<math id="underover">
+<munderover><mi id="underOverBase">3</mi><mtext id="underOverUnder">under</mtext><mtext id="underOverOver">over</mtext></munderover>
+</math><br>
+
+<math id="table">
+<mtable>
+<mtr><mtd><mi>3</mi></mtd></mtr>
+<mtr><mtd><mi>2</mi></mtd></mtr>
+<mtr><mtd><mi>1</mi></mtd></mtr>
+</mtable>
+</math>
+
+
+<div id="console"></div>
+<script>
+
+description("This tests ensures that Mac specific attributes and roles for MathML elements work as expected.")
+
+if (window.testRunner && window.accessibilityController) {
+
+   // Row
+   var row = accessibilityController.accessibleElementById("row").childAtIndex(0);
+   shouldBe("row.role", "'AXRole: AXGroup'");
+   shouldBe("row.subrole", "'AXSubrole: AXMathRow'");
+   shouldBe("row.childAtIndex(0).subrole", "'AXSubrole: AXMathIdentifier'");
+   shouldBe("row.childAtIndex(0).childAtIndex(0).stringValue", "'AXValue: a'");
+   shouldBe("row.childAtIndex(1).subrole", "'AXSubrole: AXMathNumber'");
+   shouldBe("row.childAtIndex(1).childAtIndex(0).stringValue", "'AXValue: 2'");
+
+   // Fraction
+   var fraction = accessibilityController.accessibleElementById("fraction").childAtIndex(0);
+   shouldBe("fraction.subrole", "'AXSubrole: AXMathFraction'");
+   var fractionDenominator = fraction.uiElementAttributeValue("AXMathFractionDenominator");
+   var fractionNumerator = fraction.uiElementAttributeValue("AXMathFractionNumerator");
+   shouldBe("fractionDenominator.subrole", "'AXSubrole: AXMathNumber'");
+   shouldBe("fractionDenominator.childAtIndex(0).stringValue", "'AXValue: 2'");
+   shouldBeTrue("fractionDenominator.isEqual(accessibilityController.accessibleElementById('fractionDenominator'))");
+   shouldBe("fractionNumerator.subrole", "'AXSubrole: AXMathIdentifier'");
+   shouldBe("fractionNumerator.childAtIndex(0).stringValue", "'AXValue: a'");
+   shouldBeTrue("fractionNumerator.isEqual(accessibilityController.accessibleElementById('fractionNumerator'))");
+
+   // Square root
+   var sqrt = accessibilityController.accessibleElementById("sqrt").childAtIndex(0);
+   shouldBe("sqrt.role", "'AXRole: AXGroup'");
+   shouldBe("sqrt.subrole", "'AXSubrole: AXMathSquareRoot'");
+   var sqrtRadicand = sqrt.uiElementAttributeValue("AXMathRootRadicand");
+   shouldBe("sqrtRadicand.subrole", "'AXSubrole: AXMathIdentifier'");
+   shouldBe("sqrtRadicand.childAtIndex(0).stringValue", "'AXValue: a'");
+   shouldBeTrue("sqrtRadicand.isEqual(accessibilityController.accessibleElementById('sqrtRadicand'))");
+
+   // Generic root
+   var root = accessibilityController.accessibleElementById("root").childAtIndex(0);
+   shouldBe("root.role", "'AXRole: AXGroup'");
+   shouldBe("root.subrole", "'AXSubrole: AXMathRoot'");
+   var rootIndex = root.uiElementAttributeValue("AXMathRootIndex");
+   var rootRadicand = root.uiElementAttributeValue("AXMathRootRadicand");
+   shouldBeTrue("rootIndex.isEqual(accessibilityController.accessibleElementById('rootIndex'))");
+   shouldBeTrue("rootRadicand.isEqual(accessibilityController.accessibleElementById('rootRadicand'))");
+
+   // Fenced
+   var fenced = accessibilityController.accessibleElementById("fenced").childAtIndex(0);
+   shouldBe("fenced.role", "'AXRole: AXGroup'");
+   shouldBe("fenced.subrole", "'AXSubrole: AXMathFenced'");
+   shouldBe("fenced.stringAttributeValue('AXMathFencedOpen')", "'{'");
+   shouldBe("fenced.stringAttributeValue('AXMathFencedClose')", "'}'");
+   var fenceValues = new Array("{", "2", ",", "a", ",", "e", "}");
+   for (var k = 0; k < fenceValues.length; k++) {
+      var child = fenced.childAtIndex(k);
+      shouldBe("child.childAtIndex(0).stringValue", "'AXValue: " + fenceValues[k] + "'");
+   }
+
+   // Subscript
+   var sub = accessibilityController.accessibleElementById("sub").childAtIndex(0);
+   shouldBe("sub.role", "'AXRole: AXGroup'");
+   shouldBe("sub.subrole", "'AXSubrole: AXMathSubscriptSuperscript'");
+   var subBase = sub.uiElementAttributeValue("AXMathBase");
+   shouldBe("subBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var subSub = sub.uiElementAttributeValue("AXMathSubscript");
+   shouldBe("subSub.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("subBase.isEqual(accessibilityController.accessibleElementById('subBase'))");
+   shouldBeTrue("subSub.isEqual(accessibilityController.accessibleElementById('subSub'))");
+
+   // Superscript
+   var sup = accessibilityController.accessibleElementById("sup").childAtIndex(0);
+   shouldBe("sup.role", "'AXRole: AXGroup'");
+   shouldBe("sup.subrole", "'AXSubrole: AXMathSubscriptSuperscript'");
+   var supBase = sup.uiElementAttributeValue("AXMathBase");
+   shouldBe("supBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var supSup = sup.uiElementAttributeValue("AXMathSuperscript");
+   shouldBe("supSup.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("supBase.isEqual(accessibilityController.accessibleElementById('supBase'))");
+   shouldBeTrue("supSup.isEqual(accessibilityController.accessibleElementById('supSup'))");
+
+   // Subsuperscript
+   var subsup = accessibilityController.accessibleElementById("subsup").childAtIndex(0);
+   shouldBe("subsup.role", "'AXRole: AXGroup'");
+   shouldBe("subsup.subrole", "'AXSubrole: AXMathSubscriptSuperscript'");
+   var subsupBase = subsup.uiElementAttributeValue("AXMathBase");
+   shouldBe("subsupBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var subsupSup = subsup.uiElementAttributeValue("AXMathSuperscript");
+   shouldBe("subsupSup.subrole", "'AXSubrole: AXMathText'");
+   var subsupSub = subsup.uiElementAttributeValue("AXMathSubscript");
+   shouldBe("subsupSub.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("subsupBase.isEqual(accessibilityController.accessibleElementById('subsupBase'))");
+   shouldBeTrue("subsupSub.isEqual(accessibilityController.accessibleElementById('subsupSub'))");
+   shouldBeTrue("subsupSup.isEqual(accessibilityController.accessibleElementById('subsupSup'))");
+
+   // Under
+   var under = accessibilityController.accessibleElementById("under").childAtIndex(0);
+   shouldBe("under.role", "'AXRole: AXGroup'");
+   shouldBe("under.subrole", "'AXSubrole: AXMathUnderOver'");
+   var underBase = under.uiElementAttributeValue("AXMathBase");
+   shouldBe("underBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var underUnder = under.uiElementAttributeValue("AXMathUnder");
+   shouldBe("underUnder.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("underUnder.isEqual(accessibilityController.accessibleElementById('underUnder'))");
+
+   // Over
+   var over = accessibilityController.accessibleElementById("over").childAtIndex(0);
+   shouldBe("over.role", "'AXRole: AXGroup'");
+   shouldBe("over.subrole", "'AXSubrole: AXMathUnderOver'");
+   var overBase = over.uiElementAttributeValue("AXMathBase");
+   shouldBe("overBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var overOver = over.uiElementAttributeValue("AXMathOver");
+   shouldBe("overOver.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("overBase.isEqual(accessibilityController.accessibleElementById('overBase'))");
+   shouldBeTrue("overOver.isEqual(accessibilityController.accessibleElementById('overOver'))");
+
+   // UnderOver
+   var underover = accessibilityController.accessibleElementById("underover").childAtIndex(0);
+   shouldBe("underover.role", "'AXRole: AXGroup'");
+   shouldBe("underover.subrole", "'AXSubrole: AXMathUnderOver'");
+   var underOverBase = underover.uiElementAttributeValue("AXMathBase");
+   shouldBe("underOverBase.subrole", "'AXSubrole: AXMathIdentifier'");
+   var underOverUnder = underover.uiElementAttributeValue("AXMathUnder");
+   shouldBe("underOverUnder.subrole", "'AXSubrole: AXMathText'");
+   var underOverOver = underover.uiElementAttributeValue("AXMathOver");
+   shouldBe("underOverOver.subrole", "'AXSubrole: AXMathText'");
+   shouldBeTrue("underOverBase.isEqual(accessibilityController.accessibleElementById('underOverBase'))");
+   shouldBeTrue("underOverUnder.isEqual(accessibilityController.accessibleElementById('underOverUnder'))");
+   shouldBeTrue("underOverOver.isEqual(accessibilityController.accessibleElementById('underOverOver'))");
+
+   // Table
+   var table = accessibilityController.accessibleElementById("table").childAtIndex(0);
+   shouldBe("table.role", "'AXRole: AXGroup'");
+   shouldBe("table.subrole", "'AXSubrole: AXMathTable'");
+   var row = table.childAtIndex(0);
+   shouldBe("row.subrole", "'AXSubrole: AXMathTableRow'");
+   var cell = row.childAtIndex(0);
+   shouldBe("cell.subrole", "'AXSubrole: AXMathTableCell'");
+   shouldBe("cell.childAtIndex(0).subrole", "'AXSubrole: AXMathIdentifier'");
+}
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index eea6d8a..ad44552 100644 (file)
@@ -1,3 +1,131 @@
+2012-11-13  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: MathML types need to be semantically identified in AX tree
+        https://bugs.webkit.org/show_bug.cgi?id=101263
+
+        Reviewed by Beth Dakin.
+
+        Semantically identify various MathML elements within the AX tree. This will allow
+        screen readers to identify math types so that equations can be output more accurately.
+
+        Test: platform/mac/accessibility/mathml-elements.html
+
+        * accessibility/AccessibilityObject.h:
+        (AccessibilityObject):
+        (WebCore::AccessibilityObject::isMathElement):
+        (WebCore::AccessibilityObject::isMathFraction):
+        (WebCore::AccessibilityObject::isMathFenced):
+        (WebCore::AccessibilityObject::isMathSubscriptSuperscript):
+        (WebCore::AccessibilityObject::isMathRow):
+        (WebCore::AccessibilityObject::isMathUnderOver):
+        (WebCore::AccessibilityObject::isMathRoot):
+        (WebCore::AccessibilityObject::isMathSquareRoot):
+        (WebCore::AccessibilityObject::isMathText):
+        (WebCore::AccessibilityObject::isMathNumber):
+        (WebCore::AccessibilityObject::isMathOperator):
+        (WebCore::AccessibilityObject::isMathFenceOperator):
+        (WebCore::AccessibilityObject::isMathSeparatorOperator):
+        (WebCore::AccessibilityObject::isMathIdentifier):
+        (WebCore::AccessibilityObject::isMathTable):
+        (WebCore::AccessibilityObject::isMathTableRow):
+        (WebCore::AccessibilityObject::isMathTableCell):
+        (WebCore::AccessibilityObject::mathRadicandObject):
+        (WebCore::AccessibilityObject::mathRootIndexObject):
+        (WebCore::AccessibilityObject::mathUnderObject):
+        (WebCore::AccessibilityObject::mathOverObject):
+        (WebCore::AccessibilityObject::mathNumeratorObject):
+        (WebCore::AccessibilityObject::mathDenominatorObject):
+        (WebCore::AccessibilityObject::mathBaseObject):
+        (WebCore::AccessibilityObject::mathSubscriptObject):
+        (WebCore::AccessibilityObject::mathSuperscriptObject):
+        (WebCore::AccessibilityObject::mathFencedOpenString):
+        (WebCore::AccessibilityObject::mathFencedCloseString):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::startOfContinuations):
+            Handle a case where a MathML render element is created with the node of their parent (which could lead to an assert).
+        (WebCore::AccessibilityRenderObject::textUnderElement):
+            Handle the cases for RenderMathMLOperators which use the node of their parent, which confuses the normal textUnderElement() routine.
+        (WebCore::AccessibilityRenderObject::accessibilityIsIgnored):
+            Handle ignored cases for math elements
+        (WebCore::AccessibilityRenderObject::determineAccessibilityRole):
+        (WebCore::AccessibilityRenderObject::isMathElement):
+        (WebCore::AccessibilityRenderObject::isMathFraction):
+        (WebCore::AccessibilityRenderObject::isMathFenced):
+        (WebCore::AccessibilityRenderObject::isMathSubscriptSuperscript):
+        (WebCore::AccessibilityRenderObject::isMathRow):
+        (WebCore::AccessibilityRenderObject::isMathUnderOver):
+        (WebCore::AccessibilityRenderObject::isMathSquareRoot):
+        (WebCore::AccessibilityRenderObject::isMathRoot):
+        (WebCore::AccessibilityRenderObject::isMathOperator):
+        (WebCore::AccessibilityRenderObject::isMathFenceOperator):
+        (WebCore::AccessibilityRenderObject::isMathSeparatorOperator):
+        (WebCore::AccessibilityRenderObject::isMathText):
+        (WebCore::AccessibilityRenderObject::isMathNumber):
+        (WebCore::AccessibilityRenderObject::isMathIdentifier):
+        (WebCore::AccessibilityRenderObject::isMathTable):
+        (WebCore::AccessibilityRenderObject::isMathTableRow):
+        (WebCore::AccessibilityRenderObject::isMathTableCell):
+        (WebCore::AccessibilityRenderObject::isIgnoredElementWithinMathTree):
+            Make sure anonymouse blocks are ignored within math tree; make sure non-element type objects are ignored (like <mstyle>).
+        (WebCore::AccessibilityRenderObject::mathRadicandObject):
+        (WebCore::AccessibilityRenderObject::mathRootIndexObject):
+        (WebCore::AccessibilityRenderObject::mathNumeratorObject):
+        (WebCore::AccessibilityRenderObject::mathDenominatorObject):
+        (WebCore::AccessibilityRenderObject::mathUnderObject):
+        (WebCore::AccessibilityRenderObject::mathOverObject):
+        (WebCore::AccessibilityRenderObject::mathBaseObject):
+        (WebCore::AccessibilityRenderObject::mathSubscriptObject):
+        (WebCore::AccessibilityRenderObject::mathSuperscriptObject):
+        (WebCore::AccessibilityRenderObject::mathFencedOpenString):
+        (WebCore::AccessibilityRenderObject::mathFencedCloseString):
+        * accessibility/AccessibilityRenderObject.h:
+        (AccessibilityRenderObject):
+        * accessibility/mac/WebAccessibilityObjectWrapper.mm:
+        (-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]):
+        (createAccessibilityRoleMap):
+        (-[WebAccessibilityObjectWrapper subrole]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+        * rendering/mathml/RenderMathMLBlock.cpp:
+        (WebCore::RenderMathMLBlock::RenderMathMLBlock):
+        * rendering/mathml/RenderMathMLBlock.h:
+        (WebCore::RenderMathMLBlock::isRenderMathMLFenced):
+        (WebCore::RenderMathMLBlock::isRenderMathMLFraction):
+        (WebCore::RenderMathMLBlock::isRenderMathMLRoot):
+        (WebCore::RenderMathMLBlock::isRenderMathMLSquareRoot):
+        (WebCore::RenderMathMLBlock::isRenderMathMLSubSup):
+        (WebCore::RenderMathMLBlock::isRenderMathMLUnderOver):
+        (WebCore::RenderMathMLBlock::setIgnoreInAccessibilityTree):
+        (WebCore::RenderMathMLBlock::ignoreInAccessibilityTree):
+            Add ability to identify anonymous render blocks as items that AX should ignore.
+        (RenderMathMLBlock):
+        * rendering/mathml/RenderMathMLFenced.cpp:
+        (WebCore::RenderMathMLFenced::createMathMLOperator):
+            Identify which kind of math operator is being created on the fly (Fence or Separator)
+        (WebCore::RenderMathMLFenced::makeFences):
+        (WebCore::RenderMathMLFenced::addChild):
+        * rendering/mathml/RenderMathMLFenced.h:
+        (WebCore::RenderMathMLFenced::isRenderMathMLFenced):
+        (RenderMathMLFenced):
+        * rendering/mathml/RenderMathMLFraction.h:
+        (WebCore::RenderMathMLFraction::isRenderMathMLFraction):
+        * rendering/mathml/RenderMathMLOperator.cpp:
+        (WebCore::RenderMathMLOperator::RenderMathMLOperator):
+        (WebCore::RenderMathMLOperator::updateFromElement):
+        (WebCore::RenderMathMLOperator::createGlyph):
+             Mark anonymous render blocks as AX ignored.
+        * rendering/mathml/RenderMathMLOperator.h:
+        (WebCore::RenderMathMLOperator::setOperatorType):
+        (WebCore::RenderMathMLOperator::operatorType):
+        (RenderMathMLOperator):
+        * rendering/mathml/RenderMathMLRoot.h:
+        (WebCore::RenderMathMLRoot::isRenderMathMLRoot):
+        * rendering/mathml/RenderMathMLSquareRoot.h:
+        (WebCore::RenderMathMLSquareRoot::isRenderMathMLSquareRoot):
+        * rendering/mathml/RenderMathMLSubSup.h:
+        (WebCore::RenderMathMLSubSup::isRenderMathMLSubSup):
+        * rendering/mathml/RenderMathMLUnderOver.h:
+        (WebCore::RenderMathMLUnderOver::isRenderMathMLUnderOver):
+        
 2012-11-13  Mark Lam  <mark.lam@apple.com>
 
         JSEventListener should not access m_jsFunction when its wrapper is gone.
index 7d3b660..05e130f 100644 (file)
@@ -151,6 +151,7 @@ enum AccessibilityRole {
     ListBoxOptionRole,
     ListItemRole,
     ListMarkerRole,
+    MathElementRole,
     MatteRole,
     MenuRole,
     MenuBarRole,
@@ -736,6 +737,46 @@ public:
     // Fires a children changed notification on the parent if the isIgnored value changed.
     void notifyIfIgnoredValueChanged();
 
+    // All math elements return true for isMathElement().
+    virtual bool isMathElement() const { return false; }
+    virtual bool isMathFraction() const { return false; }
+    virtual bool isMathFenced() const { return false; }
+    virtual bool isMathSubscriptSuperscript() const { return false; }
+    virtual bool isMathRow() const { return false; }
+    virtual bool isMathUnderOver() const { return false; }
+    virtual bool isMathRoot() const { return false; }
+    virtual bool isMathSquareRoot() const { return false; }
+    virtual bool isMathText() const { return false; }
+    virtual bool isMathNumber() const { return false; }
+    virtual bool isMathOperator() const { return false; }
+    virtual bool isMathFenceOperator() const { return false; }
+    virtual bool isMathSeparatorOperator() const { return false; }
+    virtual bool isMathIdentifier() const { return false; }
+    virtual bool isMathTable() const { return false; }
+    virtual bool isMathTableRow() const { return false; }
+    virtual bool isMathTableCell() const { return false; }
+    
+    // Root components.
+    virtual AccessibilityObject* mathRadicandObject() { return 0; }
+    virtual AccessibilityObject* mathRootIndexObject() { return 0; }
+    
+    // Under over components.
+    virtual AccessibilityObject* mathUnderObject() { return 0; }
+    virtual AccessibilityObject* mathOverObject() { return 0; }
+
+    // Fraction components.
+    virtual AccessibilityObject* mathNumeratorObject() { return 0; }
+    virtual AccessibilityObject* mathDenominatorObject() { return 0; }
+
+    // Subscript/superscript components.
+    virtual AccessibilityObject* mathBaseObject() { return 0; }
+    virtual AccessibilityObject* mathSubscriptObject() { return 0; }
+    virtual AccessibilityObject* mathSuperscriptObject() { return 0; }
+    
+    // Fenced components.
+    virtual String mathFencedOpenString() const { return String(); }
+    virtual String mathFencedCloseString() const { return String(); }
+    
 #if HAVE(ACCESSIBILITY)
 #if PLATFORM(GTK)
     AccessibilityObjectWrapper* wrapper() const;
index 429adc7..2d422c2 100644 (file)
@@ -72,6 +72,8 @@
 #include "RenderLayer.h"
 #include "RenderListBox.h"
 #include "RenderListMarker.h"
+#include "RenderMathMLBlock.h"
+#include "RenderMathMLOperator.h"
 #include "RenderMenuList.h"
 #include "RenderText.h"
 #include "RenderTextControl.h"
@@ -242,8 +244,17 @@ AccessibilityObject* AccessibilityRenderObject::lastChild() const
 
 static inline RenderInline* startOfContinuations(RenderObject* r)
 {
-    if (r->isInlineElementContinuation())
+    if (r->isInlineElementContinuation()) {
+#if ENABLE(MATHML)
+        // MathML elements make anonymous RenderObjects, then set their node to the parent's node.
+        // This makes it so that the renderer() != renderer()->node()->renderer()
+        // (which is what isInlineElementContinuation() uses as a determinant).
+        if (r->node()->isElementNode() && toElement(r->node())->isMathMLElement())
+            return 0;
+#endif
+        
         return toRenderInline(r->node()->renderer());
+    }
 
     // Blocks with a previous continuation always have a next continuation
     if (r->isRenderBlock() && toRenderBlock(r)->inlineElementContinuation())
@@ -617,6 +628,18 @@ String AccessibilityRenderObject::textUnderElement() const
         return toRenderFileUploadControl(m_renderer)->buttonValue();
     
     Node* node = m_renderer->node();
+
+#if ENABLE(MATHML)
+    // Math operators create RenderText nodes on the fly that are not tied into the DOM in a reasonable way,
+    // so rangeOfContents does not work for them (nor does regular text selection).
+    if (m_renderer->isText() && isMathElement()) {
+        for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) {
+            if (parent->isRenderMathMLBlock() && toRenderMathMLBlock(parent)->isRenderMathMLOperator())
+                return toRenderText(m_renderer)->text();
+        }
+    }
+#endif
+    
     if (node) {
         if (Frame* frame = node->document()->frame()) {
             // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
@@ -1171,6 +1194,15 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const
     if (supportsARIAAttributes())
         return false;
 
+#if ENABLE(MATHML)
+    // First check if this is a special case within the math tree that needs to be ignored.
+    if (isIgnoredElementWithinMathTree())
+        return true;
+    // Otherwise all other math elements are in the tree.
+    if (isMathElement())
+        return false;
+#endif
+    
     // <span> tags are inline tags and not meant to convey information if they have no other aria
     // information on them. If we don't ignore them, they may emit signals expected to come from
     // their parent. In addition, because included spans are GroupRole objects, and GroupRole
@@ -2402,6 +2434,10 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole()
     if (node && node->hasTagName(MathMLNames::mathTag))
         return DocumentMathRole;
 #endif
+    // It's not clear which role a platform should choose for a math element.
+    // Declaring a math element role should give flexibility to platforms to choose.
+    if (isMathElement())
+        return MathElementRole;
     
     if (node && node->hasTagName(ddTag))
         return DefinitionListDefinitionRole;
@@ -3290,4 +3326,315 @@ void AccessibilityRenderObject::scrollTo(const IntPoint& point) const
     layer->scrollToOffset(toSize(point), RenderLayer::ScrollOffsetClamped);
 }
 
+#if ENABLE(MATHML)
+bool AccessibilityRenderObject::isMathElement() const
+{
+    Node* node = this->node();
+    if (!m_renderer || !node)
+        return false;
+    
+    return node->isElementNode() && toElement(node)->isMathMLElement();
+}
+
+bool AccessibilityRenderObject::isMathFraction() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLFraction();
+}
+
+bool AccessibilityRenderObject::isMathFenced() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLFenced();
+}
+
+bool AccessibilityRenderObject::isMathSubscriptSuperscript() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLSubSup();
+}
+
+bool AccessibilityRenderObject::isMathRow() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLRow();
+}
+
+bool AccessibilityRenderObject::isMathUnderOver() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLUnderOver();
+}
+
+bool AccessibilityRenderObject::isMathSquareRoot() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLSquareRoot();
+}
+    
+bool AccessibilityRenderObject::isMathRoot() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    return toRenderMathMLBlock(m_renderer)->isRenderMathMLRoot();
+}
+
+bool AccessibilityRenderObject::isMathOperator() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    // Ensure that this is actually a render MathML operator because
+    // MathML will create MathMLBlocks and use the original node as the node
+    // of this new block that is not tied to the DOM.
+    if (!toRenderMathMLBlock(m_renderer)->isRenderMathMLOperator())
+        return false;
+    
+    return isMathElement() && node()->hasTagName(MathMLNames::moTag);
+}
+
+bool AccessibilityRenderObject::isMathFenceOperator() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    if (!toRenderMathMLBlock(m_renderer)->isRenderMathMLOperator())
+        return false;
+    
+    RenderMathMLOperator* mathOperator = toRenderMathMLOperator(toRenderMathMLBlock(m_renderer));
+    return mathOperator->operatorType() == RenderMathMLOperator::Fence;
+}
+
+bool AccessibilityRenderObject::isMathSeparatorOperator() const
+{
+    if (!m_renderer || !m_renderer->isRenderMathMLBlock())
+        return false;
+    
+    if (!toRenderMathMLBlock(m_renderer)->isRenderMathMLOperator())
+        return false;
+    
+    RenderMathMLOperator* mathOperator = toRenderMathMLOperator(toRenderMathMLBlock(m_renderer));
+    return mathOperator->operatorType() == RenderMathMLOperator::Separator;
+}
+    
+bool AccessibilityRenderObject::isMathText() const
+{
+    return node() && node()->hasTagName(MathMLNames::mtextTag);
+}
+
+bool AccessibilityRenderObject::isMathNumber() const
+{
+    return node() && node()->hasTagName(MathMLNames::mnTag);
+}
+
+bool AccessibilityRenderObject::isMathIdentifier() const
+{
+    return node() && node()->hasTagName(MathMLNames::miTag);
+}
+
+bool AccessibilityRenderObject::isMathTable() const
+{
+    return node() && node()->hasTagName(MathMLNames::mtableTag);
+}
+
+bool AccessibilityRenderObject::isMathTableRow() const
+{
+    return node() && node()->hasTagName(MathMLNames::mtrTag);
+}
+
+bool AccessibilityRenderObject::isMathTableCell() const
+{
+    return node() && node()->hasTagName(MathMLNames::mtdTag);
+}
+    
+bool AccessibilityRenderObject::isIgnoredElementWithinMathTree() const
+{
+    if (!m_renderer)
+        return true;
+    
+    // Ignore items that were created for layout purposes only.
+    if (m_renderer->isRenderMathMLBlock() && toRenderMathMLBlock(m_renderer)->ignoreInAccessibilityTree())
+        return true;
+
+    // Ignore anonymous renderers inside math blocks.
+    if (m_renderer->isAnonymous()) {
+        for (AccessibilityObject* parent = parentObject(); parent; parent = parent->parentObject()) {
+            if (parent->isMathElement())
+                return true;
+        }
+    }
+
+    // Only math elements that we explicitly recognize should be included
+    // We don't want things like <mstyle> to appear in the tree.
+    if (isMathElement()) {
+        if (isMathFraction() || isMathFenced() || isMathSubscriptSuperscript() || isMathRow()
+            || isMathUnderOver() || isMathRoot() || isMathText() || isMathNumber()
+            || isMathOperator() || isMathFenceOperator() || isMathSeparatorOperator()
+            || isMathIdentifier() || isMathTable() || isMathTableRow() || isMathTableCell())
+            return false;
+        return true;
+    }
+
+    return false;
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathRadicandObject()
+{
+    if (!isMathRoot())
+        return 0;
+    
+    AccessibilityObject::AccessibilityChildrenVector children = this->children();
+    if (children.size() < 1)
+        return 0;
+    
+    // The radicand is the value being rooted and must be listed first.
+    return children[0].get();
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathRootIndexObject()
+{
+    if (!isMathRoot())
+        return 0;
+    
+    AccessibilityObject::AccessibilityChildrenVector children = this->children();
+    if (children.size() != 2)
+        return 0;
+
+    // The index in a root is the value which determines if it's a square, cube, etc, root
+    // and must be listed second.
+    return children[1].get();
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathNumeratorObject()
+{
+    if (!isMathFraction())
+        return 0;
+    
+    AccessibilityObject::AccessibilityChildrenVector children = this->children();
+    if (children.size() != 2)
+        return 0;
+    
+    return children[0].get();
+}
+    
+AccessibilityObject* AccessibilityRenderObject::mathDenominatorObject()
+{
+    if (!isMathFraction())
+        return 0;
+
+    AccessibilityObject::AccessibilityChildrenVector children = this->children();
+    if (children.size() != 2)
+        return 0;
+    
+    return children[1].get();
+}
+    
+AccessibilityObject* AccessibilityRenderObject::mathUnderObject()
+{
+    if (!isMathUnderOver() || !node())
+        return 0;
+    
+    AccessibilityChildrenVector children = this->children();
+    if (children.size() < 2)
+        return 0;
+    
+    if (node()->hasTagName(MathMLNames::munderTag) || node()->hasTagName(MathMLNames::munderoverTag))
+        return children[1].get();
+    
+    return 0;
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathOverObject()
+{
+    if (!isMathUnderOver() || !node())
+        return 0;
+    
+    AccessibilityChildrenVector children = this->children();
+    if (children.size() < 2)
+        return 0;
+    
+    if (node()->hasTagName(MathMLNames::moverTag))
+        return children[1].get();
+    if (node()->hasTagName(MathMLNames::munderoverTag))
+        return children[2].get();
+
+    return 0;
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathBaseObject()
+{
+    if (!isMathSubscriptSuperscript() && !isMathUnderOver())
+        return 0;
+    
+    AccessibilityChildrenVector children = this->children();
+    // The base object in question is always the first child.
+    if (children.size() > 0)
+        return children[0].get();
+
+    return 0;
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathSubscriptObject()
+{
+    if (!isMathSubscriptSuperscript() || !node())
+        return 0;
+    
+    AccessibilityChildrenVector children = this->children();
+    if (children.size() < 2)
+        return 0;
+
+    if (node()->hasTagName(MathMLNames::msubTag) || node()->hasTagName(MathMLNames::msubsupTag))
+        return children[1].get();
+    
+    return 0;
+}
+
+AccessibilityObject* AccessibilityRenderObject::mathSuperscriptObject()
+{
+    if (!isMathSubscriptSuperscript() || !node())
+        return 0;
+    
+    AccessibilityChildrenVector children = this->children();
+    if (children.size() < 2)
+        return 0;
+    
+    if (node()->hasTagName(MathMLNames::msupTag))
+        return children[1].get();
+    if (node()->hasTagName(MathMLNames::msubsupTag))
+        return children[2].get();
+    
+    return 0;
+}
+    
+String AccessibilityRenderObject::mathFencedOpenString() const
+{
+    if (!isMathFenced())
+        return String();
+    
+    return getAttribute(MathMLNames::openAttr);
+}
+
+String AccessibilityRenderObject::mathFencedCloseString() const
+{
+    if (!isMathFenced())
+        return String();
+    
+    return getAttribute(MathMLNames::closeAttr);
+}
+
+#endif
+    
 } // namespace WebCore
index 9402e47..97bf8a3 100644 (file)
@@ -277,6 +277,52 @@ private:
     virtual bool ariaLiveRegionBusy() const;    
     
     bool inheritsPresentationalRole() const;
+    
+#if ENABLE(MATHML)
+    // All math elements return true for isMathElement().
+    virtual bool isMathElement() const;
+    virtual bool isMathFraction() const;
+    virtual bool isMathFenced() const;
+    virtual bool isMathSubscriptSuperscript() const;
+    virtual bool isMathRow() const;
+    virtual bool isMathUnderOver() const;
+    virtual bool isMathRoot() const;
+    virtual bool isMathSquareRoot() const;
+    virtual bool isMathText() const;
+    virtual bool isMathNumber() const;
+    virtual bool isMathOperator() const;
+    virtual bool isMathFenceOperator() const;
+    virtual bool isMathSeparatorOperator() const;
+    virtual bool isMathIdentifier() const;
+    virtual bool isMathTable() const;
+    virtual bool isMathTableRow() const;
+    virtual bool isMathTableCell() const;
+    
+    // Generic components.
+    virtual AccessibilityObject* mathBaseObject();
+    
+    // Root components.
+    virtual AccessibilityObject* mathRadicandObject();
+    virtual AccessibilityObject* mathRootIndexObject();
+    
+    // Fraction components.
+    virtual AccessibilityObject* mathNumeratorObject();
+    virtual AccessibilityObject* mathDenominatorObject();
+
+    // Under over components.
+    virtual AccessibilityObject* mathUnderObject();
+    virtual AccessibilityObject* mathOverObject();
+    
+    // Subscript/superscript components.
+    virtual AccessibilityObject* mathSubscriptObject();
+    virtual AccessibilityObject* mathSuperscriptObject();
+    
+    // Fenced components.
+    virtual String mathFencedOpenString() const;
+    virtual String mathFencedCloseString() const;
+
+    bool isIgnoredElementWithinMathTree() const;
+#endif
 };
 
 inline AccessibilityRenderObject* toAccessibilityRenderObject(AccessibilityObject* object)
index e53d5f1..26b6ed9 100644 (file)
@@ -338,6 +338,19 @@ using namespace std;
 #define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
 #define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
 
+// Math attributes
+#define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
+#define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
+#define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
+#define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
+#define NSAccessibilityMathBaseAttribute @"AXMathBase"
+#define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
+#define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
+#define NSAccessibilityMathUnderAttribute @"AXMathUnder"
+#define NSAccessibilityMathOverAttribute @"AXMathOver"
+#define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
+#define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
+
 @interface NSObject (WebKitAccessibilityArrayCategory)
 
 - (NSUInteger)accessibilityIndexOfChild:(id)child;
@@ -997,6 +1010,27 @@ static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosit
     if (m_object->ariaHasPopup())
         [additional addObject:NSAccessibilityHasPopupAttribute];
     
+    if (m_object->isMathRoot()) {
+        // The index of a square root is always known, so there's no object associated with it.
+        if (!m_object->isMathSquareRoot())
+            [additional addObject:NSAccessibilityMathRootIndexAttribute];
+        [additional addObject:NSAccessibilityMathRootRadicandAttribute];
+    } else if (m_object->isMathFraction()) {
+        [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
+        [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
+    } else if (m_object->isMathSubscriptSuperscript()) {
+        [additional addObject:NSAccessibilityMathBaseAttribute];
+        [additional addObject:NSAccessibilityMathSubscriptAttribute];
+        [additional addObject:NSAccessibilityMathSuperscriptAttribute];
+    } else if (m_object->isMathUnderOver()) {
+        [additional addObject:NSAccessibilityMathBaseAttribute];
+        [additional addObject:NSAccessibilityMathUnderAttribute];
+        [additional addObject:NSAccessibilityMathOverAttribute];
+    } else if (m_object->isMathFenced()) {
+        [additional addObject:NSAccessibilityMathFencedOpenAttribute];
+        [additional addObject:NSAccessibilityMathFencedCloseAttribute];
+    }
+
     return additional;
 }
 
@@ -1599,7 +1633,8 @@ static const AccessibilityRoleMap& createAccessibilityRoleMap()
         { ToggleButtonRole, NSAccessibilityButtonRole },
         { CanvasRole, NSAccessibilityImageRole },
         { SVGRootRole, NSAccessibilityGroupRole },
-        { LegendRole, NSAccessibilityGroupRole }
+        { LegendRole, NSAccessibilityGroupRole },
+        { MathElementRole, NSAccessibilityGroupRole }
     };
     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
     
@@ -1719,6 +1754,41 @@ static NSString* roleValueToNSString(AccessibilityRole value)
             break;
     }
     
+    if (m_object->roleValue() == MathElementRole) {
+        if (m_object->isMathFraction())
+            return @"AXMathFraction";
+        if (m_object->isMathFenced())
+            return @"AXMathFenced";
+        if (m_object->isMathSubscriptSuperscript())
+            return @"AXMathSubscriptSuperscript";
+        if (m_object->isMathRow())
+            return @"AXMathRow";
+        if (m_object->isMathUnderOver())
+            return @"AXMathUnderOver";
+        if (m_object->isMathSquareRoot())
+            return @"AXMathSquareRoot";
+        if (m_object->isMathRoot())
+            return @"AXMathRoot";
+        if (m_object->isMathText())
+            return @"AXMathText";
+        if (m_object->isMathNumber())
+            return @"AXMathNumber";
+        if (m_object->isMathIdentifier())
+            return @"AXMathIdentifier";
+        if (m_object->isMathTable())
+            return @"AXMathTable";
+        if (m_object->isMathTableRow())
+            return @"AXMathTableRow";
+        if (m_object->isMathTableCell())
+            return @"AXMathTableCell";
+        if (m_object->isMathFenceOperator())
+            return @"AXMathFenceOperator";
+        if (m_object->isMathSeparatorOperator())
+            return @"AXMathSeparatorOperator";
+        if (m_object->isMathOperator())
+            return @"AXMathOperator";
+    }
+    
     if (m_object->isMediaTimeline())
         return NSAccessibilityTimelineSubrole;
 
@@ -2539,6 +2609,32 @@ static NSString* roleValueToNSString(AccessibilityRole value)
         return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
     if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
         return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
+
+    // MathML Attributes.
+    if (m_object->isMathElement()) {
+        if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute])
+            return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute])
+            return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
+            return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
+            return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
+            return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
+            return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])
+            return (m_object->mathSuperscriptObject()) ? m_object->mathSuperscriptObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute])
+            return (m_object->mathUnderObject()) ? m_object->mathUnderObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute])
+            return (m_object->mathOverObject()) ? m_object->mathOverObject()->wrapper() : 0;
+        if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute])
+            return m_object->mathFencedOpenString();
+        if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute])
+            return m_object->mathFencedCloseString();
+    }
     
     // this is used only by DumpRenderTree for testing
     if ([attributeName isEqualToString:@"AXClickPoint"])
index 54f8070..c23a9de 100644 (file)
@@ -44,6 +44,7 @@ using namespace MathMLNames;
     
 RenderMathMLBlock::RenderMathMLBlock(Node* container) 
     : RenderFlexibleBox(container)
+    , m_ignoreInAccessibilityTree(false)
     , m_intrinsicPaddingBefore(0)
     , m_intrinsicPaddingAfter(0)
     , m_intrinsicPaddingStart(0)
index 36e62ad..51e80ec 100644 (file)
@@ -48,6 +48,12 @@ public:
     virtual bool isRenderMathMLOperator() const { return false; }
     virtual bool isRenderMathMLRow() const { return false; }
     virtual bool isRenderMathMLMath() const { return false; }
+    virtual bool isRenderMathMLFenced() const { return false; }
+    virtual bool isRenderMathMLFraction() const { return false; }
+    virtual bool isRenderMathMLRoot() const { return false; }
+    virtual bool isRenderMathMLSquareRoot() const { return false; }
+    virtual bool isRenderMathMLSubSup() const { return false; }
+    virtual bool isRenderMathMLUnderOver() const { return false; }
     
     // MathML defines an "embellished operator" as roughly an <mo> that may have subscripts,
     // superscripts, underscripts, overscripts, or a denominator (as in d/dx, where "d" is some
@@ -87,8 +93,12 @@ public:
     // Create a new RenderMathMLBlock, with a new style inheriting from this->style().
     RenderMathMLBlock* createAnonymousMathMLBlock(EDisplay = FLEX);
     
+    void setIgnoreInAccessibilityTree(bool flag) { m_ignoreInAccessibilityTree = flag; }
+    bool ignoreInAccessibilityTree() const { return m_ignoreInAccessibilityTree; }
+    
 private:
     virtual const char* renderName() const OVERRIDE;
+    bool m_ignoreInAccessibilityTree;
     
 protected:
     // Set our logical width to a large value, and compute our children's preferred logical heights.
index f35c336..96f6cba 100644 (file)
@@ -82,22 +82,23 @@ void RenderMathMLFenced::updateFromElement()
         makeFences();
 }
 
-RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, OperatorType operatorType)
+RenderMathMLOperator* RenderMathMLFenced::createMathMLOperator(UChar uChar, RenderMathMLOperator::OperatorType operatorType)
 {
     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), FLEX);
     newStyle->setFlexDirection(FlowColumn);
-    newStyle->setMarginEnd(Length((operatorType == Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed));
-    if (operatorType == Fence)
+    newStyle->setMarginEnd(Length((operatorType == RenderMathMLOperator::Fence ? gFenceMarginEms : gSeparatorMarginEndEms) * style()->fontSize(), Fixed));
+    if (operatorType == RenderMathMLOperator::Fence)
         newStyle->setMarginStart(Length(gFenceMarginEms * style()->fontSize(), Fixed));
     RenderMathMLOperator* newOperator = new (renderArena()) RenderMathMLOperator(node() /* "almost anonymous" */, uChar);
+    newOperator->setOperatorType(operatorType);
     newOperator->setStyle(newStyle.release());
     return newOperator;
 }
 
 void RenderMathMLFenced::makeFences()
 {
-    RenderMathMLRow::addChild(createMathMLOperator(m_open, Fence), firstChild());
-    m_closeFenceRenderer = createMathMLOperator(m_close, Fence);
+    RenderMathMLRow::addChild(createMathMLOperator(m_open, RenderMathMLOperator::Fence), firstChild());
+    m_closeFenceRenderer = createMathMLOperator(m_close, RenderMathMLOperator::Fence);
     RenderMathMLRow::addChild(m_closeFenceRenderer);
 }
 
@@ -132,7 +133,7 @@ void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild
             else
                 separator = (*m_separators.get())[count - 1];
                 
-            separatorRenderer = createMathMLOperator(separator, Separator);
+            separatorRenderer = createMathMLOperator(separator, RenderMathMLOperator::Separator);
         }
     }
     
index 0f0cfff..a8b73a9 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(MATHML)
 
+#include "RenderMathMLOperator.h"
 #include "RenderMathMLRow.h"
 
 namespace WebCore {
@@ -39,11 +40,10 @@ public:
     virtual void updateFromElement();
     
 private:
+    virtual bool isRenderMathMLFenced() const { return true; }
     virtual const char* renderName() const { return "RenderMathMLFenced"; }
 
-    // FIXME: OperatorType here will go away when default operator margins are determined by the MathML operator dictionary.
-    enum OperatorType { Separator, Fence };
-    RenderMathMLOperator* createMathMLOperator(UChar, OperatorType);
+    RenderMathMLOperator* createMathMLOperator(UChar, RenderMathMLOperator::OperatorType);
     void makeFences();
     
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
index 4c10e36..1ec4a06 100644 (file)
@@ -47,6 +47,7 @@ protected:
     virtual void layout();
     
 private:
+    virtual bool isRenderMathMLFraction() const { return true; }
     void fixChildStyle(RenderObject* child);
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
 
index 6655cce..bde8baf 100644 (file)
@@ -43,6 +43,7 @@ RenderMathMLOperator::RenderMathMLOperator(Element* element)
     : RenderMathMLBlock(element)
     , m_stretchHeight(0)
     , m_operator(0)
+    , m_operatorType(Default)
 {
 }
 
@@ -50,6 +51,7 @@ RenderMathMLOperator::RenderMathMLOperator(Node* node, UChar operatorChar)
     : RenderMathMLBlock(node)
     , m_stretchHeight(0)
     , m_operator(convertHyphenMinusToMinusSign(operatorChar))
+    , m_operatorType(Default)
 {
 }
 
@@ -201,6 +203,8 @@ void RenderMathMLOperator::updateFromElement()
     if (stretchDisabled || !shouldStack) {
         m_isStacked = false;
         RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
+        // This container doesn't offer any useful information to accessibility.
+        toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
         
         RefPtr<RenderStyle> newStyle = RenderStyle::create();
         newStyle->inheritFrom(style());
@@ -293,6 +297,7 @@ PassRefPtr<RenderStyle> RenderMathMLOperator::createStackableStyle(int maxHeight
 RenderBlock* RenderMathMLOperator::createGlyph(UChar glyph, int maxHeightForRenderer, int charRelative)
 {
     RenderBlock* container = new (renderArena()) RenderMathMLBlock(node());
+    toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true);
     container->setStyle(createStackableStyle(maxHeightForRenderer));
     addChild(container);
     RenderBlock* parent = container;
index 40d6b77..75bb941 100644 (file)
@@ -46,7 +46,11 @@ public:
     void stretchToHeight(int pixelHeight);
     
     virtual int firstLineBoxBaseline() const OVERRIDE;
-        
+    
+    enum OperatorType { Default, Separator, Fence };
+    void setOperatorType(OperatorType type) { m_operatorType = type; }
+    OperatorType operatorType() const { return m_operatorType; }
+    
 protected:
     virtual void computePreferredLogicalWidths() OVERRIDE;
     PassRefPtr<RenderStyle> createStackableStyle(int maxHeightForRenderer);
@@ -62,6 +66,7 @@ private:
     int m_stretchHeight;
     bool m_isStacked;
     UChar m_operator;
+    OperatorType m_operatorType;
 };
 
 inline RenderMathMLOperator* toRenderMathMLOperator(RenderMathMLBlock* block)
index 2ae303a..99cd365 100644 (file)
@@ -45,6 +45,7 @@ protected:
     virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
 
 private:
+    virtual bool isRenderMathMLRoot() const { return true; }
     virtual const char* renderName() const { return "RenderMathMLRoot"; }
     
     virtual void computePreferredLogicalWidths() OVERRIDE;
index 90e186c..39e0aa7 100644 (file)
@@ -38,6 +38,7 @@ public:
     RenderMathMLSquareRoot(Element*);
     
 private:
+    virtual bool isRenderMathMLSquareRoot() const { return true; }
     virtual const char* renderName() const { return "RenderMathMLSquareRoot"; }
 };
     
index 640a86e..082f1a3 100644 (file)
@@ -44,7 +44,9 @@ protected:
     virtual void layout();
     
 private:
+    virtual bool isRenderMathMLSubSup() const { return true; }
     void fixAnonymousStyles();
+
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
 
     virtual const char* renderName() const { return "RenderMathMLSubSup"; }
index caf4fc4..4608145 100644 (file)
@@ -41,6 +41,7 @@ public:
     virtual int firstLineBoxBaseline() const OVERRIDE;
     
 private:
+    virtual bool isRenderMathMLUnderOver() const { return true; }
     virtual const char* renderName() const { return "RenderMathMLUnderOver"; }
 
     enum UnderOverType { Under, Over, UnderOver };
index 2e2e500..f9f7015 100644 (file)
@@ -1,3 +1,14 @@
+2012-11-13  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: MathML types need to be semantically identified in AX tree
+        https://bugs.webkit.org/show_bug.cgi?id=101263
+
+        Reviewed by Beth Dakin.
+
+        * public/WebAccessibilityRole.h:
+        * src/AssertMatchingEnums.cpp:
+            Add new accessibility role.
+
 2012-11-13  Silvia Pfeiffer  <silviapf@chromium.org>
 
         Clean up the inheritance tree under the MediaControls Class.
index 031a69d..0008724 100644 (file)
@@ -96,6 +96,7 @@ enum WebAccessibilityRole {
     WebAccessibilityRoleListBoxOption,
     WebAccessibilityRoleListItem,
     WebAccessibilityRoleListMarker,
+    WebAccessibilityRoleMathElement,
     WebAccessibilityRoleMatte,
     WebAccessibilityRoleMenu,
     WebAccessibilityRoleMenuBar,
index 385ae7e..52601a7 100644 (file)
@@ -211,6 +211,7 @@ COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleWebCoreLink, WebCoreLinkRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleImageMapLink, ImageMapLinkRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleImageMap, ImageMapRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleListMarker, ListMarkerRole);
+COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleMathElement, MathElementRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleWebArea, WebAreaRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleHeading, HeadingRole);
 COMPILE_ASSERT_MATCHING_ENUM(WebAccessibilityRoleListBox, ListBoxRole);