1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "LocalAccessible-inl.h"
9 #include "AccAttributes.h"
10 #include "nsAccUtils.h"
11 #include "nsCoreUtils.h"
12 #include "StyleInfo.h"
14 #include "gfxTextRun.h"
15 #include "nsFontMetrics.h"
16 #include "nsLayoutUtils.h"
17 #include "nsContainerFrame.h"
18 #include "nsStyleUtil.h"
19 #include "HyperTextAccessible.h"
20 #include "mozilla/AppUnits.h"
21 #include "mozilla/gfx/2D.h"
23 using namespace mozilla
;
24 using namespace mozilla::a11y
;
26 ////////////////////////////////////////////////////////////////////////////////
28 ////////////////////////////////////////////////////////////////////////////////
30 void TextAttrsMgr::GetAttributes(AccAttributes
* aAttributes
,
31 uint32_t* aStartOffset
, uint32_t* aEndOffset
) {
32 // 1. Hyper text accessible must be specified always.
33 // 2. Offset accessible must be specified in
34 // the case of text attributes. Result hyper text offsets are optional if you
35 // just want the attributes for a single text Accessible.
36 // 3. Offset accessible and result hyper text offsets must not be specified
37 // but include default text attributes flag and attributes list must be
38 // specified in the case of default text attributes.
40 mHyperTextAcc
&& ((mOffsetAcc
&& mOffsetAccIdx
!= -1) ||
41 (!mOffsetAcc
&& mOffsetAccIdx
== -1 && !aStartOffset
&&
42 !aEndOffset
&& mIncludeDefAttrs
&& aAttributes
)),
43 "Wrong usage of TextAttrsMgr!");
45 // Embedded objects are combined into own range with empty attributes set.
46 if (mOffsetAcc
&& !mOffsetAcc
->IsText()) {
50 for (int32_t childIdx
= mOffsetAccIdx
- 1; childIdx
>= 0; childIdx
--) {
51 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
52 if (currAcc
->IsText()) break;
57 uint32_t childCount
= mHyperTextAcc
->ChildCount();
58 for (uint32_t childIdx
= mOffsetAccIdx
+ 1; childIdx
< childCount
;
60 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
61 if (currAcc
->IsText()) break;
69 // Get the content and frame of the accessible. In the case of document
70 // accessible it's role content and root frame.
71 nsIContent
* hyperTextElm
= mHyperTextAcc
->GetContent();
73 return; // XXX: we don't support text attrs on document with no body
76 nsIFrame
* rootFrame
= mHyperTextAcc
->GetFrame();
81 nsIContent
*offsetNode
= nullptr, *offsetElm
= nullptr;
82 nsIFrame
* frame
= nullptr;
84 offsetNode
= mOffsetAcc
->GetContent();
85 offsetElm
= nsCoreUtils::GetDOMElementFor(offsetNode
);
86 MOZ_ASSERT(offsetElm
, "No element for offset accessible!");
87 if (!offsetElm
) return;
89 frame
= offsetElm
->GetPrimaryFrame();
92 // "language" text attribute
93 LangTextAttr
langTextAttr(mHyperTextAcc
, hyperTextElm
, offsetNode
);
95 // "aria-invalid" text attribute
96 InvalidTextAttr
invalidTextAttr(hyperTextElm
, offsetNode
);
98 // "background-color" text attribute
99 BGColorTextAttr
bgColorTextAttr(rootFrame
, frame
);
101 // "color" text attribute
102 ColorTextAttr
colorTextAttr(rootFrame
, frame
);
104 // "font-family" text attribute
105 FontFamilyTextAttr
fontFamilyTextAttr(rootFrame
, frame
);
107 // "font-size" text attribute
108 FontSizeTextAttr
fontSizeTextAttr(rootFrame
, frame
);
110 // "font-style" text attribute
111 FontStyleTextAttr
fontStyleTextAttr(rootFrame
, frame
);
113 // "font-weight" text attribute
114 FontWeightTextAttr
fontWeightTextAttr(rootFrame
, frame
);
116 // "auto-generated" text attribute
117 AutoGeneratedTextAttr
autoGenTextAttr(mHyperTextAcc
, mOffsetAcc
);
119 // "text-underline(line-through)-style(color)" text attributes
120 TextDecorTextAttr
textDecorTextAttr(rootFrame
, frame
);
122 // "text-position" text attribute
123 TextPosTextAttr
textPosTextAttr(rootFrame
, frame
, hyperTextElm
, offsetNode
);
125 TextAttr
* attrArray
[] = {
126 &langTextAttr
, &invalidTextAttr
, &bgColorTextAttr
,
127 &colorTextAttr
, &fontFamilyTextAttr
, &fontSizeTextAttr
,
128 &fontStyleTextAttr
, &fontWeightTextAttr
, &autoGenTextAttr
,
129 &textDecorTextAttr
, &textPosTextAttr
};
131 // Expose text attributes if applicable.
133 for (uint32_t idx
= 0; idx
< ArrayLength(attrArray
); idx
++) {
134 attrArray
[idx
]->Expose(aAttributes
, mIncludeDefAttrs
);
138 // Expose text attributes range where they are applied if applicable.
140 GetRange(attrArray
, ArrayLength(attrArray
), aStartOffset
, aEndOffset
);
144 void TextAttrsMgr::GetRange(TextAttr
* aAttrArray
[], uint32_t aAttrArrayLen
,
145 uint32_t* aStartOffset
, uint32_t* aEndOffset
) {
146 // Navigate backward from anchor accessible to find start offset.
147 for (int32_t childIdx
= mOffsetAccIdx
- 1; childIdx
>= 0; childIdx
--) {
148 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
150 // Stop on embedded accessible since embedded accessibles are combined into
152 if (!currAcc
->IsText()) break;
154 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc
->GetContent()),
155 "Text accessible has to have an associated DOM element");
157 bool offsetFound
= false;
158 for (uint32_t attrIdx
= 0; attrIdx
< aAttrArrayLen
; attrIdx
++) {
159 TextAttr
* textAttr
= aAttrArray
[attrIdx
];
160 if (!textAttr
->Equal(currAcc
)) {
166 if (offsetFound
) break;
168 *(aStartOffset
) -= nsAccUtils::TextLength(currAcc
);
171 // Navigate forward from anchor accessible to find end offset.
172 uint32_t childLen
= mHyperTextAcc
->ChildCount();
173 for (uint32_t childIdx
= mOffsetAccIdx
+ 1; childIdx
< childLen
; childIdx
++) {
174 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
175 if (!currAcc
->IsText()) break;
177 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc
->GetContent()),
178 "Text accessible has to have an associated DOM element");
180 bool offsetFound
= false;
181 for (uint32_t attrIdx
= 0; attrIdx
< aAttrArrayLen
; attrIdx
++) {
182 TextAttr
* textAttr
= aAttrArray
[attrIdx
];
184 // Alter the end offset when text attribute changes its value and stop
186 if (!textAttr
->Equal(currAcc
)) {
192 if (offsetFound
) break;
194 (*aEndOffset
) += nsAccUtils::TextLength(currAcc
);
198 ////////////////////////////////////////////////////////////////////////////////
200 ////////////////////////////////////////////////////////////////////////////////
202 TextAttrsMgr::LangTextAttr::LangTextAttr(HyperTextAccessible
* aRoot
,
203 nsIContent
* aRootElm
, nsIContent
* aElm
)
204 : TTextAttr
<nsString
>(!aElm
), mRootContent(aRootElm
) {
205 aRoot
->Language(mRootNativeValue
);
206 mIsRootDefined
= !mRootNativeValue
.IsEmpty();
209 nsCoreUtils::GetLanguageFor(aElm
, mRootContent
, mNativeValue
);
210 mIsDefined
= !mNativeValue
.IsEmpty();
214 TextAttrsMgr::LangTextAttr::~LangTextAttr() {}
216 bool TextAttrsMgr::LangTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
218 nsCoreUtils::GetLanguageFor(aAccessible
->GetContent(), mRootContent
, *aValue
);
219 return !aValue
->IsEmpty();
222 void TextAttrsMgr::LangTextAttr::ExposeValue(AccAttributes
* aAttributes
,
223 const nsString
& aValue
) {
224 RefPtr
<nsAtom
> lang
= NS_Atomize(aValue
);
225 aAttributes
->SetAttribute(nsGkAtoms::language
, lang
);
228 ////////////////////////////////////////////////////////////////////////////////
230 ////////////////////////////////////////////////////////////////////////////////
232 TextAttrsMgr::InvalidTextAttr::InvalidTextAttr(nsIContent
* aRootElm
,
234 : TTextAttr
<uint32_t>(!aElm
), mRootElm(aRootElm
) {
235 mIsRootDefined
= GetValue(mRootElm
, &mRootNativeValue
);
236 if (aElm
) mIsDefined
= GetValue(aElm
, &mNativeValue
);
239 bool TextAttrsMgr::InvalidTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
241 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
242 return elm
? GetValue(elm
, aValue
) : false;
245 void TextAttrsMgr::InvalidTextAttr::ExposeValue(AccAttributes
* aAttributes
,
246 const uint32_t& aValue
) {
249 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::_false
);
253 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::grammar
);
257 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::spelling
);
261 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::_true
);
266 bool TextAttrsMgr::InvalidTextAttr::GetValue(nsIContent
* aElm
,
268 nsIContent
* elm
= aElm
;
270 if (nsAccUtils::HasDefinedARIAToken(elm
, nsGkAtoms::aria_invalid
)) {
271 static dom::Element::AttrValuesArray tokens
[] = {
272 nsGkAtoms::_false
, nsGkAtoms::grammar
, nsGkAtoms::spelling
, nullptr};
274 int32_t idx
= nsAccUtils::FindARIAAttrValueIn(
275 elm
->AsElement(), nsGkAtoms::aria_invalid
, tokens
, eCaseMatters
);
291 } while ((elm
= elm
->GetParent()) && elm
!= mRootElm
);
296 ////////////////////////////////////////////////////////////////////////////////
298 ////////////////////////////////////////////////////////////////////////////////
300 TextAttrsMgr::BGColorTextAttr::BGColorTextAttr(nsIFrame
* aRootFrame
,
302 : TTextAttr
<nscolor
>(!aFrame
), mRootFrame(aRootFrame
) {
303 mIsRootDefined
= GetColor(mRootFrame
, &mRootNativeValue
);
304 if (aFrame
) mIsDefined
= GetColor(aFrame
, &mNativeValue
);
307 bool TextAttrsMgr::BGColorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
309 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
311 nsIFrame
* frame
= elm
->GetPrimaryFrame();
313 return GetColor(frame
, aValue
);
319 void TextAttrsMgr::BGColorTextAttr::ExposeValue(AccAttributes
* aAttributes
,
320 const nscolor
& aValue
) {
321 aAttributes
->SetAttribute(nsGkAtoms::backgroundColor
, Color
{aValue
});
324 bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame
* aFrame
,
326 nscolor backgroundColor
= aFrame
->StyleBackground()->BackgroundColor(aFrame
);
327 if (NS_GET_A(backgroundColor
) > 0) {
328 *aColor
= backgroundColor
;
332 nsContainerFrame
* parentFrame
= aFrame
->GetParent();
334 *aColor
= aFrame
->PresContext()->DefaultBackgroundColor();
338 // Each frame of parents chain for the initially passed 'aFrame' has
339 // transparent background color. So background color isn't changed from
340 // 'mRootFrame' to initially passed 'aFrame'.
341 if (parentFrame
== mRootFrame
) return false;
343 return GetColor(parentFrame
, aColor
);
346 ////////////////////////////////////////////////////////////////////////////////
348 ////////////////////////////////////////////////////////////////////////////////
350 TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame
* aRootFrame
,
352 : TTextAttr
<nscolor
>(!aFrame
) {
353 mRootNativeValue
= aRootFrame
->StyleText()->mColor
.ToColor();
354 mIsRootDefined
= true;
357 mNativeValue
= aFrame
->StyleText()->mColor
.ToColor();
362 bool TextAttrsMgr::ColorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
364 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
366 if (nsIFrame
* frame
= elm
->GetPrimaryFrame()) {
367 *aValue
= frame
->StyleText()->mColor
.ToColor();
374 void TextAttrsMgr::ColorTextAttr::ExposeValue(AccAttributes
* aAttributes
,
375 const nscolor
& aValue
) {
376 aAttributes
->SetAttribute(nsGkAtoms::color
, Color
{aValue
});
379 ////////////////////////////////////////////////////////////////////////////////
380 // FontFamilyTextAttr
381 ////////////////////////////////////////////////////////////////////////////////
383 TextAttrsMgr::FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame
* aRootFrame
,
385 : TTextAttr
<nsString
>(!aFrame
) {
386 mIsRootDefined
= GetFontFamily(aRootFrame
, mRootNativeValue
);
388 if (aFrame
) mIsDefined
= GetFontFamily(aFrame
, mNativeValue
);
391 bool TextAttrsMgr::FontFamilyTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
393 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
395 nsIFrame
* frame
= elm
->GetPrimaryFrame();
397 return GetFontFamily(frame
, *aValue
);
403 void TextAttrsMgr::FontFamilyTextAttr::ExposeValue(AccAttributes
* aAttributes
,
404 const nsString
& aValue
) {
405 RefPtr
<nsAtom
> family
= NS_Atomize(aValue
);
406 aAttributes
->SetAttribute(nsGkAtoms::font_family
, family
);
409 bool TextAttrsMgr::FontFamilyTextAttr::GetFontFamily(nsIFrame
* aFrame
,
411 RefPtr
<nsFontMetrics
> fm
=
412 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, 1.0f
);
414 gfxFontGroup
* fontGroup
= fm
->GetThebesFontGroup();
415 RefPtr
<gfxFont
> font
= fontGroup
->GetFirstValidFont();
416 gfxFontEntry
* fontEntry
= font
->GetFontEntry();
417 aFamily
.Append(NS_ConvertUTF8toUTF16(fontEntry
->FamilyName()));
421 ////////////////////////////////////////////////////////////////////////////////
423 ////////////////////////////////////////////////////////////////////////////////
425 TextAttrsMgr::FontSizeTextAttr::FontSizeTextAttr(nsIFrame
* aRootFrame
,
427 : TTextAttr
<nscoord
>(!aFrame
) {
428 mDC
= aRootFrame
->PresContext()->DeviceContext();
430 mRootNativeValue
= aRootFrame
->StyleFont()->mSize
.ToAppUnits();
431 mIsRootDefined
= true;
434 mNativeValue
= aFrame
->StyleFont()->mSize
.ToAppUnits();
439 bool TextAttrsMgr::FontSizeTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
441 nsIContent
* el
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
443 nsIFrame
* frame
= el
->GetPrimaryFrame();
445 *aValue
= frame
->StyleFont()->mSize
.ToAppUnits();
452 void TextAttrsMgr::FontSizeTextAttr::ExposeValue(AccAttributes
* aAttributes
,
453 const nscoord
& aValue
) {
454 // Convert from nscoord to pt.
456 // Note: according to IA2, "The conversion doesn't have to be exact.
457 // The intent is to give the user a feel for the size of the text."
459 // ATK does not specify a unit and will likely follow IA2 here.
461 // XXX todo: consider sharing this code with layout module? (bug 474621)
462 float px
= NSAppUnitsToFloatPixels(aValue
, mozilla::AppUnitsPerCSSPixel());
463 // Each pt is 4/3 of a CSS pixel.
464 FontSize fontSize
{NS_lround(px
* 3 / 4)};
466 aAttributes
->SetAttribute(nsGkAtoms::font_size
, fontSize
);
469 ////////////////////////////////////////////////////////////////////////////////
471 ////////////////////////////////////////////////////////////////////////////////
473 TextAttrsMgr::FontStyleTextAttr::FontStyleTextAttr(nsIFrame
* aRootFrame
,
475 : TTextAttr
<FontSlantStyle
>(!aFrame
) {
476 mRootNativeValue
= aRootFrame
->StyleFont()->mFont
.style
;
477 mIsRootDefined
= true;
480 mNativeValue
= aFrame
->StyleFont()->mFont
.style
;
485 bool TextAttrsMgr::FontStyleTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
486 FontSlantStyle
* aValue
) {
487 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
489 nsIFrame
* frame
= elm
->GetPrimaryFrame();
491 *aValue
= frame
->StyleFont()->mFont
.style
;
498 void TextAttrsMgr::FontStyleTextAttr::ExposeValue(
499 AccAttributes
* aAttributes
, const FontSlantStyle
& aValue
) {
500 if (aValue
.IsNormal()) {
501 aAttributes
->SetAttribute(nsGkAtoms::font_style
, nsGkAtoms::normal
);
502 } else if (aValue
.IsItalic()) {
503 RefPtr
<nsAtom
> atom
= NS_Atomize("italic");
504 aAttributes
->SetAttribute(nsGkAtoms::font_style
, atom
);
509 CopyUTF8toUTF16(s
, wide
);
510 aAttributes
->SetAttribute(nsGkAtoms::font_style
, std::move(wide
));
514 ////////////////////////////////////////////////////////////////////////////////
515 // FontWeightTextAttr
516 ////////////////////////////////////////////////////////////////////////////////
518 TextAttrsMgr::FontWeightTextAttr::FontWeightTextAttr(nsIFrame
* aRootFrame
,
520 : TTextAttr
<FontWeight
>(!aFrame
) {
521 mRootNativeValue
= GetFontWeight(aRootFrame
);
522 mIsRootDefined
= true;
525 mNativeValue
= GetFontWeight(aFrame
);
530 bool TextAttrsMgr::FontWeightTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
531 FontWeight
* aValue
) {
532 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
534 nsIFrame
* frame
= elm
->GetPrimaryFrame();
536 *aValue
= GetFontWeight(frame
);
543 void TextAttrsMgr::FontWeightTextAttr::ExposeValue(AccAttributes
* aAttributes
,
544 const FontWeight
& aValue
) {
545 int value
= aValue
.ToIntRounded();
546 aAttributes
->SetAttribute(nsGkAtoms::fontWeight
, value
);
549 FontWeight
TextAttrsMgr::FontWeightTextAttr::GetFontWeight(nsIFrame
* aFrame
) {
550 // nsFont::width isn't suitable here because it's necessary to expose real
551 // value of font weight (used font might not have some font weight values).
552 RefPtr
<nsFontMetrics
> fm
=
553 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, 1.0f
);
555 gfxFontGroup
* fontGroup
= fm
->GetThebesFontGroup();
556 RefPtr
<gfxFont
> font
= fontGroup
->GetFirstValidFont();
558 // When there doesn't exist a bold font in the family and so the rendering of
559 // a non-bold font face is changed so that the user sees what looks like a
560 // bold font, i.e. synthetic bolding is used. (Simply returns false on any
561 // platforms that don't use the multi-strike synthetic bolding.)
562 if (font
->ApplySyntheticBold()) {
563 return FontWeight::BOLD
;
566 // On Windows, font->GetStyle()->weight will give the same weight as
567 // fontEntry->Weight(), the weight of the first font in the font group,
568 // which may not be the weight of the font face used to render the
569 // characters. On Mac, font->GetStyle()->weight will just give the same
570 // number as getComputedStyle(). fontEntry->Weight() will give the weight
571 // range supported by the font face used, so we clamp the weight that was
572 // requested by style to what is actually supported by the font.
573 gfxFontEntry
* fontEntry
= font
->GetFontEntry();
574 return fontEntry
->Weight().Clamp(font
->GetStyle()->weight
);
577 ////////////////////////////////////////////////////////////////////////////////
578 // AutoGeneratedTextAttr
579 ////////////////////////////////////////////////////////////////////////////////
580 TextAttrsMgr::AutoGeneratedTextAttr::AutoGeneratedTextAttr(
581 HyperTextAccessible
* aHyperTextAcc
, LocalAccessible
* aAccessible
)
582 : TTextAttr
<bool>(!aAccessible
) {
583 mRootNativeValue
= false;
584 mIsRootDefined
= false;
587 mIsDefined
= mNativeValue
=
588 ((aAccessible
->NativeRole() == roles::STATICTEXT
) ||
589 (aAccessible
->NativeRole() == roles::LISTITEM_MARKER
));
593 bool TextAttrsMgr::AutoGeneratedTextAttr::GetValueFor(
594 LocalAccessible
* aAccessible
, bool* aValue
) {
595 return *aValue
= (aAccessible
->NativeRole() == roles::STATICTEXT
);
598 void TextAttrsMgr::AutoGeneratedTextAttr::ExposeValue(
599 AccAttributes
* aAttributes
, const bool& aValue
) {
600 aAttributes
->SetAttribute(nsGkAtoms::auto_generated
, aValue
);
603 ////////////////////////////////////////////////////////////////////////////////
605 ////////////////////////////////////////////////////////////////////////////////
607 TextAttrsMgr::TextDecorValue::TextDecorValue(nsIFrame
* aFrame
) {
608 const nsStyleTextReset
* textReset
= aFrame
->StyleTextReset();
609 mStyle
= textReset
->mTextDecorationStyle
;
610 mColor
= textReset
->mTextDecorationColor
.CalcColor(aFrame
);
612 textReset
->mTextDecorationLine
& (StyleTextDecorationLine::UNDERLINE
|
613 StyleTextDecorationLine::LINE_THROUGH
);
616 TextAttrsMgr::TextDecorTextAttr::TextDecorTextAttr(nsIFrame
* aRootFrame
,
618 : TTextAttr
<TextDecorValue
>(!aFrame
) {
619 mRootNativeValue
= TextDecorValue(aRootFrame
);
620 mIsRootDefined
= mRootNativeValue
.IsDefined();
623 mNativeValue
= TextDecorValue(aFrame
);
624 mIsDefined
= mNativeValue
.IsDefined();
628 bool TextAttrsMgr::TextDecorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
629 TextDecorValue
* aValue
) {
630 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
632 nsIFrame
* frame
= elm
->GetPrimaryFrame();
634 *aValue
= TextDecorValue(frame
);
635 return aValue
->IsDefined();
641 void TextAttrsMgr::TextDecorTextAttr::ExposeValue(
642 AccAttributes
* aAttributes
, const TextDecorValue
& aValue
) {
643 if (aValue
.IsUnderline()) {
644 RefPtr
<nsAtom
> underlineStyle
=
645 StyleInfo::TextDecorationStyleToAtom(aValue
.Style());
646 aAttributes
->SetAttribute(nsGkAtoms::textUnderlineStyle
, underlineStyle
);
648 aAttributes
->SetAttribute(nsGkAtoms::textUnderlineColor
,
649 Color
{aValue
.Color()});
653 if (aValue
.IsLineThrough()) {
654 RefPtr
<nsAtom
> lineThroughStyle
=
655 StyleInfo::TextDecorationStyleToAtom(aValue
.Style());
656 aAttributes
->SetAttribute(nsGkAtoms::textLineThroughStyle
,
659 aAttributes
->SetAttribute(nsGkAtoms::textLineThroughColor
,
660 Color
{aValue
.Color()});
664 ////////////////////////////////////////////////////////////////////////////////
666 ////////////////////////////////////////////////////////////////////////////////
668 TextAttrsMgr::TextPosTextAttr::TextPosTextAttr(nsIFrame
* aRootFrame
,
670 nsIContent
* aRootElm
,
672 : TTextAttr
<Maybe
<TextPosValue
>>(!aFrame
&& !aElm
), mRootElm(aRootElm
) {
673 // Get the text-position values for the roots and children.
674 // If we find an ARIA text-position value on a DOM element - searching up
675 // from the supplied root DOM element - use the associated frame as the root
676 // frame. This ensures that we're using the proper root frame for comparison.
677 nsIFrame
* ariaFrame
= nullptr;
678 Maybe
<TextPosValue
> rootAria
= GetAriaTextPosValue(aRootElm
, ariaFrame
);
679 if (rootAria
&& ariaFrame
) {
680 aRootFrame
= ariaFrame
;
682 Maybe
<TextPosValue
> rootLayout
= GetLayoutTextPosValue(aRootFrame
);
683 Maybe
<TextPosValue
> childLayout
;
684 Maybe
<TextPosValue
> childAria
;
686 childLayout
= GetLayoutTextPosValue(aFrame
);
689 childAria
= GetAriaTextPosValue(aElm
);
692 // Aria values take precedence over layout values.
693 mIsRootDefined
= rootAria
|| rootLayout
;
694 mRootNativeValue
= rootAria
? rootAria
: rootLayout
;
695 mIsDefined
= childAria
|| childLayout
;
696 mNativeValue
= childAria
? childAria
: childLayout
;
698 // If there's no child text-position information from ARIA, and the child
699 // layout info is equivalent to the root layout info (i.e., it's inherited),
700 // then we should prefer the root information.
701 if (!childAria
&& childLayout
== rootLayout
) {
706 bool TextAttrsMgr::TextPosTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
707 Maybe
<TextPosValue
>* aValue
) {
708 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
710 nsIFrame
* frame
= elm
->GetPrimaryFrame();
712 Maybe
<TextPosValue
> layoutValue
= GetLayoutTextPosValue(frame
);
713 Maybe
<TextPosValue
> ariaValue
= GetAriaTextPosValue(elm
);
715 *aValue
= ariaValue
? ariaValue
: layoutValue
;
716 return aValue
->isSome();
722 void TextAttrsMgr::TextPosTextAttr::ExposeValue(
723 AccAttributes
* aAttributes
, const Maybe
<TextPosValue
>& aValue
) {
724 if (aValue
.isNothing()) {
728 RefPtr
<nsAtom
> atom
= nullptr;
730 case eTextPosBaseline
:
731 atom
= nsGkAtoms::baseline
;
735 atom
= nsGkAtoms::sub
;
739 atom
= NS_Atomize("super");
744 aAttributes
->SetAttribute(nsGkAtoms::textPosition
, atom
);
748 Maybe
<TextAttrsMgr::TextPosValue
>
749 TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent
* aElm
) const {
750 nsIFrame
* ariaFrame
= nullptr;
751 return GetAriaTextPosValue(aElm
, ariaFrame
);
754 Maybe
<TextAttrsMgr::TextPosValue
>
755 TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent
* aElm
,
756 nsIFrame
*& ariaFrame
) const {
757 // Search for the superscript and subscript roles that imply text-position.
758 const nsIContent
* elm
= aElm
;
760 if (elm
->IsElement()) {
761 const mozilla::dom::Element
* domElm
= elm
->AsElement();
762 static const dom::Element::AttrValuesArray tokens
[] = {
763 nsGkAtoms::subscript
, nsGkAtoms::superscript
, nullptr};
764 const int32_t valueIdx
= domElm
->FindAttrValueIn(
765 kNameSpaceID_None
, nsGkAtoms::role
, tokens
, eCaseMatters
);
766 ariaFrame
= domElm
->GetPrimaryFrame();
768 return Some(eTextPosSub
);
771 return Some(eTextPosSuper
);
774 } while ((elm
= elm
->GetParent()) && elm
!= mRootElm
);
780 Maybe
<TextAttrsMgr::TextPosValue
>
781 TextAttrsMgr::TextPosTextAttr::GetLayoutTextPosValue(nsIFrame
* aFrame
) const {
782 const auto& verticalAlign
= aFrame
->StyleDisplay()->mVerticalAlign
;
783 if (verticalAlign
.IsKeyword()) {
784 switch (verticalAlign
.AsKeyword()) {
785 case StyleVerticalAlignKeyword::Baseline
:
786 return Some(eTextPosBaseline
);
787 case StyleVerticalAlignKeyword::Sub
:
788 return Some(eTextPosSub
);
789 case StyleVerticalAlignKeyword::Super
:
790 return Some(eTextPosSuper
);
791 // No good guess for the rest, so do not expose value of text-position
798 const auto& length
= verticalAlign
.AsLength();
799 if (length
.ConvertsToPercentage()) {
800 const float percentValue
= length
.ToPercentage();
801 return percentValue
> 0 ? Some(eTextPosSuper
)
802 : (percentValue
< 0 ? Some(eTextPosSub
)
803 : Some(eTextPosBaseline
));
806 if (length
.ConvertsToLength()) {
807 const nscoord coordValue
= length
.ToLength();
808 return coordValue
> 0
809 ? Some(eTextPosSuper
)
810 : (coordValue
< 0 ? Some(eTextPosSub
) : Some(eTextPosBaseline
));
813 if (const nsIContent
* content
= aFrame
->GetContent()) {
814 if (content
->IsHTMLElement(nsGkAtoms::sup
)) return Some(eTextPosSuper
);
815 if (content
->IsHTMLElement(nsGkAtoms::sub
)) return Some(eTextPosSub
);