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 "Accessible-inl.h"
9 #include "nsAccUtils.h"
10 #include "nsCoreUtils.h"
11 #include "StyleInfo.h"
12
13 #include "gfxFont.h"
14 #include "nsFontMetrics.h"
15 #include "nsLayoutUtils.h"
16 #include "nsContainerFrame.h"
17 #include "HyperTextAccessible.h"
18 #include "mozilla/AppUnits.h"
19 #include "mozilla/gfx/2D.h"
20
21 #if defined(MOZ_WIDGET_GTK)
22 #include "gfxPlatformGtk.h" // xxx - for UseFcFontList
23 #endif
24
25 using namespace mozilla;
26 using namespace mozilla::a11y;
27
28 ////////////////////////////////////////////////////////////////////////////////
29 // TextAttrsMgr
30 ////////////////////////////////////////////////////////////////////////////////
31
32 void
GetAttributes(nsIPersistentProperties * aAttributes,uint32_t * aStartOffset,uint32_t * aEndOffset)33 TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes,
34 uint32_t* aStartOffset,
35 uint32_t* aEndOffset)
36 {
37 // 1. Hyper text accessible must be specified always.
38 // 2. Offset accessible and result hyper text offsets must be specified in
39 // the case of text attributes.
40 // 3. Offset accessible and result hyper text offsets must not be specified
41 // but include default text attributes flag and attributes list must be
42 // specified in the case of default text attributes.
43 NS_PRECONDITION(mHyperTextAcc &&
44 ((mOffsetAcc && mOffsetAccIdx != -1 &&
45 aStartOffset && aEndOffset) ||
46 (!mOffsetAcc && mOffsetAccIdx == -1 &&
47 !aStartOffset && !aEndOffset &&
48 mIncludeDefAttrs && aAttributes)),
49 "Wrong usage of TextAttrsMgr!");
50
51 // Embedded objects are combined into own range with empty attributes set.
52 if (mOffsetAcc && !mOffsetAcc->IsText()) {
53 for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
54 Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
55 if (currAcc->IsText())
56 break;
57
58 (*aStartOffset)--;
59 }
60
61 uint32_t childCount = mHyperTextAcc->ChildCount();
62 for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childCount;
63 childIdx++) {
64 Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
65 if (currAcc->IsText())
66 break;
67
68 (*aEndOffset)++;
69 }
70
71 return;
72 }
73
74 // Get the content and frame of the accessible. In the case of document
75 // accessible it's role content and root frame.
76 nsIContent* hyperTextElm = mHyperTextAcc->GetContent();
77 if (!hyperTextElm)
78 return; // XXX: we don't support text attrs on document with no body
79
80 nsIFrame* rootFrame = mHyperTextAcc->GetFrame();
81 MOZ_ASSERT(rootFrame, "No frame for accessible!");
82 if (!rootFrame)
83 return;
84
85 nsIContent *offsetNode = nullptr, *offsetElm = nullptr;
86 nsIFrame *frame = nullptr;
87 if (mOffsetAcc) {
88 offsetNode = mOffsetAcc->GetContent();
89 offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
90 MOZ_ASSERT(offsetElm, "No element for offset accessible!");
91 if (!offsetElm)
92 return;
93
94 frame = offsetElm->GetPrimaryFrame();
95 }
96
97 // "language" text attribute
98 LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
99
100 // "aria-invalid" text attribute
101 InvalidTextAttr invalidTextAttr(hyperTextElm, offsetNode);
102
103 // "background-color" text attribute
104 BGColorTextAttr bgColorTextAttr(rootFrame, frame);
105
106 // "color" text attribute
107 ColorTextAttr colorTextAttr(rootFrame, frame);
108
109 // "font-family" text attribute
110 FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame);
111
112 // "font-size" text attribute
113 FontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
114
115 // "font-style" text attribute
116 FontStyleTextAttr fontStyleTextAttr(rootFrame, frame);
117
118 // "font-weight" text attribute
119 FontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
120
121 // "auto-generated" text attribute
122 AutoGeneratedTextAttr autoGenTextAttr(mHyperTextAcc, mOffsetAcc);
123
124 // "text-underline(line-through)-style(color)" text attributes
125 TextDecorTextAttr textDecorTextAttr(rootFrame, frame);
126
127 // "text-position" text attribute
128 TextPosTextAttr textPosTextAttr(rootFrame, frame);
129
130 TextAttr* attrArray[] =
131 {
132 &langTextAttr,
133 &invalidTextAttr,
134 &bgColorTextAttr,
135 &colorTextAttr,
136 &fontFamilyTextAttr,
137 &fontSizeTextAttr,
138 &fontStyleTextAttr,
139 &fontWeightTextAttr,
140 &autoGenTextAttr,
141 &textDecorTextAttr,
142 &textPosTextAttr
143 };
144
145 // Expose text attributes if applicable.
146 if (aAttributes) {
147 for (uint32_t idx = 0; idx < ArrayLength(attrArray); idx++)
148 attrArray[idx]->Expose(aAttributes, mIncludeDefAttrs);
149 }
150
151 // Expose text attributes range where they are applied if applicable.
152 if (mOffsetAcc)
153 GetRange(attrArray, ArrayLength(attrArray), aStartOffset, aEndOffset);
154 }
155
156 void
GetRange(TextAttr * aAttrArray[],uint32_t aAttrArrayLen,uint32_t * aStartOffset,uint32_t * aEndOffset)157 TextAttrsMgr::GetRange(TextAttr* aAttrArray[], uint32_t aAttrArrayLen,
158 uint32_t* aStartOffset, uint32_t* aEndOffset)
159 {
160 // Navigate backward from anchor accessible to find start offset.
161 for (int32_t childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
162 Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
163
164 // Stop on embedded accessible since embedded accessibles are combined into
165 // own range.
166 if (!currAcc->IsText())
167 break;
168
169 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
170 "Text accessible has to have an associated DOM element");
171
172 bool offsetFound = false;
173 for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
174 TextAttr* textAttr = aAttrArray[attrIdx];
175 if (!textAttr->Equal(currAcc)) {
176 offsetFound = true;
177 break;
178 }
179 }
180
181 if (offsetFound)
182 break;
183
184 *(aStartOffset) -= nsAccUtils::TextLength(currAcc);
185 }
186
187 // Navigate forward from anchor accessible to find end offset.
188 uint32_t childLen = mHyperTextAcc->ChildCount();
189 for (uint32_t childIdx = mOffsetAccIdx + 1; childIdx < childLen; childIdx++) {
190 Accessible* currAcc = mHyperTextAcc->GetChildAt(childIdx);
191 if (!currAcc->IsText())
192 break;
193
194 MOZ_ASSERT(nsCoreUtils::GetDOMElementFor(currAcc->GetContent()),
195 "Text accessible has to have an associated DOM element");
196
197 bool offsetFound = false;
198 for (uint32_t attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
199 TextAttr* textAttr = aAttrArray[attrIdx];
200
201 // Alter the end offset when text attribute changes its value and stop
202 // the search.
203 if (!textAttr->Equal(currAcc)) {
204 offsetFound = true;
205 break;
206 }
207 }
208
209 if (offsetFound)
210 break;
211
212 (*aEndOffset) += nsAccUtils::TextLength(currAcc);
213 }
214 }
215
216
217 ////////////////////////////////////////////////////////////////////////////////
218 // LangTextAttr
219 ////////////////////////////////////////////////////////////////////////////////
220
221 TextAttrsMgr::LangTextAttr::
LangTextAttr(HyperTextAccessible * aRoot,nsIContent * aRootElm,nsIContent * aElm)222 LangTextAttr(HyperTextAccessible* aRoot,
223 nsIContent* aRootElm, nsIContent* aElm) :
224 TTextAttr<nsString>(!aElm), mRootContent(aRootElm)
225 {
226 aRoot->Language(mRootNativeValue);
227 mIsRootDefined = !mRootNativeValue.IsEmpty();
228
229 if (aElm) {
230 nsCoreUtils::GetLanguageFor(aElm, mRootContent, mNativeValue);
231 mIsDefined = !mNativeValue.IsEmpty();
232 }
233 }
234
235 TextAttrsMgr::LangTextAttr::
~LangTextAttr()236 ~LangTextAttr() {}
237
238 bool
239 TextAttrsMgr::LangTextAttr::
GetValueFor(Accessible * aAccessible,nsString * aValue)240 GetValueFor(Accessible* aAccessible, nsString* aValue)
241 {
242 nsCoreUtils::GetLanguageFor(aAccessible->GetContent(), mRootContent, *aValue);
243 return !aValue->IsEmpty();
244 }
245
246 void
247 TextAttrsMgr::LangTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nsString & aValue)248 ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
249 {
250 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::language, aValue);
251 }
252
253 ////////////////////////////////////////////////////////////////////////////////
254 // InvalidTextAttr
255 ////////////////////////////////////////////////////////////////////////////////
256
257 TextAttrsMgr::InvalidTextAttr::
InvalidTextAttr(nsIContent * aRootElm,nsIContent * aElm)258 InvalidTextAttr(nsIContent* aRootElm, nsIContent* aElm) :
259 TTextAttr<uint32_t>(!aElm), mRootElm(aRootElm)
260 {
261 mIsRootDefined = GetValue(mRootElm, &mRootNativeValue);
262 if (aElm)
263 mIsDefined = GetValue(aElm, &mNativeValue);
264 }
265
266 bool
267 TextAttrsMgr::InvalidTextAttr::
GetValueFor(Accessible * aAccessible,uint32_t * aValue)268 GetValueFor(Accessible* aAccessible, uint32_t* aValue)
269 {
270 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
271 return elm ? GetValue(elm, aValue) : false;
272 }
273
274 void
275 TextAttrsMgr::InvalidTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const uint32_t & aValue)276 ExposeValue(nsIPersistentProperties* aAttributes, const uint32_t& aValue)
277 {
278 switch (aValue) {
279 case eFalse:
280 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::invalid,
281 NS_LITERAL_STRING("false"));
282 break;
283
284 case eGrammar:
285 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::invalid,
286 NS_LITERAL_STRING("grammar"));
287 break;
288
289 case eSpelling:
290 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::invalid,
291 NS_LITERAL_STRING("spelling"));
292 break;
293
294 case eTrue:
295 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::invalid,
296 NS_LITERAL_STRING("true"));
297 break;
298 }
299 }
300
301 bool
302 TextAttrsMgr::InvalidTextAttr::
GetValue(nsIContent * aElm,uint32_t * aValue)303 GetValue(nsIContent* aElm, uint32_t* aValue)
304 {
305 nsIContent* elm = aElm;
306 do {
307 if (nsAccUtils::HasDefinedARIAToken(elm, nsGkAtoms::aria_invalid)) {
308 static nsIContent::AttrValuesArray tokens[] =
309 { &nsGkAtoms::_false, &nsGkAtoms::grammar, &nsGkAtoms::spelling,
310 nullptr };
311
312 int32_t idx = elm->FindAttrValueIn(kNameSpaceID_None,
313 nsGkAtoms::aria_invalid, tokens,
314 eCaseMatters);
315 switch (idx) {
316 case 0:
317 *aValue = eFalse;
318 return true;
319 case 1:
320 *aValue = eGrammar;
321 return true;
322 case 2:
323 *aValue = eSpelling;
324 return true;
325 default:
326 *aValue = eTrue;
327 return true;
328 }
329 }
330 } while ((elm = elm->GetParent()) && elm != mRootElm);
331
332 return false;
333 }
334
335
336 ////////////////////////////////////////////////////////////////////////////////
337 // BGColorTextAttr
338 ////////////////////////////////////////////////////////////////////////////////
339
340 TextAttrsMgr::BGColorTextAttr::
BGColorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)341 BGColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
342 TTextAttr<nscolor>(!aFrame), mRootFrame(aRootFrame)
343 {
344 mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
345 if (aFrame)
346 mIsDefined = GetColor(aFrame, &mNativeValue);
347 }
348
349 bool
350 TextAttrsMgr::BGColorTextAttr::
GetValueFor(Accessible * aAccessible,nscolor * aValue)351 GetValueFor(Accessible* aAccessible, nscolor* aValue)
352 {
353 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
354 if (elm) {
355 nsIFrame* frame = elm->GetPrimaryFrame();
356 if (frame) {
357 return GetColor(frame, aValue);
358 }
359 }
360 return false;
361 }
362
363 void
364 TextAttrsMgr::BGColorTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nscolor & aValue)365 ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
366 {
367 nsAutoString formattedValue;
368 StyleInfo::FormatColor(aValue, formattedValue);
369 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::backgroundColor,
370 formattedValue);
371 }
372
373 bool
374 TextAttrsMgr::BGColorTextAttr::
GetColor(nsIFrame * aFrame,nscolor * aColor)375 GetColor(nsIFrame* aFrame, nscolor* aColor)
376 {
377 const nsStyleBackground* styleBackground = aFrame->StyleBackground();
378
379 if (NS_GET_A(styleBackground->mBackgroundColor) > 0) {
380 *aColor = styleBackground->mBackgroundColor;
381 return true;
382 }
383
384 nsContainerFrame *parentFrame = aFrame->GetParent();
385 if (!parentFrame) {
386 *aColor = aFrame->PresContext()->DefaultBackgroundColor();
387 return true;
388 }
389
390 // Each frame of parents chain for the initially passed 'aFrame' has
391 // transparent background color. So background color isn't changed from
392 // 'mRootFrame' to initially passed 'aFrame'.
393 if (parentFrame == mRootFrame)
394 return false;
395
396 return GetColor(parentFrame, aColor);
397 }
398
399
400 ////////////////////////////////////////////////////////////////////////////////
401 // ColorTextAttr
402 ////////////////////////////////////////////////////////////////////////////////
403
404 TextAttrsMgr::ColorTextAttr::
ColorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)405 ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
406 TTextAttr<nscolor>(!aFrame)
407 {
408 mRootNativeValue = aRootFrame->StyleColor()->mColor;
409 mIsRootDefined = true;
410
411 if (aFrame) {
412 mNativeValue = aFrame->StyleColor()->mColor;
413 mIsDefined = true;
414 }
415 }
416
417 bool
418 TextAttrsMgr::ColorTextAttr::
GetValueFor(Accessible * aAccessible,nscolor * aValue)419 GetValueFor(Accessible* aAccessible, nscolor* aValue)
420 {
421 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
422 if (elm) {
423 nsIFrame* frame = elm->GetPrimaryFrame();
424 if (frame) {
425 *aValue = frame->StyleColor()->mColor;
426 return true;
427 }
428 }
429 return false;
430 }
431
432 void
433 TextAttrsMgr::ColorTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nscolor & aValue)434 ExposeValue(nsIPersistentProperties* aAttributes, const nscolor& aValue)
435 {
436 nsAutoString formattedValue;
437 StyleInfo::FormatColor(aValue, formattedValue);
438 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::color, formattedValue);
439 }
440
441
442 ////////////////////////////////////////////////////////////////////////////////
443 // FontFamilyTextAttr
444 ////////////////////////////////////////////////////////////////////////////////
445
446 TextAttrsMgr::FontFamilyTextAttr::
FontFamilyTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)447 FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
448 TTextAttr<nsString>(!aFrame)
449 {
450 mIsRootDefined = GetFontFamily(aRootFrame, mRootNativeValue);
451
452 if (aFrame)
453 mIsDefined = GetFontFamily(aFrame, mNativeValue);
454 }
455
456 bool
457 TextAttrsMgr::FontFamilyTextAttr::
GetValueFor(Accessible * aAccessible,nsString * aValue)458 GetValueFor(Accessible* aAccessible, nsString* aValue)
459 {
460 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
461 if (elm) {
462 nsIFrame* frame = elm->GetPrimaryFrame();
463 if (frame) {
464 return GetFontFamily(frame, *aValue);
465 }
466 }
467 return false;
468 }
469
470 void
471 TextAttrsMgr::FontFamilyTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nsString & aValue)472 ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
473 {
474 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_family, aValue);
475 }
476
477 bool
478 TextAttrsMgr::FontFamilyTextAttr::
GetFontFamily(nsIFrame * aFrame,nsString & aFamily)479 GetFontFamily(nsIFrame* aFrame, nsString& aFamily)
480 {
481 RefPtr<nsFontMetrics> fm =
482 nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
483
484 gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
485 gfxFont* font = fontGroup->GetFirstValidFont();
486 gfxFontEntry* fontEntry = font->GetFontEntry();
487 aFamily = fontEntry->FamilyName();
488 return true;
489 }
490
491
492 ////////////////////////////////////////////////////////////////////////////////
493 // FontSizeTextAttr
494 ////////////////////////////////////////////////////////////////////////////////
495
496 TextAttrsMgr::FontSizeTextAttr::
FontSizeTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)497 FontSizeTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
498 TTextAttr<nscoord>(!aFrame)
499 {
500 mDC = aRootFrame->PresContext()->DeviceContext();
501
502 mRootNativeValue = aRootFrame->StyleFont()->mSize;
503 mIsRootDefined = true;
504
505 if (aFrame) {
506 mNativeValue = aFrame->StyleFont()->mSize;
507 mIsDefined = true;
508 }
509 }
510
511 bool
512 TextAttrsMgr::FontSizeTextAttr::
GetValueFor(Accessible * aAccessible,nscoord * aValue)513 GetValueFor(Accessible* aAccessible, nscoord* aValue)
514 {
515 nsIContent* el = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
516 if (el) {
517 nsIFrame* frame = el->GetPrimaryFrame();
518 if (frame) {
519 *aValue = frame->StyleFont()->mSize;
520 return true;
521 }
522 }
523 return false;
524 }
525
526 void
527 TextAttrsMgr::FontSizeTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nscoord & aValue)528 ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
529 {
530 // Convert from nscoord to pt.
531 //
532 // Note: according to IA2, "The conversion doesn't have to be exact.
533 // The intent is to give the user a feel for the size of the text."
534 //
535 // ATK does not specify a unit and will likely follow IA2 here.
536 //
537 // XXX todo: consider sharing this code with layout module? (bug 474621)
538 float px =
539 NSAppUnitsToFloatPixels(aValue, mozilla::AppUnitsPerCSSPixel());
540 // Each pt is 4/3 of a CSS pixel.
541 int pts = NS_lround(px*3/4);
542
543 nsAutoString value;
544 value.AppendInt(pts);
545 value.AppendLiteral("pt");
546
547 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_size, value);
548 }
549
550
551 ////////////////////////////////////////////////////////////////////////////////
552 // FontStyleTextAttr
553 ////////////////////////////////////////////////////////////////////////////////
554
555 TextAttrsMgr::FontStyleTextAttr::
FontStyleTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)556 FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
557 TTextAttr<nscoord>(!aFrame)
558 {
559 mRootNativeValue = aRootFrame->StyleFont()->mFont.style;
560 mIsRootDefined = true;
561
562 if (aFrame) {
563 mNativeValue = aFrame->StyleFont()->mFont.style;
564 mIsDefined = true;
565 }
566 }
567
568 bool
569 TextAttrsMgr::FontStyleTextAttr::
GetValueFor(Accessible * aAccessible,nscoord * aValue)570 GetValueFor(Accessible* aAccessible, nscoord* aValue)
571 {
572 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
573 if (elm) {
574 nsIFrame* frame = elm->GetPrimaryFrame();
575 if (frame) {
576 *aValue = frame->StyleFont()->mFont.style;
577 return true;
578 }
579 }
580 return false;
581 }
582
583 void
584 TextAttrsMgr::FontStyleTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const nscoord & aValue)585 ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
586 {
587 nsAutoString formattedValue;
588 StyleInfo::FormatFontStyle(aValue, formattedValue);
589
590 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_style, formattedValue);
591 }
592
593
594 ////////////////////////////////////////////////////////////////////////////////
595 // FontWeightTextAttr
596 ////////////////////////////////////////////////////////////////////////////////
597
598 TextAttrsMgr::FontWeightTextAttr::
FontWeightTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)599 FontWeightTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
600 TTextAttr<int32_t>(!aFrame)
601 {
602 mRootNativeValue = GetFontWeight(aRootFrame);
603 mIsRootDefined = true;
604
605 if (aFrame) {
606 mNativeValue = GetFontWeight(aFrame);
607 mIsDefined = true;
608 }
609 }
610
611 bool
612 TextAttrsMgr::FontWeightTextAttr::
GetValueFor(Accessible * aAccessible,int32_t * aValue)613 GetValueFor(Accessible* aAccessible, int32_t* aValue)
614 {
615 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
616 if (elm) {
617 nsIFrame* frame = elm->GetPrimaryFrame();
618 if (frame) {
619 *aValue = GetFontWeight(frame);
620 return true;
621 }
622 }
623 return false;
624 }
625
626 void
627 TextAttrsMgr::FontWeightTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const int32_t & aValue)628 ExposeValue(nsIPersistentProperties* aAttributes, const int32_t& aValue)
629 {
630 nsAutoString formattedValue;
631 formattedValue.AppendInt(aValue);
632
633 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::fontWeight, formattedValue);
634 }
635
636 int32_t
637 TextAttrsMgr::FontWeightTextAttr::
GetFontWeight(nsIFrame * aFrame)638 GetFontWeight(nsIFrame* aFrame)
639 {
640 // nsFont::width isn't suitable here because it's necessary to expose real
641 // value of font weight (used font might not have some font weight values).
642 RefPtr<nsFontMetrics> fm =
643 nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f);
644
645 gfxFontGroup *fontGroup = fm->GetThebesFontGroup();
646 gfxFont *font = fontGroup->GetFirstValidFont();
647
648 // When there doesn't exist a bold font in the family and so the rendering of
649 // a non-bold font face is changed so that the user sees what looks like a
650 // bold font, i.e. synthetic bolding is used. IsSyntheticBold method is only
651 // needed on Mac, but it is "safe" to use on all platforms. (For non-Mac
652 // platforms it always return false.)
653 if (font->IsSyntheticBold())
654 return 700;
655
656 bool useFontEntryWeight = true;
657
658 // Under Linux, when gfxPangoFontGroup code is used,
659 // font->GetStyle()->weight will give the absolute weight requested of the
660 // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
661 // which doesn't initialize the weight field.
662 #if defined(MOZ_WIDGET_GTK)
663 useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
664 #endif
665
666 if (useFontEntryWeight) {
667 // On Windows, font->GetStyle()->weight will give the same weight as
668 // fontEntry->Weight(), the weight of the first font in the font group,
669 // which may not be the weight of the font face used to render the
670 // characters. On Mac, font->GetStyle()->weight will just give the same
671 // number as getComputedStyle(). fontEntry->Weight() will give the weight
672 // of the font face used.
673 gfxFontEntry *fontEntry = font->GetFontEntry();
674 return fontEntry->Weight();
675 } else {
676 return font->GetStyle()->weight;
677 }
678 }
679
680 ////////////////////////////////////////////////////////////////////////////////
681 // AutoGeneratedTextAttr
682 ////////////////////////////////////////////////////////////////////////////////
683 TextAttrsMgr::AutoGeneratedTextAttr::
AutoGeneratedTextAttr(HyperTextAccessible * aHyperTextAcc,Accessible * aAccessible)684 AutoGeneratedTextAttr(HyperTextAccessible* aHyperTextAcc,
685 Accessible* aAccessible) :
686 TTextAttr<bool>(!aAccessible)
687 {
688 mRootNativeValue = false;
689 mIsRootDefined = false;
690
691 if (aAccessible)
692 mIsDefined = mNativeValue = (aAccessible->NativeRole() == roles::STATICTEXT);
693 }
694
695 bool
696 TextAttrsMgr::AutoGeneratedTextAttr::
GetValueFor(Accessible * aAccessible,bool * aValue)697 GetValueFor(Accessible* aAccessible, bool* aValue)
698 {
699 return *aValue = (aAccessible->NativeRole() == roles::STATICTEXT);
700 }
701
702 void
703 TextAttrsMgr::AutoGeneratedTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const bool & aValue)704 ExposeValue(nsIPersistentProperties* aAttributes, const bool& aValue)
705 {
706 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::auto_generated,
707 aValue ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"));
708 }
709
710
711 ////////////////////////////////////////////////////////////////////////////////
712 // TextDecorTextAttr
713 ////////////////////////////////////////////////////////////////////////////////
714
715 TextAttrsMgr::TextDecorValue::
TextDecorValue(nsIFrame * aFrame)716 TextDecorValue(nsIFrame* aFrame)
717 {
718 const nsStyleTextReset* textReset = aFrame->StyleTextReset();
719 mStyle = textReset->mTextDecorationStyle;
720 mColor = aFrame->StyleColor()->
721 CalcComplexColor(textReset->mTextDecorationColor);
722 mLine = textReset->mTextDecorationLine &
723 (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE |
724 NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
725 }
726
727 TextAttrsMgr::TextDecorTextAttr::
TextDecorTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)728 TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
729 TTextAttr<TextDecorValue>(!aFrame)
730 {
731 mRootNativeValue = TextDecorValue(aRootFrame);
732 mIsRootDefined = mRootNativeValue.IsDefined();
733
734 if (aFrame) {
735 mNativeValue = TextDecorValue(aFrame);
736 mIsDefined = mNativeValue.IsDefined();
737 }
738 }
739
740 bool
741 TextAttrsMgr::TextDecorTextAttr::
GetValueFor(Accessible * aAccessible,TextDecorValue * aValue)742 GetValueFor(Accessible* aAccessible, TextDecorValue* aValue)
743 {
744 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
745 if (elm) {
746 nsIFrame* frame = elm->GetPrimaryFrame();
747 if (frame) {
748 *aValue = TextDecorValue(frame);
749 return aValue->IsDefined();
750 }
751 }
752 return false;
753 }
754
755 void
756 TextAttrsMgr::TextDecorTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const TextDecorValue & aValue)757 ExposeValue(nsIPersistentProperties* aAttributes, const TextDecorValue& aValue)
758 {
759 if (aValue.IsUnderline()) {
760 nsAutoString formattedStyle;
761 StyleInfo::FormatTextDecorationStyle(aValue.Style(), formattedStyle);
762 nsAccUtils::SetAccAttr(aAttributes,
763 nsGkAtoms::textUnderlineStyle,
764 formattedStyle);
765
766 nsAutoString formattedColor;
767 StyleInfo::FormatColor(aValue.Color(), formattedColor);
768 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textUnderlineColor,
769 formattedColor);
770 return;
771 }
772
773 if (aValue.IsLineThrough()) {
774 nsAutoString formattedStyle;
775 StyleInfo::FormatTextDecorationStyle(aValue.Style(), formattedStyle);
776 nsAccUtils::SetAccAttr(aAttributes,
777 nsGkAtoms::textLineThroughStyle,
778 formattedStyle);
779
780 nsAutoString formattedColor;
781 StyleInfo::FormatColor(aValue.Color(), formattedColor);
782 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textLineThroughColor,
783 formattedColor);
784 }
785 }
786
787 ////////////////////////////////////////////////////////////////////////////////
788 // TextPosTextAttr
789 ////////////////////////////////////////////////////////////////////////////////
790
791 TextAttrsMgr::TextPosTextAttr::
TextPosTextAttr(nsIFrame * aRootFrame,nsIFrame * aFrame)792 TextPosTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
793 TTextAttr<TextPosValue>(!aFrame)
794 {
795 mRootNativeValue = GetTextPosValue(aRootFrame);
796 mIsRootDefined = mRootNativeValue != eTextPosNone;
797
798 if (aFrame) {
799 mNativeValue = GetTextPosValue(aFrame);
800 mIsDefined = mNativeValue != eTextPosNone;
801 }
802 }
803
804 bool
805 TextAttrsMgr::TextPosTextAttr::
GetValueFor(Accessible * aAccessible,TextPosValue * aValue)806 GetValueFor(Accessible* aAccessible, TextPosValue* aValue)
807 {
808 nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
809 if (elm) {
810 nsIFrame* frame = elm->GetPrimaryFrame();
811 if (frame) {
812 *aValue = GetTextPosValue(frame);
813 return *aValue != eTextPosNone;
814 }
815 }
816 return false;
817 }
818
819 void
820 TextAttrsMgr::TextPosTextAttr::
ExposeValue(nsIPersistentProperties * aAttributes,const TextPosValue & aValue)821 ExposeValue(nsIPersistentProperties* aAttributes, const TextPosValue& aValue)
822 {
823 switch (aValue) {
824 case eTextPosBaseline:
825 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
826 NS_LITERAL_STRING("baseline"));
827 break;
828
829 case eTextPosSub:
830 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
831 NS_LITERAL_STRING("sub"));
832 break;
833
834 case eTextPosSuper:
835 nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
836 NS_LITERAL_STRING("super"));
837 break;
838
839 case eTextPosNone:
840 break;
841 }
842 }
843
844 TextAttrsMgr::TextPosValue
845 TextAttrsMgr::TextPosTextAttr::
GetTextPosValue(nsIFrame * aFrame) const846 GetTextPosValue(nsIFrame* aFrame) const
847 {
848 const nsStyleCoord& styleCoord = aFrame->StyleDisplay()->mVerticalAlign;
849 switch (styleCoord.GetUnit()) {
850 case eStyleUnit_Enumerated:
851 switch (styleCoord.GetIntValue()) {
852 case NS_STYLE_VERTICAL_ALIGN_BASELINE:
853 return eTextPosBaseline;
854 case NS_STYLE_VERTICAL_ALIGN_SUB:
855 return eTextPosSub;
856 case NS_STYLE_VERTICAL_ALIGN_SUPER:
857 return eTextPosSuper;
858
859 // No good guess for these:
860 // NS_STYLE_VERTICAL_ALIGN_TOP
861 // NS_STYLE_VERTICAL_ALIGN_TEXT_TOP
862 // NS_STYLE_VERTICAL_ALIGN_MIDDLE
863 // NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM
864 // NS_STYLE_VERTICAL_ALIGN_BOTTOM
865 // NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE
866 // Do not expose value of text-position attribute.
867
868 default:
869 break;
870 }
871 return eTextPosNone;
872
873 case eStyleUnit_Percent:
874 {
875 float percentValue = styleCoord.GetPercentValue();
876 return percentValue > 0 ?
877 eTextPosSuper :
878 (percentValue < 0 ? eTextPosSub : eTextPosBaseline);
879 }
880
881 case eStyleUnit_Coord:
882 {
883 nscoord coordValue = styleCoord.GetCoordValue();
884 return coordValue > 0 ?
885 eTextPosSuper :
886 (coordValue < 0 ? eTextPosSub : eTextPosBaseline);
887 }
888
889 case eStyleUnit_Null:
890 case eStyleUnit_Normal:
891 case eStyleUnit_Auto:
892 case eStyleUnit_None:
893 case eStyleUnit_Factor:
894 case eStyleUnit_Degree:
895 case eStyleUnit_Grad:
896 case eStyleUnit_Radian:
897 case eStyleUnit_Turn:
898 case eStyleUnit_FlexFraction:
899 case eStyleUnit_Integer:
900 case eStyleUnit_Calc:
901 break;
902 }
903
904 const nsIContent* content = aFrame->GetContent();
905 if (content) {
906 if (content->IsHTMLElement(nsGkAtoms::sup))
907 return eTextPosSuper;
908 if (content->IsHTMLElement(nsGkAtoms::sub))
909 return eTextPosSub;
910 }
911
912 return eTextPosNone;
913 }
914