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 "AccAttributes.h"
9 #include "nsAccUtils.h"
10 #include "nsCoreUtils.h"
11 #include "StyleInfo.h"
13 #include "gfxTextRun.h"
14 #include "nsFontMetrics.h"
15 #include "nsLayoutUtils.h"
16 #include "nsContainerFrame.h"
17 #include "HyperTextAccessible.h"
18 #include "mozilla/AppUnits.h"
20 using namespace mozilla
;
21 using namespace mozilla::a11y
;
23 ////////////////////////////////////////////////////////////////////////////////
25 ////////////////////////////////////////////////////////////////////////////////
27 void TextAttrsMgr::GetAttributes(AccAttributes
* aAttributes
,
28 uint32_t* aStartOffset
, uint32_t* aEndOffset
) {
29 // 1. Hyper text accessible must be specified always.
30 // 2. Offset accessible must be specified in
31 // the case of text attributes. Result hyper text offsets are optional if you
32 // just want the attributes for a single text Accessible.
33 // 3. Offset accessible and result hyper text offsets must not be specified
34 // but include default text attributes flag and attributes list must be
35 // specified in the case of default text attributes.
37 mHyperTextAcc
&& ((mOffsetAcc
&& mOffsetAccIdx
!= -1) ||
38 (!mOffsetAcc
&& mOffsetAccIdx
== -1 && !aStartOffset
&&
39 !aEndOffset
&& mIncludeDefAttrs
&& aAttributes
)),
40 "Wrong usage of TextAttrsMgr!");
42 // Embedded objects are combined into own range with empty attributes set.
43 if (mOffsetAcc
&& !mOffsetAcc
->IsText()) {
47 for (int32_t childIdx
= mOffsetAccIdx
- 1; childIdx
>= 0; childIdx
--) {
48 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
49 if (currAcc
->IsText()) break;
54 uint32_t childCount
= mHyperTextAcc
->ChildCount();
55 for (uint32_t childIdx
= mOffsetAccIdx
+ 1; childIdx
< childCount
;
57 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
58 if (currAcc
->IsText()) break;
66 // Get the content and frame of the accessible. In the case of document
67 // accessible it's role content and root frame.
68 nsIContent
* hyperTextElm
= mHyperTextAcc
->GetContent();
70 return; // XXX: we don't support text attrs on document with no body
73 nsIFrame
* rootFrame
= mHyperTextAcc
->GetFrame();
78 nsIContent
*offsetNode
= nullptr, *offsetElm
= nullptr;
79 nsIFrame
* frame
= nullptr;
81 offsetNode
= mOffsetAcc
->GetContent();
82 offsetElm
= nsCoreUtils::GetDOMElementFor(offsetNode
);
83 MOZ_ASSERT(offsetElm
, "No element for offset accessible!");
84 if (!offsetElm
) return;
86 frame
= offsetElm
->GetPrimaryFrame();
89 // "language" text attribute
90 LangTextAttr
langTextAttr(mHyperTextAcc
, hyperTextElm
, offsetNode
);
92 // "aria-invalid" text attribute
93 InvalidTextAttr
invalidTextAttr(hyperTextElm
, offsetNode
);
95 // "background-color" text attribute
96 BGColorTextAttr
bgColorTextAttr(rootFrame
, frame
);
98 // "color" text attribute
99 ColorTextAttr
colorTextAttr(rootFrame
, frame
);
101 // "font-family" text attribute
102 FontFamilyTextAttr
fontFamilyTextAttr(rootFrame
, frame
);
104 // "font-size" text attribute
105 FontSizeTextAttr
fontSizeTextAttr(rootFrame
, frame
);
107 // "font-style" text attribute
108 FontStyleTextAttr
fontStyleTextAttr(rootFrame
, frame
);
110 // "font-weight" text attribute
111 FontWeightTextAttr
fontWeightTextAttr(rootFrame
, frame
);
113 // "auto-generated" text attribute
114 AutoGeneratedTextAttr
autoGenTextAttr(mHyperTextAcc
, mOffsetAcc
);
116 // "text-underline(line-through)-style(color)" text attributes
117 TextDecorTextAttr
textDecorTextAttr(rootFrame
, frame
);
119 // "text-position" text attribute
120 TextPosTextAttr
textPosTextAttr(rootFrame
, frame
, hyperTextElm
, offsetNode
);
122 TextAttr
* attrArray
[] = {
123 &langTextAttr
, &invalidTextAttr
, &bgColorTextAttr
,
124 &colorTextAttr
, &fontFamilyTextAttr
, &fontSizeTextAttr
,
125 &fontStyleTextAttr
, &fontWeightTextAttr
, &autoGenTextAttr
,
126 &textDecorTextAttr
, &textPosTextAttr
};
128 // Expose text attributes if applicable.
130 for (uint32_t idx
= 0; idx
< ArrayLength(attrArray
); idx
++) {
131 attrArray
[idx
]->Expose(aAttributes
, mIncludeDefAttrs
);
135 // Expose text attributes range where they are applied if applicable.
137 GetRange(attrArray
, ArrayLength(attrArray
), aStartOffset
, aEndOffset
);
141 void TextAttrsMgr::GetRange(TextAttr
* aAttrArray
[], uint32_t aAttrArrayLen
,
142 uint32_t* aStartOffset
, uint32_t* aEndOffset
) {
143 // Navigate backward from anchor accessible to find start offset.
144 for (int32_t childIdx
= mOffsetAccIdx
- 1; childIdx
>= 0; childIdx
--) {
145 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
147 // Stop on embedded accessible since embedded accessibles are combined into
149 if (!currAcc
->IsText()) break;
151 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc
->GetContent()),
152 "Text accessible has to have an associated DOM element");
154 bool offsetFound
= false;
155 for (uint32_t attrIdx
= 0; attrIdx
< aAttrArrayLen
; attrIdx
++) {
156 TextAttr
* textAttr
= aAttrArray
[attrIdx
];
157 if (!textAttr
->Equal(currAcc
)) {
163 if (offsetFound
) break;
165 *(aStartOffset
) -= nsAccUtils::TextLength(currAcc
);
168 // Navigate forward from anchor accessible to find end offset.
169 uint32_t childLen
= mHyperTextAcc
->ChildCount();
170 for (uint32_t childIdx
= mOffsetAccIdx
+ 1; childIdx
< childLen
; childIdx
++) {
171 LocalAccessible
* currAcc
= mHyperTextAcc
->LocalChildAt(childIdx
);
172 if (!currAcc
->IsText()) break;
174 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc
->GetContent()),
175 "Text accessible has to have an associated DOM element");
177 bool offsetFound
= false;
178 for (uint32_t attrIdx
= 0; attrIdx
< aAttrArrayLen
; attrIdx
++) {
179 TextAttr
* textAttr
= aAttrArray
[attrIdx
];
181 // Alter the end offset when text attribute changes its value and stop
183 if (!textAttr
->Equal(currAcc
)) {
189 if (offsetFound
) break;
191 (*aEndOffset
) += nsAccUtils::TextLength(currAcc
);
195 ////////////////////////////////////////////////////////////////////////////////
197 ////////////////////////////////////////////////////////////////////////////////
199 TextAttrsMgr::LangTextAttr::LangTextAttr(HyperTextAccessible
* aRoot
,
200 nsIContent
* aRootElm
, nsIContent
* aElm
)
201 : TTextAttr
<nsString
>(!aElm
), mRootContent(aRootElm
) {
202 aRoot
->Language(mRootNativeValue
);
203 mIsRootDefined
= !mRootNativeValue
.IsEmpty();
206 nsCoreUtils::GetLanguageFor(aElm
, mRootContent
, mNativeValue
);
207 mIsDefined
= !mNativeValue
.IsEmpty();
211 TextAttrsMgr::LangTextAttr::~LangTextAttr() {}
213 bool TextAttrsMgr::LangTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
215 nsCoreUtils::GetLanguageFor(aAccessible
->GetContent(), mRootContent
, *aValue
);
216 return !aValue
->IsEmpty();
219 void TextAttrsMgr::LangTextAttr::ExposeValue(AccAttributes
* aAttributes
,
220 const nsString
& aValue
) {
221 RefPtr
<nsAtom
> lang
= NS_Atomize(aValue
);
222 aAttributes
->SetAttribute(nsGkAtoms::language
, lang
);
225 ////////////////////////////////////////////////////////////////////////////////
227 ////////////////////////////////////////////////////////////////////////////////
229 TextAttrsMgr::InvalidTextAttr::InvalidTextAttr(nsIContent
* aRootElm
,
231 : TTextAttr
<uint32_t>(!aElm
), mRootElm(aRootElm
) {
232 mIsRootDefined
= GetValue(mRootElm
, &mRootNativeValue
);
233 if (aElm
) mIsDefined
= GetValue(aElm
, &mNativeValue
);
236 bool TextAttrsMgr::InvalidTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
238 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
239 return elm
? GetValue(elm
, aValue
) : false;
242 void TextAttrsMgr::InvalidTextAttr::ExposeValue(AccAttributes
* aAttributes
,
243 const uint32_t& aValue
) {
246 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::_false
);
250 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::grammar
);
254 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::spelling
);
258 aAttributes
->SetAttribute(nsGkAtoms::invalid
, nsGkAtoms::_true
);
263 bool TextAttrsMgr::InvalidTextAttr::GetValue(nsIContent
* aElm
,
265 nsIContent
* elm
= aElm
;
267 if (nsAccUtils::HasDefinedARIAToken(elm
, nsGkAtoms::aria_invalid
)) {
268 static dom::Element::AttrValuesArray tokens
[] = {
269 nsGkAtoms::_false
, nsGkAtoms::grammar
, nsGkAtoms::spelling
, nullptr};
271 int32_t idx
= nsAccUtils::FindARIAAttrValueIn(
272 elm
->AsElement(), nsGkAtoms::aria_invalid
, tokens
, eCaseMatters
);
288 } while ((elm
= elm
->GetParent()) && elm
!= mRootElm
);
293 ////////////////////////////////////////////////////////////////////////////////
295 ////////////////////////////////////////////////////////////////////////////////
297 TextAttrsMgr::BGColorTextAttr::BGColorTextAttr(nsIFrame
* aRootFrame
,
299 : TTextAttr
<nscolor
>(!aFrame
), mRootFrame(aRootFrame
) {
300 mIsRootDefined
= GetColor(mRootFrame
, &mRootNativeValue
);
301 if (aFrame
) mIsDefined
= GetColor(aFrame
, &mNativeValue
);
304 bool TextAttrsMgr::BGColorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
306 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
308 nsIFrame
* frame
= elm
->GetPrimaryFrame();
310 return GetColor(frame
, aValue
);
316 void TextAttrsMgr::BGColorTextAttr::ExposeValue(AccAttributes
* aAttributes
,
317 const nscolor
& aValue
) {
318 aAttributes
->SetAttribute(nsGkAtoms::backgroundColor
, Color
{aValue
});
321 bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame
* aFrame
,
323 nscolor backgroundColor
= aFrame
->StyleBackground()->BackgroundColor(aFrame
);
324 if (NS_GET_A(backgroundColor
) > 0) {
325 *aColor
= backgroundColor
;
329 nsContainerFrame
* parentFrame
= aFrame
->GetParent();
331 *aColor
= aFrame
->PresContext()->DefaultBackgroundColor();
335 // Each frame of parents chain for the initially passed 'aFrame' has
336 // transparent background color. So background color isn't changed from
337 // 'mRootFrame' to initially passed 'aFrame'.
338 if (parentFrame
== mRootFrame
) return false;
340 return GetColor(parentFrame
, aColor
);
343 ////////////////////////////////////////////////////////////////////////////////
345 ////////////////////////////////////////////////////////////////////////////////
347 TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame
* aRootFrame
,
349 : TTextAttr
<nscolor
>(!aFrame
) {
350 mRootNativeValue
= aRootFrame
->StyleText()->mColor
.ToColor();
351 mIsRootDefined
= true;
354 mNativeValue
= aFrame
->StyleText()->mColor
.ToColor();
359 bool TextAttrsMgr::ColorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
361 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
363 if (nsIFrame
* frame
= elm
->GetPrimaryFrame()) {
364 *aValue
= frame
->StyleText()->mColor
.ToColor();
371 void TextAttrsMgr::ColorTextAttr::ExposeValue(AccAttributes
* aAttributes
,
372 const nscolor
& aValue
) {
373 aAttributes
->SetAttribute(nsGkAtoms::color
, Color
{aValue
});
376 ////////////////////////////////////////////////////////////////////////////////
377 // FontFamilyTextAttr
378 ////////////////////////////////////////////////////////////////////////////////
380 TextAttrsMgr::FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame
* aRootFrame
,
382 : TTextAttr
<nsString
>(!aFrame
) {
383 mIsRootDefined
= GetFontFamily(aRootFrame
, mRootNativeValue
);
385 if (aFrame
) mIsDefined
= GetFontFamily(aFrame
, mNativeValue
);
388 bool TextAttrsMgr::FontFamilyTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
390 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
392 nsIFrame
* frame
= elm
->GetPrimaryFrame();
394 return GetFontFamily(frame
, *aValue
);
400 void TextAttrsMgr::FontFamilyTextAttr::ExposeValue(AccAttributes
* aAttributes
,
401 const nsString
& aValue
) {
402 RefPtr
<nsAtom
> family
= NS_Atomize(aValue
);
403 aAttributes
->SetAttribute(nsGkAtoms::font_family
, family
);
406 bool TextAttrsMgr::FontFamilyTextAttr::GetFontFamily(nsIFrame
* aFrame
,
408 RefPtr
<nsFontMetrics
> fm
=
409 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, 1.0f
);
411 gfxFontGroup
* fontGroup
= fm
->GetThebesFontGroup();
412 RefPtr
<gfxFont
> font
= fontGroup
->GetFirstValidFont();
413 gfxFontEntry
* fontEntry
= font
->GetFontEntry();
414 aFamily
.Append(NS_ConvertUTF8toUTF16(fontEntry
->FamilyName()));
418 ////////////////////////////////////////////////////////////////////////////////
420 ////////////////////////////////////////////////////////////////////////////////
422 TextAttrsMgr::FontSizeTextAttr::FontSizeTextAttr(nsIFrame
* aRootFrame
,
424 : TTextAttr
<nscoord
>(!aFrame
) {
425 mDC
= aRootFrame
->PresContext()->DeviceContext();
427 mRootNativeValue
= aRootFrame
->StyleFont()->mSize
.ToAppUnits();
428 mIsRootDefined
= true;
431 mNativeValue
= aFrame
->StyleFont()->mSize
.ToAppUnits();
436 bool TextAttrsMgr::FontSizeTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
438 nsIContent
* el
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
440 nsIFrame
* frame
= el
->GetPrimaryFrame();
442 *aValue
= frame
->StyleFont()->mSize
.ToAppUnits();
449 void TextAttrsMgr::FontSizeTextAttr::ExposeValue(AccAttributes
* aAttributes
,
450 const nscoord
& aValue
) {
451 // Convert from nscoord to pt.
453 // Note: according to IA2, "The conversion doesn't have to be exact.
454 // The intent is to give the user a feel for the size of the text."
456 // ATK does not specify a unit and will likely follow IA2 here.
458 // XXX todo: consider sharing this code with layout module? (bug 474621)
459 float px
= NSAppUnitsToFloatPixels(aValue
, mozilla::AppUnitsPerCSSPixel());
460 // Each pt is 4/3 of a CSS pixel.
461 FontSize fontSize
{NS_lround(px
* 3 / 4)};
463 aAttributes
->SetAttribute(nsGkAtoms::font_size
, fontSize
);
466 ////////////////////////////////////////////////////////////////////////////////
468 ////////////////////////////////////////////////////////////////////////////////
470 TextAttrsMgr::FontStyleTextAttr::FontStyleTextAttr(nsIFrame
* aRootFrame
,
472 : TTextAttr
<FontSlantStyle
>(!aFrame
) {
473 mRootNativeValue
= aRootFrame
->StyleFont()->mFont
.style
;
474 mIsRootDefined
= true;
477 mNativeValue
= aFrame
->StyleFont()->mFont
.style
;
482 bool TextAttrsMgr::FontStyleTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
483 FontSlantStyle
* aValue
) {
484 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
486 nsIFrame
* frame
= elm
->GetPrimaryFrame();
488 *aValue
= frame
->StyleFont()->mFont
.style
;
495 void TextAttrsMgr::FontStyleTextAttr::ExposeValue(
496 AccAttributes
* aAttributes
, const FontSlantStyle
& aValue
) {
497 if (aValue
.IsNormal()) {
498 aAttributes
->SetAttribute(nsGkAtoms::font_style
, nsGkAtoms::normal
);
499 } else if (aValue
.IsItalic()) {
500 RefPtr
<nsAtom
> atom
= NS_Atomize("italic");
501 aAttributes
->SetAttribute(nsGkAtoms::font_style
, atom
);
506 CopyUTF8toUTF16(s
, wide
);
507 aAttributes
->SetAttribute(nsGkAtoms::font_style
, std::move(wide
));
511 ////////////////////////////////////////////////////////////////////////////////
512 // FontWeightTextAttr
513 ////////////////////////////////////////////////////////////////////////////////
515 TextAttrsMgr::FontWeightTextAttr::FontWeightTextAttr(nsIFrame
* aRootFrame
,
517 : TTextAttr
<FontWeight
>(!aFrame
) {
518 mRootNativeValue
= GetFontWeight(aRootFrame
);
519 mIsRootDefined
= true;
522 mNativeValue
= GetFontWeight(aFrame
);
527 bool TextAttrsMgr::FontWeightTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
528 FontWeight
* aValue
) {
529 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
531 nsIFrame
* frame
= elm
->GetPrimaryFrame();
533 *aValue
= GetFontWeight(frame
);
540 void TextAttrsMgr::FontWeightTextAttr::ExposeValue(AccAttributes
* aAttributes
,
541 const FontWeight
& aValue
) {
542 int value
= aValue
.ToIntRounded();
543 aAttributes
->SetAttribute(nsGkAtoms::fontWeight
, value
);
546 FontWeight
TextAttrsMgr::FontWeightTextAttr::GetFontWeight(nsIFrame
* aFrame
) {
547 // nsFont::width isn't suitable here because it's necessary to expose real
548 // value of font weight (used font might not have some font weight values).
549 RefPtr
<nsFontMetrics
> fm
=
550 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, 1.0f
);
552 gfxFontGroup
* fontGroup
= fm
->GetThebesFontGroup();
553 RefPtr
<gfxFont
> font
= fontGroup
->GetFirstValidFont();
555 // When there doesn't exist a bold font in the family and so the rendering of
556 // a non-bold font face is changed so that the user sees what looks like a
557 // bold font, i.e. synthetic bolding is used. (Simply returns false on any
558 // platforms that don't use the multi-strike synthetic bolding.)
559 if (font
->ApplySyntheticBold()) {
560 return FontWeight::BOLD
;
563 // On Windows, font->GetStyle()->weight will give the same weight as
564 // fontEntry->Weight(), the weight of the first font in the font group,
565 // which may not be the weight of the font face used to render the
566 // characters. On Mac, font->GetStyle()->weight will just give the same
567 // number as getComputedStyle(). fontEntry->Weight() will give the weight
568 // range supported by the font face used, so we clamp the weight that was
569 // requested by style to what is actually supported by the font.
570 gfxFontEntry
* fontEntry
= font
->GetFontEntry();
571 return fontEntry
->Weight().Clamp(font
->GetStyle()->weight
);
574 ////////////////////////////////////////////////////////////////////////////////
575 // AutoGeneratedTextAttr
576 ////////////////////////////////////////////////////////////////////////////////
577 TextAttrsMgr::AutoGeneratedTextAttr::AutoGeneratedTextAttr(
578 HyperTextAccessible
* aHyperTextAcc
, LocalAccessible
* aAccessible
)
579 : TTextAttr
<bool>(!aAccessible
) {
580 mRootNativeValue
= false;
581 mIsRootDefined
= false;
584 mIsDefined
= mNativeValue
=
585 ((aAccessible
->NativeRole() == roles::STATICTEXT
) ||
586 (aAccessible
->NativeRole() == roles::LISTITEM_MARKER
));
590 bool TextAttrsMgr::AutoGeneratedTextAttr::GetValueFor(
591 LocalAccessible
* aAccessible
, bool* aValue
) {
592 return *aValue
= (aAccessible
->NativeRole() == roles::STATICTEXT
);
595 void TextAttrsMgr::AutoGeneratedTextAttr::ExposeValue(
596 AccAttributes
* aAttributes
, const bool& aValue
) {
597 aAttributes
->SetAttribute(nsGkAtoms::auto_generated
, aValue
);
600 ////////////////////////////////////////////////////////////////////////////////
602 ////////////////////////////////////////////////////////////////////////////////
604 TextAttrsMgr::TextDecorValue::TextDecorValue(nsIFrame
* aFrame
) {
605 const nsStyleTextReset
* textReset
= aFrame
->StyleTextReset();
606 mStyle
= textReset
->mTextDecorationStyle
;
607 mColor
= textReset
->mTextDecorationColor
.CalcColor(aFrame
);
609 textReset
->mTextDecorationLine
& (StyleTextDecorationLine::UNDERLINE
|
610 StyleTextDecorationLine::LINE_THROUGH
);
613 TextAttrsMgr::TextDecorTextAttr::TextDecorTextAttr(nsIFrame
* aRootFrame
,
615 : TTextAttr
<TextDecorValue
>(!aFrame
) {
616 mRootNativeValue
= TextDecorValue(aRootFrame
);
617 mIsRootDefined
= mRootNativeValue
.IsDefined();
620 mNativeValue
= TextDecorValue(aFrame
);
621 mIsDefined
= mNativeValue
.IsDefined();
625 bool TextAttrsMgr::TextDecorTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
626 TextDecorValue
* aValue
) {
627 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
629 nsIFrame
* frame
= elm
->GetPrimaryFrame();
631 *aValue
= TextDecorValue(frame
);
632 return aValue
->IsDefined();
638 void TextAttrsMgr::TextDecorTextAttr::ExposeValue(
639 AccAttributes
* aAttributes
, const TextDecorValue
& aValue
) {
640 if (aValue
.IsUnderline()) {
641 RefPtr
<nsAtom
> underlineStyle
=
642 StyleInfo::TextDecorationStyleToAtom(aValue
.Style());
643 aAttributes
->SetAttribute(nsGkAtoms::textUnderlineStyle
, underlineStyle
);
645 aAttributes
->SetAttribute(nsGkAtoms::textUnderlineColor
,
646 Color
{aValue
.Color()});
650 if (aValue
.IsLineThrough()) {
651 RefPtr
<nsAtom
> lineThroughStyle
=
652 StyleInfo::TextDecorationStyleToAtom(aValue
.Style());
653 aAttributes
->SetAttribute(nsGkAtoms::textLineThroughStyle
,
656 aAttributes
->SetAttribute(nsGkAtoms::textLineThroughColor
,
657 Color
{aValue
.Color()});
661 ////////////////////////////////////////////////////////////////////////////////
663 ////////////////////////////////////////////////////////////////////////////////
665 TextAttrsMgr::TextPosTextAttr::TextPosTextAttr(nsIFrame
* aRootFrame
,
667 nsIContent
* aRootElm
,
669 : TTextAttr
<Maybe
<TextPosValue
>>(!aFrame
&& !aElm
), mRootElm(aRootElm
) {
670 // Get the text-position values for the roots and children.
671 // If we find an ARIA text-position value on a DOM element - searching up
672 // from the supplied root DOM element - use the associated frame as the root
673 // frame. This ensures that we're using the proper root frame for comparison.
674 nsIFrame
* ariaFrame
= nullptr;
675 Maybe
<TextPosValue
> rootAria
= GetAriaTextPosValue(aRootElm
, ariaFrame
);
676 if (rootAria
&& ariaFrame
) {
677 aRootFrame
= ariaFrame
;
679 Maybe
<TextPosValue
> rootLayout
= GetLayoutTextPosValue(aRootFrame
);
680 Maybe
<TextPosValue
> childLayout
;
681 Maybe
<TextPosValue
> childAria
;
683 childLayout
= GetLayoutTextPosValue(aFrame
);
686 childAria
= GetAriaTextPosValue(aElm
);
689 // Aria values take precedence over layout values.
690 mIsRootDefined
= rootAria
|| rootLayout
;
691 mRootNativeValue
= rootAria
? rootAria
: rootLayout
;
692 mIsDefined
= childAria
|| childLayout
;
693 mNativeValue
= childAria
? childAria
: childLayout
;
695 // If there's no child text-position information from ARIA, and the child
696 // layout info is equivalent to the root layout info (i.e., it's inherited),
697 // then we should prefer the root information.
698 if (!childAria
&& childLayout
== rootLayout
) {
703 bool TextAttrsMgr::TextPosTextAttr::GetValueFor(LocalAccessible
* aAccessible
,
704 Maybe
<TextPosValue
>* aValue
) {
705 nsIContent
* elm
= nsCoreUtils::GetDOMElementFor(aAccessible
->GetContent());
707 nsIFrame
* frame
= elm
->GetPrimaryFrame();
709 Maybe
<TextPosValue
> layoutValue
= GetLayoutTextPosValue(frame
);
710 Maybe
<TextPosValue
> ariaValue
= GetAriaTextPosValue(elm
);
712 *aValue
= ariaValue
? ariaValue
: layoutValue
;
713 return aValue
->isSome();
719 void TextAttrsMgr::TextPosTextAttr::ExposeValue(
720 AccAttributes
* aAttributes
, const Maybe
<TextPosValue
>& aValue
) {
721 if (aValue
.isNothing()) {
725 RefPtr
<nsAtom
> atom
= nullptr;
727 case eTextPosBaseline
:
728 atom
= nsGkAtoms::baseline
;
732 atom
= nsGkAtoms::sub
;
736 atom
= NS_Atomize("super");
741 aAttributes
->SetAttribute(nsGkAtoms::textPosition
, atom
);
745 Maybe
<TextAttrsMgr::TextPosValue
>
746 TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent
* aElm
) const {
747 nsIFrame
* ariaFrame
= nullptr;
748 return GetAriaTextPosValue(aElm
, ariaFrame
);
751 Maybe
<TextAttrsMgr::TextPosValue
>
752 TextAttrsMgr::TextPosTextAttr::GetAriaTextPosValue(nsIContent
* aElm
,
753 nsIFrame
*& ariaFrame
) const {
754 // Search for the superscript and subscript roles that imply text-position.
755 const nsIContent
* elm
= aElm
;
757 if (elm
->IsElement()) {
758 const mozilla::dom::Element
* domElm
= elm
->AsElement();
759 static const dom::Element::AttrValuesArray tokens
[] = {
760 nsGkAtoms::subscript
, nsGkAtoms::superscript
, nullptr};
761 const int32_t valueIdx
= domElm
->FindAttrValueIn(
762 kNameSpaceID_None
, nsGkAtoms::role
, tokens
, eCaseMatters
);
763 ariaFrame
= domElm
->GetPrimaryFrame();
765 return Some(eTextPosSub
);
768 return Some(eTextPosSuper
);
771 } while ((elm
= elm
->GetParent()) && elm
!= mRootElm
);
777 Maybe
<TextAttrsMgr::TextPosValue
>
778 TextAttrsMgr::TextPosTextAttr::GetLayoutTextPosValue(nsIFrame
* aFrame
) const {
779 const auto& verticalAlign
= aFrame
->StyleDisplay()->mVerticalAlign
;
780 if (verticalAlign
.IsKeyword()) {
781 switch (verticalAlign
.AsKeyword()) {
782 case StyleVerticalAlignKeyword::Baseline
:
783 return Some(eTextPosBaseline
);
784 case StyleVerticalAlignKeyword::Sub
:
785 return Some(eTextPosSub
);
786 case StyleVerticalAlignKeyword::Super
:
787 return Some(eTextPosSuper
);
788 // No good guess for the rest, so do not expose value of text-position
795 const auto& length
= verticalAlign
.AsLength();
796 if (length
.ConvertsToPercentage()) {
797 const float percentValue
= length
.ToPercentage();
798 return percentValue
> 0 ? Some(eTextPosSuper
)
799 : (percentValue
< 0 ? Some(eTextPosSub
)
800 : Some(eTextPosBaseline
));
803 if (length
.ConvertsToLength()) {
804 const nscoord coordValue
= length
.ToLength();
805 return coordValue
> 0
806 ? Some(eTextPosSuper
)
807 : (coordValue
< 0 ? Some(eTextPosSub
) : Some(eTextPosBaseline
));
810 if (const nsIContent
* content
= aFrame
->GetContent()) {
811 if (content
->IsHTMLElement(nsGkAtoms::sup
)) return Some(eTextPosSuper
);
812 if (content
->IsHTMLElement(nsGkAtoms::sub
)) return Some(eTextPosSub
);