1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "InterfaceInitFuncs.h"
9 #include "Accessible-inl.h"
10 #include "HyperTextAccessible-inl.h"
13 #include "nsIAccessibleTypes.h"
14 #include "nsIPersistentProperties2.h"
15 #include "nsISimpleEnumerator.h"
17 #include "mozilla/Likely.h"
19 using namespace mozilla
;
20 using namespace mozilla::a11y
;
22 static const char* sAtkTextAttrNames
[ATK_TEXT_ATTR_LAST_DEFINED
];
24 static AtkAttributeSet
*
25 ConvertToAtkTextAttributeSet(nsIPersistentProperties
* aAttributes
)
30 AtkAttributeSet
* objAttributeSet
= nullptr;
31 nsCOMPtr
<nsISimpleEnumerator
> propEnum
;
32 nsresult rv
= aAttributes
->Enumerate(getter_AddRefs(propEnum
));
33 NS_ENSURE_SUCCESS(rv
, nullptr);
36 while (NS_SUCCEEDED(propEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
37 nsCOMPtr
<nsISupports
> sup
;
38 rv
= propEnum
->GetNext(getter_AddRefs(sup
));
39 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
41 nsCOMPtr
<nsIPropertyElement
> propElem(do_QueryInterface(sup
));
42 NS_ENSURE_TRUE(propElem
, objAttributeSet
);
45 rv
= propElem
->GetKey(name
);
46 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
49 rv
= propElem
->GetValue(value
);
50 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
52 AtkAttribute
* objAttr
= (AtkAttribute
*)g_malloc(sizeof(AtkAttribute
));
53 objAttr
->name
= g_strdup(name
.get());
54 objAttr
->value
= g_strdup(NS_ConvertUTF16toUTF8(value
).get());
55 objAttributeSet
= g_slist_prepend(objAttributeSet
, objAttr
);
57 // Handle attributes where atk has its own name.
58 const char* atkName
= nullptr;
59 nsAutoString atkValue
;
60 if (name
.EqualsLiteral("color")) {
61 // The format of the atk attribute is r,g,b and the gecko one is
63 atkValue
= Substring(value
, 5, value
.Length() - 1);
64 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_FG_COLOR
];
65 } else if (name
.EqualsLiteral("background-color")) {
66 // The format of the atk attribute is r,g,b and the gecko one is
68 atkValue
= Substring(value
, 5, value
.Length() - 1);
69 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_BG_COLOR
];
70 } else if (name
.EqualsLiteral("font-family")) {
72 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_FAMILY_NAME
];
73 } else if (name
.EqualsLiteral("font-size")) {
74 // ATK wants the number of pixels without px at the end.
75 atkValue
= StringHead(value
, value
.Length() - 2);
76 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_SIZE
];
77 } else if (name
.EqualsLiteral("font-weight")) {
79 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_WEIGHT
];
80 } else if (name
.EqualsLiteral("invalid")) {
82 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_INVALID
];
86 objAttr
= static_cast<AtkAttribute
*>(g_malloc(sizeof(AtkAttribute
)));
87 objAttr
->name
= g_strdup(atkName
);
88 objAttr
->value
= g_strdup(NS_ConvertUTF16toUTF8(atkValue
).get());
89 objAttributeSet
= g_slist_prepend(objAttributeSet
, objAttr
);
93 // libatk-adaptor will free it
94 return objAttributeSet
;
98 ConvertTexttoAsterisks(AccessibleWrap
* accWrap
, nsAString
& aString
)
100 // convert each char to "*" when it's "password text"
101 if (accWrap
->NativeRole() == roles::PASSWORD_TEXT
) {
102 for (uint32_t i
= 0; i
< aString
.Length(); i
++)
103 aString
.Replace(i
, 1, NS_LITERAL_STRING("*"));
110 getTextCB(AtkText
*aText
, gint aStartOffset
, gint aEndOffset
)
112 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
116 HyperTextAccessible
* text
= accWrap
->AsHyperText();
117 if (!text
|| !text
->IsTextRole())
120 nsAutoString autoStr
;
121 text
->TextSubstring(aStartOffset
, aEndOffset
, autoStr
);
123 ConvertTexttoAsterisks(accWrap
, autoStr
);
124 NS_ConvertUTF16toUTF8
cautoStr(autoStr
);
126 //copy and return, libspi will free it.
127 return (cautoStr
.get()) ? g_strdup(cautoStr
.get()) : nullptr;
131 getTextAfterOffsetCB(AtkText
*aText
, gint aOffset
,
132 AtkTextBoundary aBoundaryType
,
133 gint
*aStartOffset
, gint
*aEndOffset
)
135 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
139 HyperTextAccessible
* text
= accWrap
->AsHyperText();
140 if (!text
|| !text
->IsTextRole())
143 nsAutoString autoStr
;
144 int32_t startOffset
= 0, endOffset
= 0;
145 text
->TextAfterOffset(aOffset
, aBoundaryType
, &startOffset
, &endOffset
, autoStr
);
147 *aStartOffset
= startOffset
;
148 *aEndOffset
= endOffset
;
150 ConvertTexttoAsterisks(accWrap
, autoStr
);
151 NS_ConvertUTF16toUTF8
cautoStr(autoStr
);
152 return (cautoStr
.get()) ? g_strdup(cautoStr
.get()) : nullptr;
156 getTextAtOffsetCB(AtkText
*aText
, gint aOffset
,
157 AtkTextBoundary aBoundaryType
,
158 gint
*aStartOffset
, gint
*aEndOffset
)
160 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
164 HyperTextAccessible
* text
= accWrap
->AsHyperText();
165 if (!text
|| !text
->IsTextRole())
168 nsAutoString autoStr
;
169 int32_t startOffset
= 0, endOffset
= 0;
170 text
->TextAtOffset(aOffset
, aBoundaryType
, &startOffset
, &endOffset
, autoStr
);
171 *aStartOffset
= startOffset
;
172 *aEndOffset
= endOffset
;
174 ConvertTexttoAsterisks(accWrap
, autoStr
);
175 NS_ConvertUTF16toUTF8
cautoStr(autoStr
);
176 return (cautoStr
.get()) ? g_strdup(cautoStr
.get()) : nullptr;
180 getCharacterAtOffsetCB(AtkText
* aText
, gint aOffset
)
182 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
186 HyperTextAccessible
* text
= accWrap
->AsHyperText();
187 if (!text
|| !text
->IsTextRole())
190 // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
191 return static_cast<gunichar
>(text
->CharAt(aOffset
));
195 getTextBeforeOffsetCB(AtkText
*aText
, gint aOffset
,
196 AtkTextBoundary aBoundaryType
,
197 gint
*aStartOffset
, gint
*aEndOffset
)
199 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
203 HyperTextAccessible
* text
= accWrap
->AsHyperText();
204 if (!text
|| !text
->IsTextRole())
207 nsAutoString autoStr
;
208 int32_t startOffset
= 0, endOffset
= 0;
209 text
->TextBeforeOffset(aOffset
, aBoundaryType
,
210 &startOffset
, &endOffset
, autoStr
);
211 *aStartOffset
= startOffset
;
212 *aEndOffset
= endOffset
;
214 ConvertTexttoAsterisks(accWrap
, autoStr
);
215 NS_ConvertUTF16toUTF8
cautoStr(autoStr
);
216 return (cautoStr
.get()) ? g_strdup(cautoStr
.get()) : nullptr;
220 getCaretOffsetCB(AtkText
*aText
)
222 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
226 HyperTextAccessible
* text
= accWrap
->AsHyperText();
227 if (!text
|| !text
->IsTextRole())
230 return static_cast<gint
>(text
->CaretOffset());
233 static AtkAttributeSet
*
234 getRunAttributesCB(AtkText
*aText
, gint aOffset
,
241 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
245 HyperTextAccessible
* text
= accWrap
->AsHyperText();
246 if (!text
|| !text
->IsTextRole())
249 int32_t startOffset
= 0, endOffset
= 0;
250 nsCOMPtr
<nsIPersistentProperties
> attributes
=
251 text
->TextAttributes(false, aOffset
, &startOffset
, &endOffset
);
253 *aStartOffset
= startOffset
;
254 *aEndOffset
= endOffset
;
256 return ConvertToAtkTextAttributeSet(attributes
);
259 static AtkAttributeSet
*
260 getDefaultAttributesCB(AtkText
*aText
)
262 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
266 HyperTextAccessible
* text
= accWrap
->AsHyperText();
267 if (!text
|| !text
->IsTextRole())
270 nsCOMPtr
<nsIPersistentProperties
> attributes
= text
->DefaultTextAttributes();
271 return ConvertToAtkTextAttributeSet(attributes
);
275 getCharacterExtentsCB(AtkText
*aText
, gint aOffset
,
277 gint
*aWidth
, gint
*aHeight
,
278 AtkCoordType aCoords
)
280 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
281 if(!accWrap
|| !aX
|| !aY
|| !aWidth
|| !aHeight
)
284 HyperTextAccessible
* text
= accWrap
->AsHyperText();
285 if (!text
|| !text
->IsTextRole())
288 uint32_t geckoCoordType
;
289 if (aCoords
== ATK_XY_SCREEN
)
290 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
;
292 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
;
294 nsIntRect rect
= text
->CharBounds(aOffset
, geckoCoordType
);
297 *aWidth
= rect
.width
;
298 *aHeight
= rect
.height
;
302 getRangeExtentsCB(AtkText
*aText
, gint aStartOffset
, gint aEndOffset
,
303 AtkCoordType aCoords
, AtkTextRectangle
*aRect
)
305 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
306 if(!accWrap
|| !aRect
)
309 HyperTextAccessible
* text
= accWrap
->AsHyperText();
310 if (!text
|| !text
->IsTextRole())
313 uint32_t geckoCoordType
;
314 if (aCoords
== ATK_XY_SCREEN
)
315 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
;
317 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
;
319 nsIntRect rect
= text
->TextBounds(aStartOffset
, aEndOffset
, geckoCoordType
);
322 aRect
->width
= rect
.width
;
323 aRect
->height
= rect
.height
;
327 getCharacterCountCB(AtkText
*aText
)
329 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
333 HyperTextAccessible
* textAcc
= accWrap
->AsHyperText();
334 return textAcc
->IsDefunct() ?
335 0 : static_cast<gint
>(textAcc
->CharacterCount());
339 getOffsetAtPointCB(AtkText
*aText
,
341 AtkCoordType aCoords
)
343 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
347 HyperTextAccessible
* text
= accWrap
->AsHyperText();
348 if (!text
|| !text
->IsTextRole())
351 return static_cast<gint
>(
352 text
->OffsetAtPoint(aX
, aY
,
353 (aCoords
== ATK_XY_SCREEN
?
354 nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
:
355 nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
)));
359 getTextSelectionCountCB(AtkText
*aText
)
361 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
365 HyperTextAccessible
* text
= accWrap
->AsHyperText();
366 if (!text
|| !text
->IsTextRole())
369 return text
->SelectionCount();
373 getTextSelectionCB(AtkText
*aText
, gint aSelectionNum
,
374 gint
*aStartOffset
, gint
*aEndOffset
)
376 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
380 HyperTextAccessible
* text
= accWrap
->AsHyperText();
381 if (!text
|| !text
->IsTextRole())
384 int32_t startOffset
= 0, endOffset
= 0;
385 text
->SelectionBoundsAt(aSelectionNum
, &startOffset
, &endOffset
);
387 *aStartOffset
= startOffset
;
388 *aEndOffset
= endOffset
;
390 return getTextCB(aText
, *aStartOffset
, *aEndOffset
);
395 addTextSelectionCB(AtkText
*aText
,
399 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
403 HyperTextAccessible
* text
= accWrap
->AsHyperText();
404 if (!text
|| !text
->IsTextRole())
407 return text
->AddToSelection(aStartOffset
, aEndOffset
);
411 removeTextSelectionCB(AtkText
*aText
,
414 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
418 HyperTextAccessible
* text
= accWrap
->AsHyperText();
419 if (!text
|| !text
->IsTextRole())
422 return text
->RemoveFromSelection(aSelectionNum
);
426 setTextSelectionCB(AtkText
*aText
, gint aSelectionNum
,
427 gint aStartOffset
, gint aEndOffset
)
429 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
433 HyperTextAccessible
* text
= accWrap
->AsHyperText();
434 if (!text
|| !text
->IsTextRole())
437 return text
->SetSelectionBoundsAt(aSelectionNum
, aStartOffset
, aEndOffset
);
441 setCaretOffsetCB(AtkText
*aText
, gint aOffset
)
443 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
447 HyperTextAccessible
* text
= accWrap
->AsHyperText();
448 if (!text
|| !text
->IsTextRole() || !text
->IsValidOffset(aOffset
))
451 text
->SetCaretOffset(aOffset
);
457 textInterfaceInitCB(AtkTextIface
* aIface
)
459 NS_ASSERTION(aIface
, "Invalid aIface");
460 if (MOZ_UNLIKELY(!aIface
))
463 aIface
->get_text
= getTextCB
;
464 aIface
->get_text_after_offset
= getTextAfterOffsetCB
;
465 aIface
->get_text_at_offset
= getTextAtOffsetCB
;
466 aIface
->get_character_at_offset
= getCharacterAtOffsetCB
;
467 aIface
->get_text_before_offset
= getTextBeforeOffsetCB
;
468 aIface
->get_caret_offset
= getCaretOffsetCB
;
469 aIface
->get_run_attributes
= getRunAttributesCB
;
470 aIface
->get_default_attributes
= getDefaultAttributesCB
;
471 aIface
->get_character_extents
= getCharacterExtentsCB
;
472 aIface
->get_range_extents
= getRangeExtentsCB
;
473 aIface
->get_character_count
= getCharacterCountCB
;
474 aIface
->get_offset_at_point
= getOffsetAtPointCB
;
475 aIface
->get_n_selections
= getTextSelectionCountCB
;
476 aIface
->get_selection
= getTextSelectionCB
;
479 aIface
->add_selection
= addTextSelectionCB
;
480 aIface
->remove_selection
= removeTextSelectionCB
;
481 aIface
->set_selection
= setTextSelectionCB
;
482 aIface
->set_caret_offset
= setCaretOffsetCB
;
484 // Cache the string values of the atk text attribute names.
485 for (uint32_t i
= 0; i
< ArrayLength(sAtkTextAttrNames
); i
++)
486 sAtkTextAttrNames
[i
] =
487 atk_text_attribute_get_name(static_cast<AtkTextAttribute
>(i
));