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