Bug 1769547 - Do not MOZ_CRASH() on missing process r=nika
[gecko.git] / accessible / base / TextAttrs.cpp
blobc4bb300b5bc8c8d872b56c90c4b7838cb4fe8d1d
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/. */
6 #include "TextAttrs.h"
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 ////////////////////////////////////////////////////////////////////////////////
27 // TextAttrsMgr
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.
39 MOZ_ASSERT(
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()) {
47 if (!aStartOffset) {
48 return;
50 for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
51 LocalAccessible* currAcc = mHyperTextAcc->LocalChildAt(childIdx);
52 if (currAcc->IsText()) break;
54 (*aStartOffset)--;
57 uint32_t childCount = mHyperTextAcc->ChildCount();
58 for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childCount;
59 childIdx++) {
60 LocalAccessible* currAcc = mHyperTextAcc->LocalChildAt(childIdx);
61 if (currAcc->IsText()) break;
63 (*aEndOffset)++;
66 return;
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();
72 if (!hyperTextElm) {
73 return; // XXX: we don't support text attrs on document with no body
76 nsIFrame* rootFrame = mHyperTextAcc->GetFrame();
77 if (!rootFrame) {
78 return;
81 nsIContent *offsetNode = nullptr, *offsetElm = nullptr;
82 nsIFrame* frame = nullptr;
83 if (mOffsetAcc) {
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);
125 TextAttr* attrArray[] = {
126 &langTextAttr, &invalidTextAttr, &bgColorTextAttr,
127 &colorTextAttr, &fontFamilyTextAttr, &fontSizeTextAttr,
128 &fontStyleTextAttr, &fontWeightTextAttr, &autoGenTextAttr,
129 &textDecorTextAttr, &textPosTextAttr};
131 // Expose text attributes if applicable.
132 if (aAttributes) {
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.
139 if (aStartOffset) {
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
151 // own range.
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)) {
161 offsetFound = true;
162 break;
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
185 // the search.
186 if (!textAttr->Equal(currAcc)) {
187 offsetFound = true;
188 break;
192 if (offsetFound) break;
194 (*aEndOffset) += nsAccUtils::TextLength(currAcc);
198 ////////////////////////////////////////////////////////////////////////////////
199 // LangTextAttr
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();
208 if (aElm) {
209 nsCoreUtils::GetLanguageFor(aElm, mRootContent, mNativeValue);
210 mIsDefined = !mNativeValue.IsEmpty();
214 TextAttrsMgr::LangTextAttr::~LangTextAttr() {}
216 bool TextAttrsMgr::LangTextAttr::GetValueFor(LocalAccessible* aAccessible,
217 nsString* aValue) {
218 nsCoreUtils::GetLanguageFor(aAccessible->GetContent(), mRootContent, *aValue);
219 return !aValue->IsEmpty();
222 void TextAttrsMgr::LangTextAttr::ExposeValue(AccAttributes* aAttributes,
223 const nsString& aValue) {
224 aAttributes->SetAttributeStringCopy(nsGkAtoms::language, aValue);
227 ////////////////////////////////////////////////////////////////////////////////
228 // InvalidTextAttr
229 ////////////////////////////////////////////////////////////////////////////////
231 TextAttrsMgr::InvalidTextAttr::InvalidTextAttr(nsIContent* aRootElm,
232 nsIContent* aElm)
233 : TTextAttr<uint32_t>(!aElm), mRootElm(aRootElm) {
234 mIsRootDefined = GetValue(mRootElm, &mRootNativeValue);
235 if (aElm) mIsDefined = GetValue(aElm, &mNativeValue);
238 bool TextAttrsMgr::InvalidTextAttr::GetValueFor(LocalAccessible* aAccessible,
239 uint32_t* aValue) {
240 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
241 return elm ? GetValue(elm, aValue) : false;
244 void TextAttrsMgr::InvalidTextAttr::ExposeValue(AccAttributes* aAttributes,
245 const uint32_t& aValue) {
246 switch (aValue) {
247 case eFalse:
248 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::_false);
249 break;
251 case eGrammar:
252 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::grammar);
253 break;
255 case eSpelling:
256 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::spelling);
257 break;
259 case eTrue:
260 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::_true);
261 break;
265 bool TextAttrsMgr::InvalidTextAttr::GetValue(nsIContent* aElm,
266 uint32_t* aValue) {
267 nsIContent* elm = aElm;
268 do {
269 if (nsAccUtils::HasDefinedARIAToken(elm, nsGkAtoms::aria_invalid)) {
270 static dom::Element::AttrValuesArray tokens[] = {
271 nsGkAtoms::_false, nsGkAtoms::grammar, nsGkAtoms::spelling, nullptr};
273 int32_t idx = elm->AsElement()->FindAttrValueIn(
274 kNameSpaceID_None, nsGkAtoms::aria_invalid, tokens, eCaseMatters);
275 switch (idx) {
276 case 0:
277 *aValue = eFalse;
278 return true;
279 case 1:
280 *aValue = eGrammar;
281 return true;
282 case 2:
283 *aValue = eSpelling;
284 return true;
285 default:
286 *aValue = eTrue;
287 return true;
290 } while ((elm = elm->GetParent()) && elm != mRootElm);
292 return false;
295 ////////////////////////////////////////////////////////////////////////////////
296 // BGColorTextAttr
297 ////////////////////////////////////////////////////////////////////////////////
299 TextAttrsMgr::BGColorTextAttr::BGColorTextAttr(nsIFrame* aRootFrame,
300 nsIFrame* aFrame)
301 : TTextAttr<nscolor>(!aFrame), mRootFrame(aRootFrame) {
302 mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
303 if (aFrame) mIsDefined = GetColor(aFrame, &mNativeValue);
306 bool TextAttrsMgr::BGColorTextAttr::GetValueFor(LocalAccessible* aAccessible,
307 nscolor* aValue) {
308 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
309 if (elm) {
310 nsIFrame* frame = elm->GetPrimaryFrame();
311 if (frame) {
312 return GetColor(frame, aValue);
315 return false;
318 void TextAttrsMgr::BGColorTextAttr::ExposeValue(AccAttributes* aAttributes,
319 const nscolor& aValue) {
320 aAttributes->SetAttribute(nsGkAtoms::backgroundColor, Color{aValue});
323 bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame* aFrame,
324 nscolor* aColor) {
325 nscolor backgroundColor = aFrame->StyleBackground()->BackgroundColor(aFrame);
326 if (NS_GET_A(backgroundColor) > 0) {
327 *aColor = backgroundColor;
328 return true;
331 nsContainerFrame* parentFrame = aFrame->GetParent();
332 if (!parentFrame) {
333 *aColor = aFrame->PresContext()->DefaultBackgroundColor();
334 return true;
337 // Each frame of parents chain for the initially passed 'aFrame' has
338 // transparent background color. So background color isn't changed from
339 // 'mRootFrame' to initially passed 'aFrame'.
340 if (parentFrame == mRootFrame) return false;
342 return GetColor(parentFrame, aColor);
345 ////////////////////////////////////////////////////////////////////////////////
346 // ColorTextAttr
347 ////////////////////////////////////////////////////////////////////////////////
349 TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame,
350 nsIFrame* aFrame)
351 : TTextAttr<nscolor>(!aFrame) {
352 mRootNativeValue = aRootFrame->StyleText()->mColor.ToColor();
353 mIsRootDefined = true;
355 if (aFrame) {
356 mNativeValue = aFrame->StyleText()->mColor.ToColor();
357 mIsDefined = true;
361 bool TextAttrsMgr::ColorTextAttr::GetValueFor(LocalAccessible* aAccessible,
362 nscolor* aValue) {
363 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
364 if (elm) {
365 if (nsIFrame* frame = elm->GetPrimaryFrame()) {
366 *aValue = frame->StyleText()->mColor.ToColor();
367 return true;
370 return false;
373 void TextAttrsMgr::ColorTextAttr::ExposeValue(AccAttributes* aAttributes,
374 const nscolor& aValue) {
375 aAttributes->SetAttribute(nsGkAtoms::color, Color{aValue});
378 ////////////////////////////////////////////////////////////////////////////////
379 // FontFamilyTextAttr
380 ////////////////////////////////////////////////////////////////////////////////
382 TextAttrsMgr::FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame* aRootFrame,
383 nsIFrame* aFrame)
384 : TTextAttr<nsString>(!aFrame) {
385 mIsRootDefined = GetFontFamily(aRootFrame, mRootNativeValue);
387 if (aFrame) mIsDefined = GetFontFamily(aFrame, mNativeValue);
390 bool TextAttrsMgr::FontFamilyTextAttr::GetValueFor(LocalAccessible* aAccessible,
391 nsString* aValue) {
392 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
393 if (elm) {
394 nsIFrame* frame = elm->GetPrimaryFrame();
395 if (frame) {
396 return GetFontFamily(frame, *aValue);
399 return false;
402 void TextAttrsMgr::FontFamilyTextAttr::ExposeValue(AccAttributes* aAttributes,
403 const nsString& aValue) {
404 aAttributes->SetAttributeStringCopy(nsGkAtoms::font_family, aValue);
407 bool TextAttrsMgr::FontFamilyTextAttr::GetFontFamily(nsIFrame* aFrame,
408 nsString& aFamily) {
409 RefPtr<nsFontMetrics> fm =
410 nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
412 gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
413 gfxFont* font = fontGroup->GetFirstValidFont();
414 gfxFontEntry* fontEntry = font->GetFontEntry();
415 aFamily.Append(NS_ConvertUTF8toUTF16(fontEntry->FamilyName()));
416 return true;
419 ////////////////////////////////////////////////////////////////////////////////
420 // FontSizeTextAttr
421 ////////////////////////////////////////////////////////////////////////////////
423 TextAttrsMgr::FontSizeTextAttr::FontSizeTextAttr(nsIFrame* aRootFrame,
424 nsIFrame* aFrame)
425 : TTextAttr<nscoord>(!aFrame) {
426 mDC = aRootFrame->PresContext()->DeviceContext();
428 mRootNativeValue = aRootFrame->StyleFont()->mSize.ToAppUnits();
429 mIsRootDefined = true;
431 if (aFrame) {
432 mNativeValue = aFrame->StyleFont()->mSize.ToAppUnits();
433 mIsDefined = true;
437 bool TextAttrsMgr::FontSizeTextAttr::GetValueFor(LocalAccessible* aAccessible,
438 nscoord* aValue) {
439 nsIContent* el = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
440 if (el) {
441 nsIFrame* frame = el->GetPrimaryFrame();
442 if (frame) {
443 *aValue = frame->StyleFont()->mSize.ToAppUnits();
444 return true;
447 return false;
450 void TextAttrsMgr::FontSizeTextAttr::ExposeValue(AccAttributes* aAttributes,
451 const nscoord& aValue) {
452 // Convert from nscoord to pt.
454 // Note: according to IA2, "The conversion doesn't have to be exact.
455 // The intent is to give the user a feel for the size of the text."
457 // ATK does not specify a unit and will likely follow IA2 here.
459 // XXX todo: consider sharing this code with layout module? (bug 474621)
460 float px = NSAppUnitsToFloatPixels(aValue, mozilla::AppUnitsPerCSSPixel());
461 // Each pt is 4/3 of a CSS pixel.
462 FontSize fontSize{NS_lround(px * 3 / 4)};
464 aAttributes->SetAttribute(nsGkAtoms::font_size, fontSize);
467 ////////////////////////////////////////////////////////////////////////////////
468 // FontStyleTextAttr
469 ////////////////////////////////////////////////////////////////////////////////
471 TextAttrsMgr::FontStyleTextAttr::FontStyleTextAttr(nsIFrame* aRootFrame,
472 nsIFrame* aFrame)
473 : TTextAttr<FontSlantStyle>(!aFrame) {
474 mRootNativeValue = aRootFrame->StyleFont()->mFont.style;
475 mIsRootDefined = true;
477 if (aFrame) {
478 mNativeValue = aFrame->StyleFont()->mFont.style;
479 mIsDefined = true;
483 bool TextAttrsMgr::FontStyleTextAttr::GetValueFor(LocalAccessible* aAccessible,
484 FontSlantStyle* aValue) {
485 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
486 if (elm) {
487 nsIFrame* frame = elm->GetPrimaryFrame();
488 if (frame) {
489 *aValue = frame->StyleFont()->mFont.style;
490 return true;
493 return false;
496 void TextAttrsMgr::FontStyleTextAttr::ExposeValue(
497 AccAttributes* aAttributes, const FontSlantStyle& aValue) {
498 if (aValue.IsNormal()) {
499 aAttributes->SetAttribute(nsGkAtoms::font_style, nsGkAtoms::normal);
500 } else if (aValue.IsItalic()) {
501 RefPtr<nsAtom> atom = NS_Atomize("italic");
502 aAttributes->SetAttribute(nsGkAtoms::font_style, atom);
503 } else {
504 auto angle = aValue.ObliqueAngle();
505 nsString string(u"oblique"_ns);
506 if (angle != FontSlantStyle::kDefaultAngle) {
507 string.AppendLiteral(" ");
508 nsStyleUtil::AppendCSSNumber(angle, string);
509 string.AppendLiteral("deg");
511 aAttributes->SetAttribute(nsGkAtoms::font_style, std::move(string));
515 ////////////////////////////////////////////////////////////////////////////////
516 // FontWeightTextAttr
517 ////////////////////////////////////////////////////////////////////////////////
519 TextAttrsMgr::FontWeightTextAttr::FontWeightTextAttr(nsIFrame* aRootFrame,
520 nsIFrame* aFrame)
521 : TTextAttr<FontWeight>(!aFrame) {
522 mRootNativeValue = GetFontWeight(aRootFrame);
523 mIsRootDefined = true;
525 if (aFrame) {
526 mNativeValue = GetFontWeight(aFrame);
527 mIsDefined = true;
531 bool TextAttrsMgr::FontWeightTextAttr::GetValueFor(LocalAccessible* aAccessible,
532 FontWeight* aValue) {
533 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
534 if (elm) {
535 nsIFrame* frame = elm->GetPrimaryFrame();
536 if (frame) {
537 *aValue = GetFontWeight(frame);
538 return true;
541 return false;
544 void TextAttrsMgr::FontWeightTextAttr::ExposeValue(AccAttributes* aAttributes,
545 const FontWeight& aValue) {
546 aAttributes->SetAttribute(nsGkAtoms::fontWeight, aValue.ToIntRounded());
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 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;
586 if (aAccessible) {
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 ////////////////////////////////////////////////////////////////////////////////
604 // TextDecorTextAttr
605 ////////////////////////////////////////////////////////////////////////////////
607 TextAttrsMgr::TextDecorValue::TextDecorValue(nsIFrame* aFrame) {
608 const nsStyleTextReset* textReset = aFrame->StyleTextReset();
609 mStyle = textReset->mTextDecorationStyle;
610 mColor = textReset->mTextDecorationColor.CalcColor(aFrame);
611 mLine =
612 textReset->mTextDecorationLine & (StyleTextDecorationLine::UNDERLINE |
613 StyleTextDecorationLine::LINE_THROUGH);
616 TextAttrsMgr::TextDecorTextAttr::TextDecorTextAttr(nsIFrame* aRootFrame,
617 nsIFrame* aFrame)
618 : TTextAttr<TextDecorValue>(!aFrame) {
619 mRootNativeValue = TextDecorValue(aRootFrame);
620 mIsRootDefined = mRootNativeValue.IsDefined();
622 if (aFrame) {
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());
631 if (elm) {
632 nsIFrame* frame = elm->GetPrimaryFrame();
633 if (frame) {
634 *aValue = TextDecorValue(frame);
635 return aValue->IsDefined();
638 return false;
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()});
650 return;
653 if (aValue.IsLineThrough()) {
654 RefPtr<nsAtom> lineThroughStyle =
655 StyleInfo::TextDecorationStyleToAtom(aValue.Style());
656 aAttributes->SetAttribute(nsGkAtoms::textLineThroughStyle,
657 lineThroughStyle);
659 aAttributes->SetAttribute(nsGkAtoms::textLineThroughColor,
660 Color{aValue.Color()});
664 ////////////////////////////////////////////////////////////////////////////////
665 // TextPosTextAttr
666 ////////////////////////////////////////////////////////////////////////////////
668 TextAttrsMgr::TextPosTextAttr::TextPosTextAttr(nsIFrame* aRootFrame,
669 nsIFrame* aFrame)
670 : TTextAttr<TextPosValue>(!aFrame) {
671 mRootNativeValue = GetTextPosValue(aRootFrame);
672 mIsRootDefined = mRootNativeValue != eTextPosNone;
674 if (aFrame) {
675 mNativeValue = GetTextPosValue(aFrame);
676 mIsDefined = mNativeValue != eTextPosNone;
680 bool TextAttrsMgr::TextPosTextAttr::GetValueFor(LocalAccessible* aAccessible,
681 TextPosValue* aValue) {
682 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
683 if (elm) {
684 nsIFrame* frame = elm->GetPrimaryFrame();
685 if (frame) {
686 *aValue = GetTextPosValue(frame);
687 return *aValue != eTextPosNone;
690 return false;
693 void TextAttrsMgr::TextPosTextAttr::ExposeValue(AccAttributes* aAttributes,
694 const TextPosValue& aValue) {
695 RefPtr<nsAtom> atom = nullptr;
696 switch (aValue) {
697 case eTextPosBaseline:
698 atom = nsGkAtoms::baseline;
699 break;
701 case eTextPosSub:
702 atom = nsGkAtoms::sub;
703 break;
705 case eTextPosSuper:
706 atom = NS_Atomize("super");
707 break;
709 case eTextPosNone:
710 break;
713 if (atom) {
714 aAttributes->SetAttribute(nsGkAtoms::textPosition, atom);
718 TextAttrsMgr::TextPosValue TextAttrsMgr::TextPosTextAttr::GetTextPosValue(
719 nsIFrame* aFrame) const {
720 const auto& verticalAlign = aFrame->StyleDisplay()->mVerticalAlign;
721 if (verticalAlign.IsKeyword()) {
722 switch (verticalAlign.AsKeyword()) {
723 case StyleVerticalAlignKeyword::Baseline:
724 return eTextPosBaseline;
725 case StyleVerticalAlignKeyword::Sub:
726 return eTextPosSub;
727 case StyleVerticalAlignKeyword::Super:
728 return eTextPosSuper;
729 // No good guess for the rest, so do not expose value of text-position
730 // attribute.
731 default:
732 return eTextPosNone;
736 const auto& length = verticalAlign.AsLength();
737 if (length.ConvertsToPercentage()) {
738 float percentValue = length.ToPercentage();
739 return percentValue > 0
740 ? eTextPosSuper
741 : (percentValue < 0 ? eTextPosSub : eTextPosBaseline);
744 if (length.ConvertsToLength()) {
745 nscoord coordValue = length.ToLength();
746 return coordValue > 0 ? eTextPosSuper
747 : (coordValue < 0 ? eTextPosSub : eTextPosBaseline);
750 if (const nsIContent* content = aFrame->GetContent()) {
751 if (content->IsHTMLElement(nsGkAtoms::sup)) return eTextPosSuper;
752 if (content->IsHTMLElement(nsGkAtoms::sub)) return eTextPosSub;
755 return eTextPosNone;