Bug 1732280 - Implement mappings for sub, sup elements and subscript, superscript roles, r=Jamie

This commit adds mappings for HTML sub and sup elements, as well as ARIA
role mappings for subscript, superscript roles, with the goal of properly
exposing this information to the accessibility tree. This commit also updates
text attribute code to account for the attributes implied by those roles.
Finally, this commit updates tests to verify that the role and attribute
information is working properly.

Differential Revision: https://phabricator.services.mozilla.com/D155523
This commit is contained in:
Nathan LaPre 2022-08-31 16:48:56 +00:00
Родитель 088c86b28a
Коммит 982410361d
12 изменённых файлов: 324 добавлений и 74 удалений

Просмотреть файл

@ -1152,6 +1152,15 @@ static const nsRoleMapEntry sWAIRoleMaps[] = {
kGenericAccType,
kNoReqStates
},
{ // subscript
nsGkAtoms::subscript,
roles::SUBSCRIPT,
kUseMapRole,
eNoValue,
eNoAction,
eNoLiveAttr,
kGenericAccType
},
{ // suggestion
nsGkAtoms::suggestion,
roles::SUGGESTION,
@ -1161,6 +1170,15 @@ static const nsRoleMapEntry sWAIRoleMaps[] = {
eNoLiveAttr,
kGenericAccType,
},
{ // superscript
nsGkAtoms::superscript,
roles::SUPERSCRIPT,
kUseMapRole,
eNoValue,
eNoAction,
eNoLiveAttr,
kGenericAccType
},
{ // switch
nsGkAtoms::svgSwitch,
roles::SWITCH,

Просмотреть файл

@ -333,6 +333,8 @@ MARKUPMAP(
},
0)
MARKUPMAP(sub, New_HyperText, roles::SUBSCRIPT)
MARKUPMAP(
summary,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
@ -340,6 +342,8 @@ MARKUPMAP(
},
roles::SUMMARY)
MARKUPMAP(sup, New_HyperText, roles::SUPERSCRIPT)
MARKUPMAP(
table,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {

Просмотреть файл

@ -19,7 +19,7 @@ namespace roles {
enum Role {
/**
* Used when accessible hans't strong defined role.
* Used when the accessible has no strongly-defined role.
*/
NOTHING = 0,
@ -1083,7 +1083,21 @@ enum Role {
*/
METER = 185,
LAST_ROLE = METER
/**
* Represents phrasing content that is presented with vertical alignment
* lower than the baseline and a smaller font size. For example, the "2" in
* the chemical formula H2O.
*/
SUBSCRIPT = 186,
/**
* Represents phrasing content that is presented with vertical alignment
* higher than the baseline and a smaller font size. For example, the
* exponent in a math expression.
*/
SUPERSCRIPT = 187,
LAST_ROLE = SUPERSCRIPT
};
} // namespace roles

Просмотреть файл

@ -1886,4 +1886,24 @@ ROLE(METER,
ROLE_SYSTEM_PROGRESSBAR,
java::SessionAccessibility::CLASSNAME_VIEW,
eNameFromValueRule)
ROLE(SUBSCRIPT,
"subscript",
ATK_ROLE_SUBSCRIPT,
NSAccessibilityGroupRole,
@"AXSubscriptStyleGroup",
ROLE_SYSTEM_GROUPING,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
eNoNameRule)
ROLE(SUPERSCRIPT,
"superscript",
ATK_ROLE_SUPERSCRIPT,
NSAccessibilityGroupRole,
@"AXSuperscriptStyleGroup",
ROLE_SYSTEM_GROUPING,
IA2_ROLE_TEXT_FRAME,
java::SessionAccessibility::CLASSNAME_VIEW,
eNoNameRule)
// clang-format on

Просмотреть файл

@ -120,7 +120,7 @@ void TextAttrsMgr::GetAttributes(AccAttributes* aAttributes,
TextDecorTextAttr textDecorTextAttr(rootFrame, frame);
// "text-position" text attribute
TextPosTextAttr textPosTextAttr(rootFrame, frame);
TextPosTextAttr textPosTextAttr(rootFrame, frame, hyperTextElm, offsetNode);
TextAttr* attrArray[] = {
&langTextAttr, &invalidTextAttr, &bgColorTextAttr,
@ -664,34 +664,67 @@ void TextAttrsMgr::TextDecorTextAttr::ExposeValue(
////////////////////////////////////////////////////////////////////////////////
TextAttrsMgr::TextPosTextAttr::TextPosTextAttr(nsIFrame* aRootFrame,
nsIFrame* aFrame)
: TTextAttr<TextPosValue>(!aFrame) {
mRootNativeValue = GetTextPosValue(aRootFrame);
mIsRootDefined = mRootNativeValue != eTextPosNone;
nsIFrame* aFrame,
nsIContent* aRootElm,
nsIContent* aElm)
: TTextAttr<Maybe<TextPosValue>>(!aFrame && !aElm), mRootElm(aRootElm) {
// Get the text-position values for the roots and children.
// If we find an ARIA text-position value on a DOM element - searching up
// from the supplied root DOM element - use the associated frame as the root
// frame. This ensures that we're using the proper root frame for comparison.
nsIFrame* ariaFrame = nullptr;
Maybe<TextPosValue> rootAria = GetAriaTextPosValue(aRootElm, ariaFrame);
if (rootAria && ariaFrame) {
aRootFrame = ariaFrame;
}
Maybe<TextPosValue> rootLayout = GetLayoutTextPosValue(aRootFrame);
Maybe<TextPosValue> childLayout;
Maybe<TextPosValue> childAria;
if (aFrame) {
mNativeValue = GetTextPosValue(aFrame);
mIsDefined = mNativeValue != eTextPosNone;
childLayout = GetLayoutTextPosValue(aFrame);
}
if (aElm) {
childAria = GetAriaTextPosValue(aElm);
}
// Aria values take precedence over layout values.
mIsRootDefined = rootAria || rootLayout;
mRootNativeValue = rootAria ? rootAria : rootLayout;
mIsDefined = childAria || childLayout;
mNativeValue = childAria ? childAria : childLayout;
// If there's no child text-position information from ARIA, and the child
// layout info is equivalent to the root layout info (i.e., it's inherited),
// then we should prefer the root information.
if (!childAria && childLayout == rootLayout) {
mIsDefined = false;
}
}
bool TextAttrsMgr::TextPosTextAttr::GetValueFor(LocalAccessible* aAccessible,
TextPosValue* aValue) {
Maybe<TextPosValue>* aValue) {
nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
if (elm) {
nsIFrame* frame = elm->GetPrimaryFrame();
if (frame) {
*aValue = GetTextPosValue(frame);
return *aValue != eTextPosNone;
Maybe<TextPosValue> layoutValue = GetLayoutTextPosValue(frame);
Maybe<TextPosValue> ariaValue = GetAriaTextPosValue(elm);
*aValue = ariaValue ? ariaValue : layoutValue;
return aValue->isSome();
}
}
return false;
}
void TextAttrsMgr::TextPosTextAttr::ExposeValue(AccAttributes* aAttributes,
const TextPosValue& aValue) {
void TextAttrsMgr::TextPosTextAttr::ExposeValue(
AccAttributes* aAttributes, const Maybe<TextPosValue>& aValue) {
if (aValue.isNothing()) {
return;
}
RefPtr<nsAtom> atom = nullptr;
switch (aValue) {
switch (*aValue) {
case eTextPosBaseline:
atom = nsGkAtoms::baseline;
break;
@ -703,9 +736,6 @@ void TextAttrsMgr::TextPosTextAttr::ExposeValue(AccAttributes* aAttributes,
case eTextPosSuper:
atom = NS_Atomize("super");
break;
case eTextPosNone:
break;
}
if (atom) {
@ -713,42 +743,75 @@ void TextAttrsMgr::TextPosTextAttr::ExposeValue(AccAttributes* aAttributes,
}
}
TextAttrsMgr::TextPosValue TextAttrsMgr::TextPosTextAttr::GetTextPosValue(
nsIFrame* aFrame) const {
Maybe<TextAttrsMgr::TextPosValue>
TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent* aElm) const {
nsIFrame* ariaFrame = nullptr;
return GetAriaTextPosValue(aElm, ariaFrame);
}
Maybe<TextAttrsMgr::TextPosValue>
TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent* aElm,
nsIFrame*& ariaFrame) const {
// Search for the superscript and subscript roles that imply text-position.
const nsIContent* elm = aElm;
do {
if (elm->IsElement()) {
const mozilla::dom::Element* domElm = elm->AsElement();
static const dom::Element::AttrValuesArray tokens[] = {
nsGkAtoms::subscript, nsGkAtoms::superscript, nullptr};
const int32_t valueIdx = domElm->FindAttrValueIn(
kNameSpaceID_None, nsGkAtoms::role, tokens, eCaseMatters);
ariaFrame = domElm->GetPrimaryFrame();
if (valueIdx == 0) {
return Some(eTextPosSub);
}
if (valueIdx == 1) {
return Some(eTextPosSuper);
}
}
} while ((elm = elm->GetParent()) && elm != mRootElm);
ariaFrame = nullptr;
return Nothing{};
}
Maybe<TextAttrsMgr::TextPosValue>
TextAttrsMgr::TextPosTextAttr::GetLayoutTextPosValue(nsIFrame* aFrame) const {
const auto& verticalAlign = aFrame->StyleDisplay()->mVerticalAlign;
if (verticalAlign.IsKeyword()) {
switch (verticalAlign.AsKeyword()) {
case StyleVerticalAlignKeyword::Baseline:
return eTextPosBaseline;
return Some(eTextPosBaseline);
case StyleVerticalAlignKeyword::Sub:
return eTextPosSub;
return Some(eTextPosSub);
case StyleVerticalAlignKeyword::Super:
return eTextPosSuper;
return Some(eTextPosSuper);
// No good guess for the rest, so do not expose value of text-position
// attribute.
default:
return eTextPosNone;
return Nothing{};
}
}
const auto& length = verticalAlign.AsLength();
if (length.ConvertsToPercentage()) {
float percentValue = length.ToPercentage();
return percentValue > 0
? eTextPosSuper
: (percentValue < 0 ? eTextPosSub : eTextPosBaseline);
const float percentValue = length.ToPercentage();
return percentValue > 0 ? Some(eTextPosSuper)
: (percentValue < 0 ? Some(eTextPosSub)
: Some(eTextPosBaseline));
}
if (length.ConvertsToLength()) {
nscoord coordValue = length.ToLength();
return coordValue > 0 ? eTextPosSuper
: (coordValue < 0 ? eTextPosSub : eTextPosBaseline);
const nscoord coordValue = length.ToLength();
return coordValue > 0
? Some(eTextPosSuper)
: (coordValue < 0 ? Some(eTextPosSub) : Some(eTextPosBaseline));
}
if (const nsIContent* content = aFrame->GetContent()) {
if (content->IsHTMLElement(nsGkAtoms::sup)) return eTextPosSuper;
if (content->IsHTMLElement(nsGkAtoms::sub)) return eTextPosSub;
if (content->IsHTMLElement(nsGkAtoms::sup)) return Some(eTextPosSuper);
if (content->IsHTMLElement(nsGkAtoms::sub)) return Some(eTextPosSub);
}
return eTextPosNone;
return Nothing{};
}

Просмотреть файл

@ -407,27 +407,27 @@ class TextAttrsMgr {
* Class is used for the work with "text-position" text attribute.
*/
enum TextPosValue {
eTextPosNone = 0,
eTextPosBaseline,
eTextPosSub,
eTextPosSuper
};
enum TextPosValue { eTextPosBaseline, eTextPosSub, eTextPosSuper };
class TextPosTextAttr : public TTextAttr<TextPosValue> {
class TextPosTextAttr : public TTextAttr<Maybe<TextPosValue>> {
public:
TextPosTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
TextPosTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame,
nsIContent* aRootElm, nsIContent* aElm);
virtual ~TextPosTextAttr() {}
protected:
// TextAttr
virtual bool GetValueFor(LocalAccessible* aAccessible,
TextPosValue* aValue) override;
Maybe<TextPosValue>* aValue) override;
virtual void ExposeValue(AccAttributes* aAttributes,
const TextPosValue& aValue) override;
const Maybe<TextPosValue>& aValue) override;
private:
TextPosValue GetTextPosValue(nsIFrame* aFrame) const;
Maybe<TextPosValue> GetAriaTextPosValue(nsIContent* aElm) const;
Maybe<TextPosValue> GetAriaTextPosValue(nsIContent* aElm,
nsIFrame*& ariaFrame) const;
Maybe<TextPosValue> GetLayoutTextPosValue(nsIFrame* aFrame) const;
nsIContent* mRootElm;
};
}; // TextAttrMgr

Просмотреть файл

@ -12,7 +12,7 @@
interface nsIAccessibleRole : nsISupports
{
/**
* Used when accessible hans't strong defined role.
* Used when the accessible has no strongly-defined role.
*/
const unsigned long ROLE_NOTHING = 0;
@ -1077,4 +1077,18 @@ interface nsIAccessibleRole : nsISupports
*/
const unsigned long ROLE_METER = 185;
/**
* Represents phrasing content that is presented with vertical alignment
* lower than the baseline and a smaller font size. For example, the "2" in
* the chemical formula H2O.
*/
const unsigned long ROLE_SUBSCRIPT = 186;
/**
* Represents phrasing content that is presented with vertical alignment
* higher than the baseline and a smaller font size. For example, the
* exponent in a math expression.
*/
const unsigned long ROLE_SUPERSCRIPT = 187;
};

Просмотреть файл

@ -94,6 +94,8 @@ addAccessibleTask(
<hr id="hr" />
<ins id="insertion">Inserted text</ins>
<meter id="meter" min="0" max="100" value="24">meter text here</meter>
<sub id="sub">sub text here</sub>
<sup id="sup">sup text here</sup>
<!-- Some SVG stuff -->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg"
@ -211,6 +213,8 @@ addAccessibleTask(
null,
"level indicator"
);
testRoleAndSubRole(accDoc, "sub", "AXGroup", "AXSubscriptStyleGroup");
testRoleAndSubRole(accDoc, "sup", "AXGroup", "AXSuperscriptStyleGroup");
// Some SVG stuff
testRoleAndSubRole(accDoc, "svg", "AXImage");

Просмотреть файл

@ -1375,18 +1375,33 @@
};
testElm("strong_container", obj);
// ////////////////////////////////////////////////////////////////////////
// HTML:sub
obj = {
role: ROLE_SUBSCRIPT
};
testElm("sub", obj);
// ////////////////////////////////////////////////////////////////////////
// HTML:sup
obj = {
role: ROLE_SUPERSCRIPT
};
testElm("sup", obj);
// ////////////////////////////////////////////////////////////////////////
// HTML:sub contained by paragraph
obj = {
role: ROLE_PARAGRAPH,
textAttrs: {
0: { },
6: { "text-position": "sub" },
},
children: [
{ role: ROLE_TEXT_LEAF }, // plain text
{ role: ROLE_TEXT_LEAF }, // HTML:sub text
{
role: ROLE_SUBSCRIPT, // HTML:sub
children: [
{ role: ROLE_TEXT_LEAF } // HTML:sub text
]
}
],
};
testElm("sub_container", obj);
@ -1396,13 +1411,14 @@
obj = {
role: ROLE_PARAGRAPH,
textAttrs: {
0: { },
6: { "text-position": "super" },
},
children: [
{ role: ROLE_TEXT_LEAF }, // plain text
{ role: ROLE_TEXT_LEAF }, // HTML:sup text
{
role: ROLE_SUPERSCRIPT, // HTML:sup
children: [
{ role: ROLE_TEXT_LEAF } // HTML:sup text
]
}
],
};
testElm("sup_container", obj);
@ -1961,6 +1977,8 @@
<span id="span"></span>
<span id="span_explicit" title="explicit"></span>
<p id="strong_container">normal<strong>strong</strong></p>
<sub id="sub"></sub>
<sup id="sup"></sup>
<p id="sub_container">normal<sub>sub</sub></p>
<p id="sup_container">normal<sup>sup</sup></p>

Просмотреть файл

@ -125,7 +125,9 @@ const ROLE_SLIDER = nsIAccessibleRole.ROLE_SLIDER;
const ROLE_SPINBUTTON = nsIAccessibleRole.ROLE_SPINBUTTON;
const ROLE_STATICTEXT = nsIAccessibleRole.ROLE_STATICTEXT;
const ROLE_STATUSBAR = nsIAccessibleRole.ROLE_STATUSBAR;
const ROLE_SUBSCRIPT = nsIAccessibleRole.ROLE_SUBSCRIPT;
const ROLE_SUGGESTION = nsIAccessibleRole.ROLE_SUGGESTION;
const ROLE_SUPERSCRIPT = nsIAccessibleRole.ROLE_SUPERSCRIPT;
const ROLE_SUMMARY = nsIAccessibleRole.ROLE_SUMMARY;
const ROLE_SWITCH = nsIAccessibleRole.ROLE_SWITCH;
const ROLE_TABLE = nsIAccessibleRole.ROLE_TABLE;

Просмотреть файл

@ -146,8 +146,12 @@
testRole("aria_spinbutton_mixed", ROLE_SPINBUTTON);
testRole("aria_status", ROLE_STATUSBAR);
testRole("aria_status_mixed", ROLE_STATUSBAR);
testRole("aria_subscript", ROLE_SUBSCRIPT);
testRole("aria_subscript_mixed", ROLE_SUBSCRIPT);
testRole("aria_suggestion", ROLE_SUGGESTION);
testRole("aria_suggestion_mixed", ROLE_SUGGESTION);
testRole("aria_superscript", ROLE_SUPERSCRIPT);
testRole("aria_superscript_mixed", ROLE_SUPERSCRIPT);
testRole("aria_switch", ROLE_SWITCH);
testRole("aria_switch_mixed", ROLE_SWITCH);
testRole("aria_tab", ROLE_PAGETAB);
@ -496,8 +500,12 @@
<span id="aria_spinbutton_mixed" role="sPINBUTTOn"></span>
<span id="aria_status" role="status"></span>
<span id="aria_status_mixed" role="sTATUs"></span>
<span id="aria_subscript" role="subscript"></span>
<span id="aria_subscript_mixed" role="sUBSCRIPt"></span>
<span id="aria_suggestion" role="suggestion"></span>
<span id="aria_suggestion_mixed" role="sUGGESTIOn"></span>
<span id="aria_superscript" role="superscript"></span>
<span id="aria_superscript_mixed" role="sUPERSCRIPt"></span>
<span id="aria_switch" role="switch"></span>
<span id="aria_switch_mixed" role="sWITCh"></span>
<span id="aria_tab" role="tab"></span>

Просмотреть файл

@ -151,50 +151,50 @@
attrs = {};
testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
attrs = { "text-position": "super", "font-size": "10pt" };
testTextAttrs(ID, 5, attrs, defAttrs, 5, 13);
// Embedded object (sup) has no attributes but takes up one character.
testTextAttrs(ID, 5, {}, {}, 5, 6);
attrs = {};
testTextAttrs(ID, 13, attrs, defAttrs, 13, 27);
testTextAttrs(ID, 6, attrs, defAttrs, 6, 20);
attrs = { "text-position": "super" };
testTextAttrs(ID, 27, attrs, defAttrs, 27, 35);
testTextAttrs(ID, 20, attrs, defAttrs, 20, 28);
attrs = {};
testTextAttrs(ID, 35, attrs, defAttrs, 35, 39);
testTextAttrs(ID, 28, attrs, defAttrs, 28, 32);
attrs = { "text-position": "sub", "font-size": "10pt" };
testTextAttrs(ID, 39, attrs, defAttrs, 39, 50);
// Embedded object (sub) has no attributes but takes up one character.
testTextAttrs(ID, 32, {}, {}, 32, 33);
attrs = {};
testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
testTextAttrs(ID, 33, attrs, defAttrs, 33, 38);
attrs = { "text-position": "sub" };
testTextAttrs(ID, 55, attrs, defAttrs, 55, 64);
testTextAttrs(ID, 38, attrs, defAttrs, 38, 47);
attrs = {};
testTextAttrs(ID, 64, attrs, defAttrs, 64, 69);
testTextAttrs(ID, 47, attrs, defAttrs, 47, 52);
attrs = { "text-position": "super" };
testTextAttrs(ID, 69, attrs, defAttrs, 69, 84);
testTextAttrs(ID, 52, attrs, defAttrs, 52, 67);
attrs = {};
testTextAttrs(ID, 84, attrs, defAttrs, 84, 89);
testTextAttrs(ID, 67, attrs, defAttrs, 67, 72);
attrs = { "text-position": "sub" };
testTextAttrs(ID, 89, attrs, defAttrs, 89, 102);
testTextAttrs(ID, 72, attrs, defAttrs, 72, 85);
attrs = {};
testTextAttrs(ID, 102, attrs, defAttrs, 102, 107);
testTextAttrs(ID, 85, attrs, defAttrs, 85, 90);
attrs = { "text-position": "super" };
testTextAttrs(ID, 107, attrs, defAttrs, 107, 123);
testTextAttrs(ID, 90, attrs, defAttrs, 90, 106);
attrs = {};
testTextAttrs(ID, 123, attrs, defAttrs, 123, 128);
testTextAttrs(ID, 106, attrs, defAttrs, 106, 111);
attrs = { "text-position": "sub" };
testTextAttrs(ID, 128, attrs, defAttrs, 128, 142);
testTextAttrs(ID, 111, attrs, defAttrs, 111, 125);
// ////////////////////////////////////////////////////////////////////////
// area7
@ -573,6 +573,75 @@
testDefaultTextAttrs(ID, defAttrs);
testTextAttrs(ID, -1, {}, defAttrs, 0, 11);
// ////////////////////////////////////////////////////////////////////////
// HTML sub tag offset test - verify attributes
ID = "sub_tag";
defAttrs = buildDefaultTextAttrs(ID, "10pt");
defAttrs["text-position"] = "sub";
testDefaultTextAttrs(ID, defAttrs);
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
// ////////////////////////////////////////////////////////////////////////
// HTML sup tag offset test - verify attributes
ID = "sup_tag";
defAttrs = buildDefaultTextAttrs(ID, "10pt");
defAttrs["text-position"] = "super";
testDefaultTextAttrs(ID, defAttrs);
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
// ////////////////////////////////////////////////////////////////////////
// ARIA subscript role - verify text-position attribute
ID = "subscript_role";
defAttrs = { "text-position": "sub" };
testDefaultTextAttrs(ID, defAttrs, true);
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
// ////////////////////////////////////////////////////////////////////////
// ARIA superscript role - verify text-position attribute
ID = "superscript_role";
defAttrs = { "text-position": "super" };
testDefaultTextAttrs(ID, defAttrs, true);
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
// ////////////////////////////////////////////////////////////////////////
// test text-position attributes in various situations
ID = "superscript_role_in_div";
defAttrs = { "text-position": "super" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "sub_within_superscript_role";
defAttrs = { "text-position": "sub" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "sup_within_subscript_role";
defAttrs = { "text-position": "super" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "sub_within_sup";
defAttrs = { "text-position": "sub" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "sup_within_sub";
defAttrs = { "text-position": "super" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "css_sub_within_superscript_role";
attrs = { "text-position": "sub" };
testTextAttrs(ID, 0, attrs, {}, 0, 11, true);
ID = "css_super_within_subscript_role";
attrs = { "text-position": "super" };
testTextAttrs(ID, 0, attrs, {}, 0, 11, true);
ID = "sub_with_superscript_role";
defAttrs = { "text-position": "super" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
ID = "sup_with_subscript_role";
defAttrs = { "text-position": "sub" };
testTextAttrs(ID, 0, {}, defAttrs, 0, 11, true);
SimpleTest.finish();
}
@ -734,5 +803,21 @@
<p id="area20" style="font-size: 15pt;">offset test</p>
<!-- subscript, superscript tests -->
<sub id="sub_tag">offset test</sub>
<sup id="sup_tag">offset test</sup>
<p id="subscript_role" role="subscript">offset test</p>
<p id="superscript_role" role="superscript">offset test</p>
<div><span id="superscript_role_in_div" role="superscript">offset test</span></div>
<p role="superscript"><sub id="sub_within_superscript_role">offset test</sub></p>
<p role="subscript"><sup id="sup_within_subscript_role">offset test</sup></p>
<sup><sub id="sub_within_sup">offset test</sub></sup>
<sub><sup id="sup_within_sub">offset test</sup></sub>
<p id="css_sub_within_superscript_role" role="superscript"><span style="vertical-align: sub">offset test</span></p>
<p id="css_super_within_subscript_role" role="subscript"><span style="vertical-align: super">offset test</span></p>
<sub id="sub_with_superscript_role" role="superscript">offset test</sub>
<sup id="sup_with_subscript_role" role="subscript">offset test</sup>
</body>
</html>