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/. */
5
6 #include "TextAttrs.h"
7
8 #include "LocalAccessible-inl.h"
9 #include "AccAttributes.h"
10 #include "nsAccUtils.h"
11 #include "nsCoreUtils.h"
12 #include "StyleInfo.h"
13
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"
22
23 using namespace mozilla;
24 using namespace mozilla::a11y;
25
26 ////////////////////////////////////////////////////////////////////////////////
27 // TextAttrsMgr
28 ////////////////////////////////////////////////////////////////////////////////
29
GetAttributes(AccAttributes * aAttributes,uint32_t * aStartOffset,uint32_t * aEndOffset)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 and result hyper text offsets must be specified in
34 // the case of text attributes.
35 // 3. Offset accessible and result hyper text offsets must not be specified
36 // but include default text attributes flag and attributes list must be
37 // specified in the case of default text attributes.
38 MOZ_ASSERT(
39 mHyperTextAcc &&
40 ((mOffsetAcc && mOffsetAccIdx != -1 && aStartOffset && aEndOffset) ||
41 (!mOffsetAcc && mOffsetAccIdx == -1 && !aStartOffset &&
42 !aEndOffset && mIncludeDefAttrs && aAttributes)),
43 "Wrong usage of TextAttrsMgr!");
44
45 // Embedded objects are combined into own range with empty attributes set.
46 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;
50
51 (*aStartOffset)--;
52 }
53
54 uint32_t childCount = mHyperTextAcc->ChildCount();
55 for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childCount;
56 childIdx++) {
57 LocalAccessible* currAcc = mHyperTextAcc->LocalChildAt(childIdx);
58 if (currAcc->IsText()) break;
59
60 (*aEndOffset)++;
61 }
62
63 return;
64 }
65
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();
69 if (!hyperTextElm) {
70 return; // XXX: we don't support text attrs on document with no body
71 }
72
73 nsIFrame* rootFrame = mHyperTextAcc->GetFrame();
74 MOZ_ASSERT(rootFrame, "No frame for accessible!");
75 if (!rootFrame) return;
76
77 nsIContent *offsetNode = nullptr, *offsetElm = nullptr;
78 nsIFrame* frame = nullptr;
79 if (mOffsetAcc) {
80 offsetNode = mOffsetAcc->GetContent();
81 offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
82 MOZ_ASSERT(offsetElm, "No element for offset accessible!");
83 if (!offsetElm) return;
84
85 frame = offsetElm->GetPrimaryFrame();
86 }
87
88 // "language" text attribute
89 LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
90
91 // "aria-invalid" text attribute
92 InvalidTextAttr invalidTextAttr(hyperTextElm, offsetNode);
93
94 // "background-color" text attribute
95 BGColorTextAttr bgColorTextAttr(rootFrame, frame);
96
97 // "color" text attribute
98 ColorTextAttr colorTextAttr(rootFrame, frame);
99
100 // "font-family" text attribute
101 FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame);
102
103 // "font-size" text attribute
104 FontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
105
106 // "font-style" text attribute
107 FontStyleTextAttr fontStyleTextAttr(rootFrame, frame);
108
109 // "font-weight" text attribute
110 FontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
111
112 // "auto-generated" text attribute
113 AutoGeneratedTextAttr autoGenTextAttr(mHyperTextAcc, mOffsetAcc);
114
115 // "text-underline(line-through)-style(color)" text attributes
116 TextDecorTextAttr textDecorTextAttr(rootFrame, frame);
117
118 // "text-position" text attribute
119 TextPosTextAttr textPosTextAttr(rootFrame, frame);
120
121 TextAttr* attrArray[] = {
122 &langTextAttr, &invalidTextAttr, &bgColorTextAttr,
123 &colorTextAttr, &fontFamilyTextAttr, &fontSizeTextAttr,
124 &fontStyleTextAttr, &fontWeightTextAttr, &autoGenTextAttr,
125 &textDecorTextAttr, &textPosTextAttr};
126
127 // Expose text attributes if applicable.
128 if (aAttributes) {
129 for (uint32_t idx = 0; idx < ArrayLength(attrArray); idx++) {
130 attrArray[idx]->Expose(aAttributes, mIncludeDefAttrs);
131 }
132 }
133
134 // Expose text attributes range where they are applied if applicable.
135 if (mOffsetAcc) {
136 GetRange(attrArray, ArrayLength(attrArray), aStartOffset, aEndOffset);
137 }
138 }
139
GetRange(TextAttr * aAttrArray[],uint32_t aAttrArrayLen,uint32_t * aStartOffset,uint32_t * aEndOffset)140 void TextAttrsMgr::GetRange(TextAttr* aAttrArray[], uint32_t aAttrArrayLen,
141 uint32_t* aStartOffset, uint32_t* aEndOffset) {
142 // Navigate backward from anchor accessible to find start offset.
143 for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
144 LocalAccessible* currAcc = mHyperTextAcc->LocalChildAt(childIdx);
145
146 // Stop on embedded accessible since embedded accessibles are combined into
147 // own range.
148 if (!currAcc->IsText()) break;
149
150 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
151 "Text accessible has to have an associated DOM element");
152
153 bool offsetFound = false;
154 for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
155 TextAttr* textAttr = aAttrArray[attrIdx];
156 if (!textAttr->Equal(currAcc)) {
157 offsetFound = true;
158 break;
159 }
160 }
161
162 if (offsetFound) break;
163
164 *(aStartOffset) -= nsAccUtils::TextLength(currAcc);
165 }
166
167 // Navigate forward from anchor accessible to find end offset.
168 uint32_t childLen = mHyperTextAcc->ChildCount();
169 for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childLen; childIdx++) {
170 LocalAccessible* currAcc = mHyperTextAcc->LocalChildAt(childIdx);
171 if (!currAcc->IsText()) break;
172
173 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
174 "Text accessible has to have an associated DOM element");
175
176 bool offsetFound = false;
177 for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
178 TextAttr* textAttr = aAttrArray[attrIdx];
179
180 // Alter the end offset when text attribute changes its value and stop
181 // the search.
182 if (!textAttr->Equal(currAcc)) {
183 offsetFound = true;
184 break;
185 }
186 }
187
188 if (offsetFound) break;
189
190 (*aEndOffset) += nsAccUtils::TextLength(currAcc);
191 }
192 }
193
194 ////////////////////////////////////////////////////////////////////////////////
195 // LangTextAttr
196 ////////////////////////////////////////////////////////////////////////////////
197
LangTextAttr(HyperTextAccessible * aRoot,nsIContent * aRootElm,nsIContent * aElm)198 TextAttrsMgr::LangTextAttr::LangTextAttr(HyperTextAccessible* aRoot,
199 nsIContent* aRootElm, nsIContent* aElm)
200 : TTextAttr<nsString>(!aElm), mRootContent(aRootElm) {
201 aRoot->Language(mRootNativeValue);
202 mIsRootDefined = !mRootNativeValue.IsEmpty();
203
204 if (aElm) {
205 nsCoreUtils::GetLanguageFor(aElm, mRootContent, mNativeValue);
206 mIsDefined = !mNativeValue.IsEmpty();
207 }
208 }
209
~LangTextAttr()210 TextAttrsMgr::LangTextAttr::~LangTextAttr() {}
211
GetValueFor(LocalAccessible * aAccessible,nsString * aValue)212 bool TextAttrsMgr::LangTextAttr::GetValueFor(LocalAccessible* aAccessible,
213 nsString* aValue) {
214 nsCoreUtils::GetLanguageFor(aAccessible->GetContent(), mRootContent, *aValue);
215 return !aValue->IsEmpty();
216 }
217
ExposeValue(AccAttributes * aAttributes,const nsString & aValue)218 void TextAttrsMgr::LangTextAttr::ExposeValue(AccAttributes* aAttributes,
219 const nsString& aValue) {
220 aAttributes->SetAttribute(nsGkAtoms::language, aValue);
221 }
222
223 ////////////////////////////////////////////////////////////////////////////////
224 // InvalidTextAttr
225 ////////////////////////////////////////////////////////////////////////////////
226
InvalidTextAttr(nsIContent * aRootElm,nsIContent * aElm)227 TextAttrsMgr::InvalidTextAttr::InvalidTextAttr(nsIContent* aRootElm,
228 nsIContent* aElm)
229 : TTextAttr<uint32_t>(!aElm), mRootElm(aRootElm) {
230 mIsRootDefined = GetValue(mRootElm, &mRootNativeValue);
231 if (aElm) mIsDefined = GetValue(aElm, &mNativeValue);
232 }
233
GetValueFor(LocalAccessible * aAccessible,uint32_t * aValue)234 bool TextAttrsMgr::InvalidTextAttr::GetValueFor(LocalAccessible* aAccessible,
235 uint32_t* aValue) {
236 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
237 return elm ? GetValue(elm, aValue) : false;
238 }
239
ExposeValue(AccAttributes * aAttributes,const uint32_t & aValue)240 void TextAttrsMgr::InvalidTextAttr::ExposeValue(AccAttributes* aAttributes,
241 const uint32_t& aValue) {
242 switch (aValue) {
243 case eFalse:
244 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::_false);
245 break;
246
247 case eGrammar:
248 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::grammar);
249 break;
250
251 case eSpelling:
252 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::spelling);
253 break;
254
255 case eTrue:
256 aAttributes->SetAttribute(nsGkAtoms::invalid, nsGkAtoms::_true);
257 break;
258 }
259 }
260
GetValue(nsIContent * aElm,uint32_t * aValue)261 bool TextAttrsMgr::InvalidTextAttr::GetValue(nsIContent* aElm,
262 uint32_t* aValue) {
263 nsIContent* elm = aElm;
264 do {
265 if (nsAccUtils::HasDefinedARIAToken(elm, nsGkAtoms::aria_invalid)) {
266 static dom::Element::AttrValuesArray tokens[] = {
267 nsGkAtoms::_false, nsGkAtoms::grammar, nsGkAtoms::spelling, nullptr};
268
269 int32_t idx = elm->AsElement()->FindAttrValueIn(
270 kNameSpaceID_None, nsGkAtoms::aria_invalid, tokens, eCaseMatters);
271 switch (idx) {
272 case 0:
273 *aValue = eFalse;
274 return true;
275 case 1:
276 *aValue = eGrammar;
277 return true;
278 case 2:
279 *aValue = eSpelling;
280 return true;
281 default:
282 *aValue = eTrue;
283 return true;
284 }
285 }
286 } while ((elm = elm->GetParent()) && elm != mRootElm);
287
288 return false;
289 }
290
291 ////////////////////////////////////////////////////////////////////////////////
292 // BGColorTextAttr
293 ////////////////////////////////////////////////////////////////////////////////
294
BGColorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)295 TextAttrsMgr::BGColorTextAttr::BGColorTextAttr(nsIFrame* aRootFrame,
296 nsIFrame* aFrame)
297 : TTextAttr<nscolor>(!aFrame), mRootFrame(aRootFrame) {
298 mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
299 if (aFrame) mIsDefined = GetColor(aFrame, &mNativeValue);
300 }
301
GetValueFor(LocalAccessible * aAccessible,nscolor * aValue)302 bool TextAttrsMgr::BGColorTextAttr::GetValueFor(LocalAccessible* aAccessible,
303 nscolor* aValue) {
304 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
305 if (elm) {
306 nsIFrame* frame = elm->GetPrimaryFrame();
307 if (frame) {
308 return GetColor(frame, aValue);
309 }
310 }
311 return false;
312 }
313
ExposeValue(AccAttributes * aAttributes,const nscolor & aValue)314 void TextAttrsMgr::BGColorTextAttr::ExposeValue(AccAttributes* aAttributes,
315 const nscolor& aValue) {
316 aAttributes->SetAttribute(nsGkAtoms::backgroundColor, Color{aValue});
317 }
318
GetColor(nsIFrame * aFrame,nscolor * aColor)319 bool TextAttrsMgr::BGColorTextAttr::GetColor(nsIFrame* aFrame,
320 nscolor* aColor) {
321 nscolor backgroundColor = aFrame->StyleBackground()->BackgroundColor(aFrame);
322 if (NS_GET_A(backgroundColor) > 0) {
323 *aColor = backgroundColor;
324 return true;
325 }
326
327 nsContainerFrame* parentFrame = aFrame->GetParent();
328 if (!parentFrame) {
329 *aColor = aFrame->PresContext()->DefaultBackgroundColor();
330 return true;
331 }
332
333 // Each frame of parents chain for the initially passed 'aFrame' has
334 // transparent background color. So background color isn't changed from
335 // 'mRootFrame' to initially passed 'aFrame'.
336 if (parentFrame == mRootFrame) return false;
337
338 return GetColor(parentFrame, aColor);
339 }
340
341 ////////////////////////////////////////////////////////////////////////////////
342 // ColorTextAttr
343 ////////////////////////////////////////////////////////////////////////////////
344
ColorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)345 TextAttrsMgr::ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame,
346 nsIFrame* aFrame)
347 : TTextAttr<nscolor>(!aFrame) {
348 mRootNativeValue = aRootFrame->StyleText()->mColor.ToColor();
349 mIsRootDefined = true;
350
351 if (aFrame) {
352 mNativeValue = aFrame->StyleText()->mColor.ToColor();
353 mIsDefined = true;
354 }
355 }
356
GetValueFor(LocalAccessible * aAccessible,nscolor * aValue)357 bool TextAttrsMgr::ColorTextAttr::GetValueFor(LocalAccessible* aAccessible,
358 nscolor* aValue) {
359 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
360 if (elm) {
361 if (nsIFrame* frame = elm->GetPrimaryFrame()) {
362 *aValue = frame->StyleText()->mColor.ToColor();
363 return true;
364 }
365 }
366 return false;
367 }
368
ExposeValue(AccAttributes * aAttributes,const nscolor & aValue)369 void TextAttrsMgr::ColorTextAttr::ExposeValue(AccAttributes* aAttributes,
370 const nscolor& aValue) {
371 aAttributes->SetAttribute(nsGkAtoms::color, Color{aValue});
372 }
373
374 ////////////////////////////////////////////////////////////////////////////////
375 // FontFamilyTextAttr
376 ////////////////////////////////////////////////////////////////////////////////
377
FontFamilyTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)378 TextAttrsMgr::FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame* aRootFrame,
379 nsIFrame* aFrame)
380 : TTextAttr<nsString>(!aFrame) {
381 mIsRootDefined = GetFontFamily(aRootFrame, mRootNativeValue);
382
383 if (aFrame) mIsDefined = GetFontFamily(aFrame, mNativeValue);
384 }
385
GetValueFor(LocalAccessible * aAccessible,nsString * aValue)386 bool TextAttrsMgr::FontFamilyTextAttr::GetValueFor(LocalAccessible* aAccessible,
387 nsString* aValue) {
388 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
389 if (elm) {
390 nsIFrame* frame = elm->GetPrimaryFrame();
391 if (frame) {
392 return GetFontFamily(frame, *aValue);
393 }
394 }
395 return false;
396 }
397
ExposeValue(AccAttributes * aAttributes,const nsString & aValue)398 void TextAttrsMgr::FontFamilyTextAttr::ExposeValue(AccAttributes* aAttributes,
399 const nsString& aValue) {
400 aAttributes->SetAttribute(nsGkAtoms::font_family, aValue);
401 }
402
GetFontFamily(nsIFrame * aFrame,nsString & aFamily)403 bool TextAttrsMgr::FontFamilyTextAttr::GetFontFamily(nsIFrame* aFrame,
404 nsString& aFamily) {
405 RefPtr<nsFontMetrics> fm =
406 nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
407
408 gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
409 gfxFont* font = fontGroup->GetFirstValidFont();
410 gfxFontEntry* fontEntry = font->GetFontEntry();
411 aFamily.Append(NS_ConvertUTF8toUTF16(fontEntry->FamilyName()));
412 return true;
413 }
414
415 ////////////////////////////////////////////////////////////////////////////////
416 // FontSizeTextAttr
417 ////////////////////////////////////////////////////////////////////////////////
418
FontSizeTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)419 TextAttrsMgr::FontSizeTextAttr::FontSizeTextAttr(nsIFrame* aRootFrame,
420 nsIFrame* aFrame)
421 : TTextAttr<nscoord>(!aFrame) {
422 mDC = aRootFrame->PresContext()->DeviceContext();
423
424 mRootNativeValue = aRootFrame->StyleFont()->mSize.ToAppUnits();
425 mIsRootDefined = true;
426
427 if (aFrame) {
428 mNativeValue = aFrame->StyleFont()->mSize.ToAppUnits();
429 mIsDefined = true;
430 }
431 }
432
GetValueFor(LocalAccessible * aAccessible,nscoord * aValue)433 bool TextAttrsMgr::FontSizeTextAttr::GetValueFor(LocalAccessible* aAccessible,
434 nscoord* aValue) {
435 nsIContent* el = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
436 if (el) {
437 nsIFrame* frame = el->GetPrimaryFrame();
438 if (frame) {
439 *aValue = frame->StyleFont()->mSize.ToAppUnits();
440 return true;
441 }
442 }
443 return false;
444 }
445
ExposeValue(AccAttributes * aAttributes,const nscoord & aValue)446 void TextAttrsMgr::FontSizeTextAttr::ExposeValue(AccAttributes* aAttributes,
447 const nscoord& aValue) {
448 // Convert from nscoord to pt.
449 //
450 // Note: according to IA2, "The conversion doesn't have to be exact.
451 // The intent is to give the user a feel for the size of the text."
452 //
453 // ATK does not specify a unit and will likely follow IA2 here.
454 //
455 // XXX todo: consider sharing this code with layout module? (bug 474621)
456 float px = NSAppUnitsToFloatPixels(aValue, mozilla::AppUnitsPerCSSPixel());
457 // Each pt is 4/3 of a CSS pixel.
458 FontSize fontSize{NS_lround(px * 3 / 4)};
459
460 aAttributes->SetAttribute(nsGkAtoms::font_size, fontSize);
461 }
462
463 ////////////////////////////////////////////////////////////////////////////////
464 // FontStyleTextAttr
465 ////////////////////////////////////////////////////////////////////////////////
466
FontStyleTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)467 TextAttrsMgr::FontStyleTextAttr::FontStyleTextAttr(nsIFrame* aRootFrame,
468 nsIFrame* aFrame)
469 : TTextAttr<FontSlantStyle>(!aFrame) {
470 mRootNativeValue = aRootFrame->StyleFont()->mFont.style;
471 mIsRootDefined = true;
472
473 if (aFrame) {
474 mNativeValue = aFrame->StyleFont()->mFont.style;
475 mIsDefined = true;
476 }
477 }
478
GetValueFor(LocalAccessible * aAccessible,FontSlantStyle * aValue)479 bool TextAttrsMgr::FontStyleTextAttr::GetValueFor(LocalAccessible* aAccessible,
480 FontSlantStyle* aValue) {
481 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
482 if (elm) {
483 nsIFrame* frame = elm->GetPrimaryFrame();
484 if (frame) {
485 *aValue = frame->StyleFont()->mFont.style;
486 return true;
487 }
488 }
489 return false;
490 }
491
ExposeValue(AccAttributes * aAttributes,const FontSlantStyle & aValue)492 void TextAttrsMgr::FontStyleTextAttr::ExposeValue(
493 AccAttributes* aAttributes, const FontSlantStyle& aValue) {
494 if (aValue.IsNormal()) {
495 aAttributes->SetAttribute(nsGkAtoms::font_style, nsGkAtoms::normal);
496 } else if (aValue.IsItalic()) {
497 RefPtr<nsAtom> atom = NS_Atomize("italic");
498 aAttributes->SetAttribute(nsGkAtoms::font_style, atom);
499 } else {
500 auto angle = aValue.ObliqueAngle();
501 nsAutoString string;
502 string.AppendLiteral("oblique");
503 if (angle != FontSlantStyle::kDefaultAngle) {
504 string.AppendLiteral(" ");
505 nsStyleUtil::AppendCSSNumber(angle, string);
506 string.AppendLiteral("deg");
507 }
508 aAttributes->SetAttribute(nsGkAtoms::font_style, string);
509 }
510 }
511
512 ////////////////////////////////////////////////////////////////////////////////
513 // FontWeightTextAttr
514 ////////////////////////////////////////////////////////////////////////////////
515
FontWeightTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)516 TextAttrsMgr::FontWeightTextAttr::FontWeightTextAttr(nsIFrame* aRootFrame,
517 nsIFrame* aFrame)
518 : TTextAttr<FontWeight>(!aFrame) {
519 mRootNativeValue = GetFontWeight(aRootFrame);
520 mIsRootDefined = true;
521
522 if (aFrame) {
523 mNativeValue = GetFontWeight(aFrame);
524 mIsDefined = true;
525 }
526 }
527
GetValueFor(LocalAccessible * aAccessible,FontWeight * aValue)528 bool TextAttrsMgr::FontWeightTextAttr::GetValueFor(LocalAccessible* aAccessible,
529 FontWeight* aValue) {
530 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
531 if (elm) {
532 nsIFrame* frame = elm->GetPrimaryFrame();
533 if (frame) {
534 *aValue = GetFontWeight(frame);
535 return true;
536 }
537 }
538 return false;
539 }
540
ExposeValue(AccAttributes * aAttributes,const FontWeight & aValue)541 void TextAttrsMgr::FontWeightTextAttr::ExposeValue(AccAttributes* aAttributes,
542 const FontWeight& aValue) {
543 aAttributes->SetAttribute(nsGkAtoms::fontWeight, aValue.ToIntRounded());
544 }
545
GetFontWeight(nsIFrame * aFrame)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);
551
552 gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
553 gfxFont* font = fontGroup->GetFirstValidFont();
554
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. IsSyntheticBold method is only
558 // needed on Mac, but it is "safe" to use on all platforms. (For non-Mac
559 // platforms it always return false.)
560 if (font->IsSyntheticBold()) {
561 return FontWeight::Bold();
562 }
563
564 // On Windows, font->GetStyle()->weight will give the same weight as
565 // fontEntry->Weight(), the weight of the first font in the font group,
566 // which may not be the weight of the font face used to render the
567 // characters. On Mac, font->GetStyle()->weight will just give the same
568 // number as getComputedStyle(). fontEntry->Weight() will give the weight
569 // range supported by the font face used, so we clamp the weight that was
570 // requested by style to what is actually supported by the font.
571 gfxFontEntry* fontEntry = font->GetFontEntry();
572 return fontEntry->Weight().Clamp(font->GetStyle()->weight);
573 }
574
575 ////////////////////////////////////////////////////////////////////////////////
576 // AutoGeneratedTextAttr
577 ////////////////////////////////////////////////////////////////////////////////
AutoGeneratedTextAttr(HyperTextAccessible * aHyperTextAcc,LocalAccessible * aAccessible)578 TextAttrsMgr::AutoGeneratedTextAttr::AutoGeneratedTextAttr(
579 HyperTextAccessible* aHyperTextAcc, LocalAccessible* aAccessible)
580 : TTextAttr<bool>(!aAccessible) {
581 mRootNativeValue = false;
582 mIsRootDefined = false;
583
584 if (aAccessible) {
585 mIsDefined = mNativeValue =
586 ((aAccessible->NativeRole() == roles::STATICTEXT) ||
587 (aAccessible->NativeRole() == roles::LISTITEM_MARKER));
588 }
589 }
590
GetValueFor(LocalAccessible * aAccessible,bool * aValue)591 bool TextAttrsMgr::AutoGeneratedTextAttr::GetValueFor(
592 LocalAccessible* aAccessible, bool* aValue) {
593 return *aValue = (aAccessible->NativeRole() == roles::STATICTEXT);
594 }
595
ExposeValue(AccAttributes * aAttributes,const bool & aValue)596 void TextAttrsMgr::AutoGeneratedTextAttr::ExposeValue(
597 AccAttributes* aAttributes, const bool& aValue) {
598 aAttributes->SetAttribute(nsGkAtoms::auto_generated, aValue);
599 }
600
601 ////////////////////////////////////////////////////////////////////////////////
602 // TextDecorTextAttr
603 ////////////////////////////////////////////////////////////////////////////////
604
TextDecorValue(nsIFrame * aFrame)605 TextAttrsMgr::TextDecorValue::TextDecorValue(nsIFrame* aFrame) {
606 const nsStyleTextReset* textReset = aFrame->StyleTextReset();
607 mStyle = textReset->mTextDecorationStyle;
608 mColor = textReset->mTextDecorationColor.CalcColor(aFrame);
609 mLine =
610 textReset->mTextDecorationLine & (StyleTextDecorationLine::UNDERLINE |
611 StyleTextDecorationLine::LINE_THROUGH);
612 }
613
TextDecorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)614 TextAttrsMgr::TextDecorTextAttr::TextDecorTextAttr(nsIFrame* aRootFrame,
615 nsIFrame* aFrame)
616 : TTextAttr<TextDecorValue>(!aFrame) {
617 mRootNativeValue = TextDecorValue(aRootFrame);
618 mIsRootDefined = mRootNativeValue.IsDefined();
619
620 if (aFrame) {
621 mNativeValue = TextDecorValue(aFrame);
622 mIsDefined = mNativeValue.IsDefined();
623 }
624 }
625
GetValueFor(LocalAccessible * aAccessible,TextDecorValue * aValue)626 bool TextAttrsMgr::TextDecorTextAttr::GetValueFor(LocalAccessible* aAccessible,
627 TextDecorValue* aValue) {
628 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
629 if (elm) {
630 nsIFrame* frame = elm->GetPrimaryFrame();
631 if (frame) {
632 *aValue = TextDecorValue(frame);
633 return aValue->IsDefined();
634 }
635 }
636 return false;
637 }
638
ExposeValue(AccAttributes * aAttributes,const TextDecorValue & aValue)639 void TextAttrsMgr::TextDecorTextAttr::ExposeValue(
640 AccAttributes* aAttributes, const TextDecorValue& aValue) {
641 if (aValue.IsUnderline()) {
642 RefPtr<nsAtom> underlineStyle =
643 StyleInfo::TextDecorationStyleToAtom(aValue.Style());
644 aAttributes->SetAttribute(nsGkAtoms::textUnderlineStyle, underlineStyle);
645
646 aAttributes->SetAttribute(nsGkAtoms::textUnderlineColor,
647 Color{aValue.Color()});
648 return;
649 }
650
651 if (aValue.IsLineThrough()) {
652 RefPtr<nsAtom> lineThroughStyle =
653 StyleInfo::TextDecorationStyleToAtom(aValue.Style());
654 aAttributes->SetAttribute(nsGkAtoms::textLineThroughStyle,
655 lineThroughStyle);
656
657 aAttributes->SetAttribute(nsGkAtoms::textLineThroughColor,
658 Color{aValue.Color()});
659 }
660 }
661
662 ////////////////////////////////////////////////////////////////////////////////
663 // TextPosTextAttr
664 ////////////////////////////////////////////////////////////////////////////////
665
TextPosTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)666 TextAttrsMgr::TextPosTextAttr::TextPosTextAttr(nsIFrame* aRootFrame,
667 nsIFrame* aFrame)
668 : TTextAttr<TextPosValue>(!aFrame) {
669 mRootNativeValue = GetTextPosValue(aRootFrame);
670 mIsRootDefined = mRootNativeValue != eTextPosNone;
671
672 if (aFrame) {
673 mNativeValue = GetTextPosValue(aFrame);
674 mIsDefined = mNativeValue != eTextPosNone;
675 }
676 }
677
GetValueFor(LocalAccessible * aAccessible,TextPosValue * aValue)678 bool TextAttrsMgr::TextPosTextAttr::GetValueFor(LocalAccessible* aAccessible,
679 TextPosValue* aValue) {
680 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
681 if (elm) {
682 nsIFrame* frame = elm->GetPrimaryFrame();
683 if (frame) {
684 *aValue = GetTextPosValue(frame);
685 return *aValue != eTextPosNone;
686 }
687 }
688 return false;
689 }
690
ExposeValue(AccAttributes * aAttributes,const TextPosValue & aValue)691 void TextAttrsMgr::TextPosTextAttr::ExposeValue(AccAttributes* aAttributes,
692 const TextPosValue& aValue) {
693 RefPtr<nsAtom> atom = nullptr;
694 switch (aValue) {
695 case eTextPosBaseline:
696 atom = nsGkAtoms::baseline;
697 break;
698
699 case eTextPosSub:
700 atom = nsGkAtoms::sub;
701 break;
702
703 case eTextPosSuper:
704 atom = NS_Atomize("super");
705 break;
706
707 case eTextPosNone:
708 break;
709 }
710
711 if (atom) {
712 aAttributes->SetAttribute(nsGkAtoms::textPosition, atom);
713 }
714 }
715
GetTextPosValue(nsIFrame * aFrame) const716 TextAttrsMgr::TextPosValue TextAttrsMgr::TextPosTextAttr::GetTextPosValue(
717 nsIFrame* aFrame) const {
718 const auto& verticalAlign = aFrame->StyleDisplay()->mVerticalAlign;
719 if (verticalAlign.IsKeyword()) {
720 switch (verticalAlign.AsKeyword()) {
721 case StyleVerticalAlignKeyword::Baseline:
722 return eTextPosBaseline;
723 case StyleVerticalAlignKeyword::Sub:
724 return eTextPosSub;
725 case StyleVerticalAlignKeyword::Super:
726 return eTextPosSuper;
727 // No good guess for the rest, so do not expose value of text-position
728 // attribute.
729 default:
730 return eTextPosNone;
731 }
732 }
733
734 const auto& length = verticalAlign.AsLength();
735 if (length.ConvertsToPercentage()) {
736 float percentValue = length.ToPercentage();
737 return percentValue > 0
738 ? eTextPosSuper
739 : (percentValue < 0 ? eTextPosSub : eTextPosBaseline);
740 }
741
742 if (length.ConvertsToLength()) {
743 nscoord coordValue = length.ToLength();
744 return coordValue > 0 ? eTextPosSuper
745 : (coordValue < 0 ? eTextPosSub : eTextPosBaseline);
746 }
747
748 if (const nsIContent* content = aFrame->GetContent()) {
749 if (content->IsHTMLElement(nsGkAtoms::sup)) return eTextPosSuper;
750 if (content->IsHTMLElement(nsGkAtoms::sub)) return eTextPosSub;
751 }
752
753 return eTextPosNone;
754 }
755