Bug 1177765 - Add xmlroles for MathML. r=surkov

This commit is contained in:
Frédéric Wang 2015-07-16 05:43:00 -04:00
parent 729b7b3747
commit a5efb9235a
3 changed files with 163 additions and 1 deletions

View File

@ -30,6 +30,7 @@
#include "nsIScrollableFrame.h"
#include "nsIServiceManager.h"
#include "nsITextControlElement.h"
#include "nsIMathMLFrame.h"
#include "nsTextFragment.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/dom/Element.h"
@ -952,6 +953,145 @@ HyperTextAccessible::GetLevelInternal()
return AccessibleWrap::GetLevelInternal();
}
void
HyperTextAccessible::SetMathMLXMLRoles(nsIPersistentProperties* aAttributes)
{
// Add MathML xmlroles based on the position inside the parent.
Accessible* parent = Parent();
if (parent) {
switch (parent->Role()) {
case roles::MATHML_CELL:
case roles::MATHML_ENCLOSED:
case roles::MATHML_ERROR:
case roles::MATHML_MATH:
case roles::MATHML_ROW:
case roles::MATHML_SQUARE_ROOT:
case roles::MATHML_STYLE:
if (Role() == roles::MATHML_OPERATOR) {
// This is an operator inside an <mrow> (or an inferred <mrow>).
// See http://www.w3.org/TR/MathML3/chapter3.html#presm.inferredmrow
// XXX We should probably do something similar for MATHML_FENCED, but
// operators do not appear in the accessible tree. See bug 1175747.
nsIMathMLFrame* mathMLFrame = do_QueryFrame(GetFrame());
if (mathMLFrame) {
nsEmbellishData embellishData;
mathMLFrame->GetEmbellishData(embellishData);
if (NS_MATHML_EMBELLISH_IS_FENCE(embellishData.flags)) {
if (!PrevSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::open_fence);
} else if (!NextSibling()) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::close_fence);
}
}
if (NS_MATHML_EMBELLISH_IS_SEPARATOR(embellishData.flags)) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::separator_);
}
}
}
break;
case roles::MATHML_FRACTION:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ?
nsGkAtoms::numerator :
nsGkAtoms::denominator);
break;
case roles::MATHML_ROOT:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::root_index);
break;
case roles::MATHML_SUB:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::subscript);
break;
case roles::MATHML_SUP:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::superscript);
break;
case roles::MATHML_SUB_SUP: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::subscript :
nsGkAtoms::superscript));
} break;
case roles::MATHML_UNDER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::underscript);
break;
case roles::MATHML_OVER:
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
IndexInParent() == 0 ? nsGkAtoms::base :
nsGkAtoms::overscript);
break;
case roles::MATHML_UNDER_OVER: {
int32_t index = IndexInParent();
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
index == 0 ? nsGkAtoms::base :
(index == 1 ? nsGkAtoms::underscript :
nsGkAtoms::overscript));
} break;
case roles::MATHML_MULTISCRIPTS: {
// Get the <multiscripts> base.
nsIContent* child;
bool baseFound = false;
for (child = parent->GetContent()->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->IsMathMLElement()) {
baseFound = true;
break;
}
}
if (baseFound) {
nsIContent* content = GetContent();
if (child == content) {
// We are the base.
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
nsGkAtoms::base);
} else {
// Browse the list of scripts to find us and determine our type.
bool postscript = true;
bool subscript = true;
for (child = child->GetNextSibling(); child;
child = child->GetNextSibling()) {
if (!child->IsMathMLElement())
continue;
if (child->IsMathMLElement(nsGkAtoms::mprescripts_)) {
postscript = false;
subscript = true;
continue;
}
if (child == content) {
if (postscript) {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::subscript :
nsGkAtoms::superscript);
} else {
nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
subscript ?
nsGkAtoms::presubscript :
nsGkAtoms::presuperscript);
}
break;
}
subscript = !subscript;
}
}
}
} break;
default:
break;
}
}
}
already_AddRefed<nsIPersistentProperties>
HyperTextAccessible::NativeAttributes()
{
@ -976,8 +1116,11 @@ HyperTextAccessible::NativeAttributes()
}
}
if (HasOwnContent())
if (HasOwnContent()) {
GetAccService()->MarkupAttributes(mContent, attributes);
if (mContent->IsMathMLElement())
SetMathMLXMLRoles(attributes);
}
return attributes.forget();
}

View File

@ -561,6 +561,12 @@ protected:
uint32_t* aStartOffset, uint32_t* aEndOffset,
nsIPersistentProperties* aAttributes);
/**
* Set xml-roles attributes for MathML elements.
* @param aAttributes
*/
void SetMathMLXMLRoles(nsIPersistentProperties* aAttributes);
private:
/**
* End text offsets array.

View File

@ -2343,6 +2343,19 @@ GK_ATOM(toolbarspring, "toolbarspring")
GK_ATOM(treegrid, "treegrid")
GK_ATOM(_undefined, "undefined")
GK_ATOM(xmlroles, "xml-roles")
// MathML xml roles
GK_ATOM(close_fence, "close-fence")
GK_ATOM(denominator, "denominator")
GK_ATOM(numerator, "numerator")
GK_ATOM(open_fence, "open-fence")
GK_ATOM(overscript, "overscript")
GK_ATOM(presubscript, "presubscript")
GK_ATOM(presuperscript, "presuperscript")
GK_ATOM(root_index, "root-index")
GK_ATOM(subscript, "subscript")
GK_ATOM(superscript, "superscript")
GK_ATOM(underscript, "underscript")
#endif
#ifdef MOZ_WEBSPEECH