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"
8 #include "mozilla/a11y/PDocAccessible.h"
9 #include "LocalAccessible-inl.h"
10 #include "HyperTextAccessible-inl.h"
12 #include "RemoteAccessible.h"
14 #include "nsIAccessibleTypes.h"
15 #include "nsIPersistentProperties2.h"
16 #include "nsISimpleEnumerator.h"
17 #include "nsUTF8Utils.h"
19 #include "mozilla/Likely.h"
23 using namespace mozilla
;
24 using namespace mozilla::a11y
;
26 static const char* sAtkTextAttrNames
[ATK_TEXT_ATTR_LAST_DEFINED
];
28 void ConvertTextAttributeToAtkAttribute(const nsACString
& aName
,
29 const nsAString
& aValue
,
30 AtkAttributeSet
** aAttributeSet
) {
31 // Handle attributes where atk has its own name.
32 const char* atkName
= nullptr;
33 nsAutoString atkValue
;
34 if (aName
.EqualsLiteral("color")) {
35 // The format of the atk attribute is r,g,b and the gecko one is
37 atkValue
= Substring(aValue
, 4, aValue
.Length() - 5);
38 atkValue
.StripWhitespace();
39 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_FG_COLOR
];
40 } else if (aName
.EqualsLiteral("background-color")) {
41 // The format of the atk attribute is r,g,b and the gecko one is
43 atkValue
= Substring(aValue
, 4, aValue
.Length() - 5);
44 atkValue
.StripWhitespace();
45 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_BG_COLOR
];
46 } else if (aName
.EqualsLiteral("font-family")) {
48 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_FAMILY_NAME
];
49 } else if (aName
.EqualsLiteral("font-size")) {
50 // ATK wants the number of pixels without px at the end.
51 atkValue
= StringHead(aValue
, aValue
.Length() - 2);
52 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_SIZE
];
53 } else if (aName
.EqualsLiteral("font-weight")) {
55 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_WEIGHT
];
56 } else if (aName
.EqualsLiteral("invalid")) {
58 atkName
= sAtkTextAttrNames
[ATK_TEXT_ATTR_INVALID
];
62 AtkAttribute
* objAttr
=
63 static_cast<AtkAttribute
*>(g_malloc(sizeof(AtkAttribute
)));
64 objAttr
->name
= g_strdup(atkName
);
65 objAttr
->value
= g_strdup(NS_ConvertUTF16toUTF8(atkValue
).get());
66 *aAttributeSet
= g_slist_prepend(*aAttributeSet
, objAttr
);
70 static AtkAttributeSet
* ConvertToAtkTextAttributeSet(
71 nsTArray
<Attribute
>& aAttributes
) {
72 AtkAttributeSet
* objAttributeSet
= nullptr;
73 for (size_t i
= 0; i
< aAttributes
.Length(); ++i
) {
74 AtkAttribute
* objAttr
= (AtkAttribute
*)g_malloc(sizeof(AtkAttribute
));
75 objAttr
->name
= g_strdup(aAttributes
[i
].Name().get());
77 g_strdup(NS_ConvertUTF16toUTF8(aAttributes
[i
].Value()).get());
78 objAttributeSet
= g_slist_prepend(objAttributeSet
, objAttr
);
79 ConvertTextAttributeToAtkAttribute(
80 aAttributes
[i
].Name(), aAttributes
[i
].Value(), &objAttributeSet
);
82 return objAttributeSet
;
85 static AtkAttributeSet
* ConvertToAtkTextAttributeSet(
86 nsIPersistentProperties
* aAttributes
) {
87 if (!aAttributes
) return nullptr;
89 AtkAttributeSet
* objAttributeSet
= nullptr;
90 nsCOMPtr
<nsISimpleEnumerator
> propEnum
;
91 nsresult rv
= aAttributes
->Enumerate(getter_AddRefs(propEnum
));
92 NS_ENSURE_SUCCESS(rv
, nullptr);
95 while (NS_SUCCEEDED(propEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
96 nsCOMPtr
<nsISupports
> sup
;
97 rv
= propEnum
->GetNext(getter_AddRefs(sup
));
98 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
100 nsCOMPtr
<nsIPropertyElement
> propElem(do_QueryInterface(sup
));
101 NS_ENSURE_TRUE(propElem
, objAttributeSet
);
104 rv
= propElem
->GetKey(name
);
105 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
108 rv
= propElem
->GetValue(value
);
109 NS_ENSURE_SUCCESS(rv
, objAttributeSet
);
111 AtkAttribute
* objAttr
= (AtkAttribute
*)g_malloc(sizeof(AtkAttribute
));
112 objAttr
->name
= g_strdup(name
.get());
113 objAttr
->value
= g_strdup(NS_ConvertUTF16toUTF8(value
).get());
114 objAttributeSet
= g_slist_prepend(objAttributeSet
, objAttr
);
116 ConvertTextAttributeToAtkAttribute(name
, value
, &objAttributeSet
);
119 // libatk-adaptor will free it
120 return objAttributeSet
;
123 static void ConvertTexttoAsterisks(AccessibleWrap
* accWrap
,
124 nsAString
& aString
) {
125 // convert each char to "*" when it's "password text"
126 if (accWrap
->IsPassword()) {
127 DOMtoATK::ConvertTexttoAsterisks(aString
);
133 static gchar
* getTextCB(AtkText
* aText
, gint aStartOffset
, gint aEndOffset
) {
134 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
135 nsAutoString autoStr
;
137 HyperTextAccessible
* text
= accWrap
->AsHyperText();
138 if (!text
|| !text
->IsTextRole() || text
->IsDefunct()) return nullptr;
140 return DOMtoATK::NewATKString(
141 text
, aStartOffset
, aEndOffset
,
142 accWrap
->IsPassword()
143 ? DOMtoATK::AtkStringConvertFlags::ConvertTextToAsterisks
144 : DOMtoATK::AtkStringConvertFlags::None
);
146 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
147 return DOMtoATK::NewATKString(proxy
, aStartOffset
, aEndOffset
,
148 DOMtoATK::AtkStringConvertFlags::None
);
154 static gint
getCharacterCountCB(AtkText
* aText
);
156 // Note: this does not support magic offsets, which is fine for its callers
157 // which do not implement any.
158 static gchar
* getCharTextAtOffset(AtkText
* aText
, gint aOffset
,
159 gint
* aStartOffset
, gint
* aEndOffset
) {
160 gint end
= aOffset
+ 1;
161 gint count
= getCharacterCountCB(aText
);
163 if (aOffset
> count
) {
175 *aStartOffset
= aOffset
;
178 return getTextCB(aText
, aOffset
, end
);
181 static gchar
* getTextAfterOffsetCB(AtkText
* aText
, gint aOffset
,
182 AtkTextBoundary aBoundaryType
,
183 gint
* aStartOffset
, gint
* aEndOffset
) {
184 if (aBoundaryType
== ATK_TEXT_BOUNDARY_CHAR
) {
185 return getCharTextAtOffset(aText
, aOffset
+ 1, aStartOffset
, aEndOffset
);
188 nsAutoString autoStr
;
189 int32_t startOffset
= 0, endOffset
= 0;
190 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
192 HyperTextAccessible
* text
= accWrap
->AsHyperText();
193 if (!text
|| !text
->IsTextRole()) return nullptr;
195 text
->TextAfterOffset(aOffset
, aBoundaryType
, &startOffset
, &endOffset
,
197 ConvertTexttoAsterisks(accWrap
, autoStr
);
198 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
199 proxy
->GetTextAfterOffset(aOffset
, aBoundaryType
, autoStr
, &startOffset
,
203 *aStartOffset
= startOffset
;
204 *aEndOffset
= endOffset
;
206 // libspi will free it.
207 return DOMtoATK::Convert(autoStr
);
210 static gchar
* getTextAtOffsetCB(AtkText
* aText
, gint aOffset
,
211 AtkTextBoundary aBoundaryType
,
212 gint
* aStartOffset
, gint
* aEndOffset
) {
213 if (aBoundaryType
== ATK_TEXT_BOUNDARY_CHAR
) {
214 return getCharTextAtOffset(aText
, aOffset
, aStartOffset
, aEndOffset
);
217 nsAutoString autoStr
;
218 int32_t startOffset
= 0, endOffset
= 0;
219 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
221 HyperTextAccessible
* text
= accWrap
->AsHyperText();
222 if (!text
|| !text
->IsTextRole()) return nullptr;
224 text
->TextAtOffset(aOffset
, aBoundaryType
, &startOffset
, &endOffset
,
226 ConvertTexttoAsterisks(accWrap
, autoStr
);
227 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
228 proxy
->GetTextAtOffset(aOffset
, aBoundaryType
, autoStr
, &startOffset
,
232 *aStartOffset
= startOffset
;
233 *aEndOffset
= endOffset
;
235 // libspi will free it.
236 return DOMtoATK::Convert(autoStr
);
239 static gunichar
getCharacterAtOffsetCB(AtkText
* aText
, gint aOffset
) {
240 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
242 HyperTextAccessible
* text
= accWrap
->AsHyperText();
243 if (!text
|| !text
->IsTextRole()) {
246 return DOMtoATK::ATKCharacter(text
, aOffset
);
249 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
250 return DOMtoATK::ATKCharacter(proxy
, aOffset
);
256 static gchar
* getTextBeforeOffsetCB(AtkText
* aText
, gint aOffset
,
257 AtkTextBoundary aBoundaryType
,
258 gint
* aStartOffset
, gint
* aEndOffset
) {
259 if (aBoundaryType
== ATK_TEXT_BOUNDARY_CHAR
) {
260 return getCharTextAtOffset(aText
, aOffset
- 1, aStartOffset
, aEndOffset
);
263 nsAutoString autoStr
;
264 int32_t startOffset
= 0, endOffset
= 0;
265 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
267 HyperTextAccessible
* text
= accWrap
->AsHyperText();
268 if (!text
|| !text
->IsTextRole()) return nullptr;
270 text
->TextBeforeOffset(aOffset
, aBoundaryType
, &startOffset
, &endOffset
,
272 ConvertTexttoAsterisks(accWrap
, autoStr
);
273 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
274 proxy
->GetTextBeforeOffset(aOffset
, aBoundaryType
, autoStr
, &startOffset
,
278 *aStartOffset
= startOffset
;
279 *aEndOffset
= endOffset
;
281 // libspi will free it.
282 return DOMtoATK::Convert(autoStr
);
285 static gint
getCaretOffsetCB(AtkText
* aText
) {
286 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
288 HyperTextAccessible
* text
= accWrap
->AsHyperText();
289 if (!text
|| !text
->IsTextRole()) {
293 return static_cast<gint
>(text
->CaretOffset());
296 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
297 return static_cast<gint
>(proxy
->CaretOffset());
303 static AtkAttributeSet
* getRunAttributesCB(AtkText
* aText
, gint aOffset
,
308 int32_t startOffset
= 0, endOffset
= 0;
310 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
312 HyperTextAccessible
* text
= accWrap
->AsHyperText();
313 if (!text
|| !text
->IsTextRole()) {
317 nsCOMPtr
<nsIPersistentProperties
> attributes
=
318 text
->TextAttributes(false, aOffset
, &startOffset
, &endOffset
);
320 *aStartOffset
= startOffset
;
321 *aEndOffset
= endOffset
;
323 return ConvertToAtkTextAttributeSet(attributes
);
326 RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
));
331 AutoTArray
<Attribute
, 10> attrs
;
332 proxy
->TextAttributes(false, aOffset
, &attrs
, &startOffset
, &endOffset
);
333 *aStartOffset
= startOffset
;
334 *aEndOffset
= endOffset
;
335 return ConvertToAtkTextAttributeSet(attrs
);
338 static AtkAttributeSet
* getDefaultAttributesCB(AtkText
* aText
) {
339 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
341 HyperTextAccessible
* text
= accWrap
->AsHyperText();
342 if (!text
|| !text
->IsTextRole()) {
346 nsCOMPtr
<nsIPersistentProperties
> attributes
=
347 text
->DefaultTextAttributes();
348 return ConvertToAtkTextAttributeSet(attributes
);
351 RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
));
356 AutoTArray
<Attribute
, 10> attrs
;
357 proxy
->DefaultTextAttributes(&attrs
);
358 return ConvertToAtkTextAttributeSet(attrs
);
361 static void getCharacterExtentsCB(AtkText
* aText
, gint aOffset
, gint
* aX
,
362 gint
* aY
, gint
* aWidth
, gint
* aHeight
,
363 AtkCoordType aCoords
) {
364 if (!aX
|| !aY
|| !aWidth
|| !aHeight
) {
367 *aX
= *aY
= *aWidth
= *aHeight
= -1;
370 uint32_t geckoCoordType
;
371 if (aCoords
== ATK_XY_SCREEN
) {
372 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
;
374 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
;
377 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
379 HyperTextAccessible
* text
= accWrap
->AsHyperText();
380 if (!text
|| !text
->IsTextRole()) {
384 rect
= text
->CharBounds(aOffset
, geckoCoordType
);
385 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
386 rect
= proxy
->CharBounds(aOffset
, geckoCoordType
);
393 *aWidth
= rect
.width
;
394 *aHeight
= rect
.height
;
397 static void getRangeExtentsCB(AtkText
* aText
, gint aStartOffset
,
398 gint aEndOffset
, AtkCoordType aCoords
,
399 AtkTextRectangle
* aRect
) {
403 aRect
->x
= aRect
->y
= aRect
->width
= aRect
->height
= -1;
406 uint32_t geckoCoordType
;
407 if (aCoords
== ATK_XY_SCREEN
) {
408 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
;
410 geckoCoordType
= nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
;
413 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
415 HyperTextAccessible
* text
= accWrap
->AsHyperText();
416 if (!text
|| !text
->IsTextRole()) {
420 rect
= text
->TextBounds(aStartOffset
, aEndOffset
, geckoCoordType
);
421 } else if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
422 rect
= proxy
->TextBounds(aStartOffset
, aEndOffset
, geckoCoordType
);
429 aRect
->width
= rect
.width
;
430 aRect
->height
= rect
.height
;
433 static gint
getCharacterCountCB(AtkText
* aText
) {
434 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
436 HyperTextAccessible
* textAcc
= accWrap
->AsHyperText();
437 return !textAcc
|| textAcc
->IsDefunct()
439 : static_cast<gint
>(textAcc
->CharacterCount());
442 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
443 return proxy
->CharacterCount();
449 static gint
getOffsetAtPointCB(AtkText
* aText
, gint aX
, gint aY
,
450 AtkCoordType aCoords
) {
451 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
453 HyperTextAccessible
* text
= accWrap
->AsHyperText();
454 if (!text
|| !text
->IsTextRole()) {
458 return static_cast<gint
>(text
->OffsetAtPoint(
460 (aCoords
== ATK_XY_SCREEN
461 ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
462 : nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
)));
465 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
466 return static_cast<gint
>(proxy
->OffsetAtPoint(
468 (aCoords
== ATK_XY_SCREEN
469 ? nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
470 : nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE
)));
476 static gint
getTextSelectionCountCB(AtkText
* aText
) {
477 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
479 HyperTextAccessible
* text
= accWrap
->AsHyperText();
480 if (!text
|| !text
->IsTextRole()) {
484 return text
->SelectionCount();
487 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
488 return proxy
->SelectionCount();
494 static gchar
* getTextSelectionCB(AtkText
* aText
, gint aSelectionNum
,
495 gint
* aStartOffset
, gint
* aEndOffset
) {
496 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
497 int32_t startOffset
= 0, endOffset
= 0;
499 HyperTextAccessible
* text
= accWrap
->AsHyperText();
500 if (!text
|| !text
->IsTextRole()) {
504 text
->SelectionBoundsAt(aSelectionNum
, &startOffset
, &endOffset
);
505 *aStartOffset
= startOffset
;
506 *aEndOffset
= endOffset
;
508 return getTextCB(aText
, *aStartOffset
, *aEndOffset
);
510 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
512 proxy
->SelectionBoundsAt(aSelectionNum
, data
, &startOffset
, &endOffset
);
513 *aStartOffset
= startOffset
;
514 *aEndOffset
= endOffset
;
516 NS_ConvertUTF16toUTF8
dataAsUTF8(data
);
517 return (dataAsUTF8
.get()) ? g_strdup(dataAsUTF8
.get()) : nullptr;
523 static gboolean
addTextSelectionCB(AtkText
* aText
, gint aStartOffset
,
525 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
527 HyperTextAccessible
* text
= accWrap
->AsHyperText();
528 if (!text
|| !text
->IsTextRole()) {
532 return text
->AddToSelection(aStartOffset
, aEndOffset
);
534 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
535 return proxy
->AddToSelection(aStartOffset
, aEndOffset
);
541 static gboolean
removeTextSelectionCB(AtkText
* aText
, gint aSelectionNum
) {
542 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
544 HyperTextAccessible
* text
= accWrap
->AsHyperText();
545 if (!text
|| !text
->IsTextRole()) {
549 return text
->RemoveFromSelection(aSelectionNum
);
551 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
552 return proxy
->RemoveFromSelection(aSelectionNum
);
558 static gboolean
setTextSelectionCB(AtkText
* aText
, gint aSelectionNum
,
559 gint aStartOffset
, gint aEndOffset
) {
560 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
562 HyperTextAccessible
* text
= accWrap
->AsHyperText();
563 if (!text
|| !text
->IsTextRole()) {
567 return text
->SetSelectionBoundsAt(aSelectionNum
, aStartOffset
, aEndOffset
);
569 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
570 return proxy
->SetSelectionBoundsAt(aSelectionNum
, aStartOffset
, aEndOffset
);
576 static gboolean
setCaretOffsetCB(AtkText
* aText
, gint aOffset
) {
577 AccessibleWrap
* accWrap
= GetAccessibleWrap(ATK_OBJECT(aText
));
579 HyperTextAccessible
* text
= accWrap
->AsHyperText();
580 if (!text
|| !text
->IsTextRole() || !text
->IsValidOffset(aOffset
)) {
584 text
->SetCaretOffset(aOffset
);
588 if (RemoteAccessible
* proxy
= GetProxy(ATK_OBJECT(aText
))) {
589 proxy
->SetCaretOffset(aOffset
);
596 static gboolean
scrollSubstringToCB(AtkText
* aText
, gint aStartOffset
,
597 gint aEndOffset
, AtkScrollType aType
) {
598 AtkObject
* atkObject
= ATK_OBJECT(aText
);
599 AccessibleWrap
* accWrap
= GetAccessibleWrap(atkObject
);
601 HyperTextAccessible
* text
= accWrap
->AsHyperText();
602 if (!text
|| !text
->IsTextRole() ||
603 !text
->IsValidRange(aStartOffset
, aEndOffset
)) {
606 text
->ScrollSubstringTo(aStartOffset
, aEndOffset
, aType
);
610 RemoteAccessible
* proxy
= GetProxy(atkObject
);
612 proxy
->ScrollSubstringTo(aStartOffset
, aEndOffset
, aType
);
619 static gboolean
scrollSubstringToPointCB(AtkText
* aText
, gint aStartOffset
,
620 gint aEndOffset
, AtkCoordType aCoords
,
622 AtkObject
* atkObject
= ATK_OBJECT(aText
);
623 AccessibleWrap
* accWrap
= GetAccessibleWrap(atkObject
);
625 HyperTextAccessible
* text
= accWrap
->AsHyperText();
626 if (!text
|| !text
->IsTextRole() ||
627 !text
->IsValidRange(aStartOffset
, aEndOffset
)) {
630 text
->ScrollSubstringToPoint(aStartOffset
, aEndOffset
, aCoords
, aX
, aY
);
634 RemoteAccessible
* proxy
= GetProxy(atkObject
);
636 proxy
->ScrollSubstringToPoint(aStartOffset
, aEndOffset
, aCoords
, aX
, aY
);
644 void textInterfaceInitCB(AtkTextIface
* aIface
) {
645 NS_ASSERTION(aIface
, "Invalid aIface");
646 if (MOZ_UNLIKELY(!aIface
)) return;
648 aIface
->get_text
= getTextCB
;
649 aIface
->get_text_after_offset
= getTextAfterOffsetCB
;
650 aIface
->get_text_at_offset
= getTextAtOffsetCB
;
651 aIface
->get_character_at_offset
= getCharacterAtOffsetCB
;
652 aIface
->get_text_before_offset
= getTextBeforeOffsetCB
;
653 aIface
->get_caret_offset
= getCaretOffsetCB
;
654 aIface
->get_run_attributes
= getRunAttributesCB
;
655 aIface
->get_default_attributes
= getDefaultAttributesCB
;
656 aIface
->get_character_extents
= getCharacterExtentsCB
;
657 aIface
->get_range_extents
= getRangeExtentsCB
;
658 aIface
->get_character_count
= getCharacterCountCB
;
659 aIface
->get_offset_at_point
= getOffsetAtPointCB
;
660 aIface
->get_n_selections
= getTextSelectionCountCB
;
661 aIface
->get_selection
= getTextSelectionCB
;
664 aIface
->add_selection
= addTextSelectionCB
;
665 aIface
->remove_selection
= removeTextSelectionCB
;
666 aIface
->set_selection
= setTextSelectionCB
;
667 aIface
->set_caret_offset
= setCaretOffsetCB
;
669 if (IsAtkVersionAtLeast(2, 32)) {
670 aIface
->scroll_substring_to
= scrollSubstringToCB
;
671 aIface
->scroll_substring_to_point
= scrollSubstringToPointCB
;
674 // Cache the string values of the atk text attribute names.
675 for (uint32_t i
= 0; i
< ArrayLength(sAtkTextAttrNames
); i
++) {
676 sAtkTextAttrNames
[i
] =
677 atk_text_attribute_get_name(static_cast<AtkTextAttribute
>(i
));