accessible/src/atk/nsMaiInterfaceText.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:66a02a096c84
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/. */
6
7 #include "InterfaceInitFuncs.h"
8
9 #include "Accessible-inl.h"
10 #include "HyperTextAccessible-inl.h"
11 #include "nsMai.h"
12
13 #include "nsIAccessibleTypes.h"
14 #include "nsIPersistentProperties2.h"
15 #include "nsISimpleEnumerator.h"
16
17 #include "mozilla/Likely.h"
18
19 using namespace mozilla;
20 using namespace mozilla::a11y;
21
22 static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED];
23
24 static AtkAttributeSet*
25 ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes)
26 {
27 if (!aAttributes)
28 return nullptr;
29
30 AtkAttributeSet* objAttributeSet = nullptr;
31 nsCOMPtr<nsISimpleEnumerator> propEnum;
32 nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
33 NS_ENSURE_SUCCESS(rv, nullptr);
34
35 bool hasMore = false;
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);
40
41 nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
42 NS_ENSURE_TRUE(propElem, objAttributeSet);
43
44 nsAutoCString name;
45 rv = propElem->GetKey(name);
46 NS_ENSURE_SUCCESS(rv, objAttributeSet);
47
48 nsAutoString value;
49 rv = propElem->GetValue(value);
50 NS_ENSURE_SUCCESS(rv, objAttributeSet);
51
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);
56
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
62 // rgb(r,g,b).
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
67 // rgb(r,g,b).
68 atkValue = Substring(value, 5, value.Length() - 1);
69 atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR];
70 } else if (name.EqualsLiteral("font-family")) {
71 atkValue = value;
72 atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME];
73 } else if (name.Equals("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")) {
78 atkValue = value;
79 atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT];
80 } else if (name.EqualsLiteral("invalid")) {
81 atkValue = value;
82 atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID];
83 }
84
85 if (atkName) {
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);
90 }
91 }
92
93 // libatk-adaptor will free it
94 return objAttributeSet;
95 }
96
97 static void
98 ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
99 {
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("*"));
104 }
105 }
106
107 extern "C" {
108
109 static gchar*
110 getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
111 {
112 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
113 if (!accWrap)
114 return nullptr;
115
116 HyperTextAccessible* text = accWrap->AsHyperText();
117 if (!text || !text->IsTextRole())
118 return nullptr;
119
120 nsAutoString autoStr;
121 text->TextSubstring(aStartOffset, aEndOffset, autoStr);
122
123 ConvertTexttoAsterisks(accWrap, autoStr);
124 NS_ConvertUTF16toUTF8 cautoStr(autoStr);
125
126 //copy and return, libspi will free it.
127 return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
128 }
129
130 static gchar*
131 getTextAfterOffsetCB(AtkText *aText, gint aOffset,
132 AtkTextBoundary aBoundaryType,
133 gint *aStartOffset, gint *aEndOffset)
134 {
135 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
136 if (!accWrap)
137 return nullptr;
138
139 HyperTextAccessible* text = accWrap->AsHyperText();
140 if (!text || !text->IsTextRole())
141 return nullptr;
142
143 nsAutoString autoStr;
144 int32_t startOffset = 0, endOffset = 0;
145 text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
146
147 *aStartOffset = startOffset;
148 *aEndOffset = endOffset;
149
150 ConvertTexttoAsterisks(accWrap, autoStr);
151 NS_ConvertUTF16toUTF8 cautoStr(autoStr);
152 return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
153 }
154
155 static gchar*
156 getTextAtOffsetCB(AtkText *aText, gint aOffset,
157 AtkTextBoundary aBoundaryType,
158 gint *aStartOffset, gint *aEndOffset)
159 {
160 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
161 if (!accWrap)
162 return nullptr;
163
164 HyperTextAccessible* text = accWrap->AsHyperText();
165 if (!text || !text->IsTextRole())
166 return nullptr;
167
168 nsAutoString autoStr;
169 int32_t startOffset = 0, endOffset = 0;
170 text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
171 *aStartOffset = startOffset;
172 *aEndOffset = endOffset;
173
174 ConvertTexttoAsterisks(accWrap, autoStr);
175 NS_ConvertUTF16toUTF8 cautoStr(autoStr);
176 return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
177 }
178
179 static gunichar
180 getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
181 {
182 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
183 if (!accWrap)
184 return 0;
185
186 HyperTextAccessible* text = accWrap->AsHyperText();
187 if (!text || !text->IsTextRole())
188 return 0;
189
190 // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
191 return static_cast<gunichar>(text->CharAt(aOffset));
192 }
193
194 static gchar*
195 getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
196 AtkTextBoundary aBoundaryType,
197 gint *aStartOffset, gint *aEndOffset)
198 {
199 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
200 if (!accWrap)
201 return nullptr;
202
203 HyperTextAccessible* text = accWrap->AsHyperText();
204 if (!text || !text->IsTextRole())
205 return nullptr;
206
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;
213
214 ConvertTexttoAsterisks(accWrap, autoStr);
215 NS_ConvertUTF16toUTF8 cautoStr(autoStr);
216 return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
217 }
218
219 static gint
220 getCaretOffsetCB(AtkText *aText)
221 {
222 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
223 if (!accWrap)
224 return 0;
225
226 HyperTextAccessible* text = accWrap->AsHyperText();
227 if (!text || !text->IsTextRole())
228 return 0;
229
230 return static_cast<gint>(text->CaretOffset());
231 }
232
233 static AtkAttributeSet*
234 getRunAttributesCB(AtkText *aText, gint aOffset,
235 gint *aStartOffset,
236 gint *aEndOffset)
237 {
238 *aStartOffset = -1;
239 *aEndOffset = -1;
240
241 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
242 if (!accWrap)
243 return nullptr;
244
245 HyperTextAccessible* text = accWrap->AsHyperText();
246 if (!text || !text->IsTextRole())
247 return nullptr;
248
249 int32_t startOffset = 0, endOffset = 0;
250 nsCOMPtr<nsIPersistentProperties> attributes =
251 text->TextAttributes(false, aOffset, &startOffset, &endOffset);
252
253 *aStartOffset = startOffset;
254 *aEndOffset = endOffset;
255
256 return ConvertToAtkTextAttributeSet(attributes);
257 }
258
259 static AtkAttributeSet*
260 getDefaultAttributesCB(AtkText *aText)
261 {
262 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
263 if (!accWrap)
264 return nullptr;
265
266 HyperTextAccessible* text = accWrap->AsHyperText();
267 if (!text || !text->IsTextRole())
268 return nullptr;
269
270 nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes();
271 return ConvertToAtkTextAttributeSet(attributes);
272 }
273
274 static void
275 getCharacterExtentsCB(AtkText *aText, gint aOffset,
276 gint *aX, gint *aY,
277 gint *aWidth, gint *aHeight,
278 AtkCoordType aCoords)
279 {
280 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
281 if(!accWrap || !aX || !aY || !aWidth || !aHeight)
282 return;
283
284 HyperTextAccessible* text = accWrap->AsHyperText();
285 if (!text || !text->IsTextRole())
286 return;
287
288 uint32_t geckoCoordType;
289 if (aCoords == ATK_XY_SCREEN)
290 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
291 else
292 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
293
294 nsIntRect rect = text->CharBounds(aOffset, geckoCoordType);
295 *aX = rect.x;
296 *aY = rect.y;
297 *aWidth = rect.width;
298 *aHeight = rect.height;
299 }
300
301 static void
302 getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
303 AtkCoordType aCoords, AtkTextRectangle *aRect)
304 {
305 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
306 if(!accWrap || !aRect)
307 return;
308
309 HyperTextAccessible* text = accWrap->AsHyperText();
310 if (!text || !text->IsTextRole())
311 return;
312
313 uint32_t geckoCoordType;
314 if (aCoords == ATK_XY_SCREEN)
315 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
316 else
317 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
318
319 nsIntRect rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
320 aRect->x = rect.x;
321 aRect->y = rect.y;
322 aRect->width = rect.width;
323 aRect->height = rect.height;
324 }
325
326 static gint
327 getCharacterCountCB(AtkText *aText)
328 {
329 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
330 if (!accWrap)
331 return 0;
332
333 HyperTextAccessible* textAcc = accWrap->AsHyperText();
334 return textAcc->IsDefunct() ?
335 0 : static_cast<gint>(textAcc->CharacterCount());
336 }
337
338 static gint
339 getOffsetAtPointCB(AtkText *aText,
340 gint aX, gint aY,
341 AtkCoordType aCoords)
342 {
343 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
344 if (!accWrap)
345 return -1;
346
347 HyperTextAccessible* text = accWrap->AsHyperText();
348 if (!text || !text->IsTextRole())
349 return -1;
350
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)));
356 }
357
358 static gint
359 getTextSelectionCountCB(AtkText *aText)
360 {
361 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
362 if (!accWrap)
363 return 0;
364
365 HyperTextAccessible* text = accWrap->AsHyperText();
366 if (!text || !text->IsTextRole())
367 return 0;
368
369 return text->SelectionCount();
370 }
371
372 static gchar*
373 getTextSelectionCB(AtkText *aText, gint aSelectionNum,
374 gint *aStartOffset, gint *aEndOffset)
375 {
376 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
377 if (!accWrap)
378 return nullptr;
379
380 HyperTextAccessible* text = accWrap->AsHyperText();
381 if (!text || !text->IsTextRole())
382 return nullptr;
383
384 int32_t startOffset = 0, endOffset = 0;
385 text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
386
387 *aStartOffset = startOffset;
388 *aEndOffset = endOffset;
389
390 return getTextCB(aText, *aStartOffset, *aEndOffset);
391 }
392
393 // set methods
394 static gboolean
395 addTextSelectionCB(AtkText *aText,
396 gint aStartOffset,
397 gint aEndOffset)
398 {
399 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
400 if (!accWrap)
401 return FALSE;
402
403 HyperTextAccessible* text = accWrap->AsHyperText();
404 if (!text || !text->IsTextRole())
405 return FALSE;
406
407 return text->AddToSelection(aStartOffset, aEndOffset);
408 }
409
410 static gboolean
411 removeTextSelectionCB(AtkText *aText,
412 gint aSelectionNum)
413 {
414 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
415 if (!accWrap)
416 return FALSE;
417
418 HyperTextAccessible* text = accWrap->AsHyperText();
419 if (!text || !text->IsTextRole())
420 return FALSE;
421
422 return text->RemoveFromSelection(aSelectionNum);
423 }
424
425 static gboolean
426 setTextSelectionCB(AtkText *aText, gint aSelectionNum,
427 gint aStartOffset, gint aEndOffset)
428 {
429 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
430 if (!accWrap)
431 return FALSE;
432
433 HyperTextAccessible* text = accWrap->AsHyperText();
434 if (!text || !text->IsTextRole())
435 return FALSE;
436
437 return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
438 }
439
440 static gboolean
441 setCaretOffsetCB(AtkText *aText, gint aOffset)
442 {
443 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
444 if (!accWrap)
445 return FALSE;
446
447 HyperTextAccessible* text = accWrap->AsHyperText();
448 if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset))
449 return FALSE;
450
451 text->SetCaretOffset(aOffset);
452 return TRUE;
453 }
454 }
455
456 void
457 textInterfaceInitCB(AtkTextIface* aIface)
458 {
459 NS_ASSERTION(aIface, "Invalid aIface");
460 if (MOZ_UNLIKELY(!aIface))
461 return;
462
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;
477
478 // set methods
479 aIface->add_selection = addTextSelectionCB;
480 aIface->remove_selection = removeTextSelectionCB;
481 aIface->set_selection = setTextSelectionCB;
482 aIface->set_caret_offset = setCaretOffsetCB;
483
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));
488 }

mercurial