Bumping manifests a=b2g-bump
[gecko.git] / accessible / atk / nsMaiInterfaceText.cpp
bloba8922d49e707b4364a54027d6d8e13b72c1d6836
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"
11 #include "nsMai.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)
27 if (!aAttributes)
28 return nullptr;
30 AtkAttributeSet* objAttributeSet = nullptr;
31 nsCOMPtr<nsISimpleEnumerator> propEnum;
32 nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
33 NS_ENSURE_SUCCESS(rv, nullptr);
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);
41 nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
42 NS_ENSURE_TRUE(propElem, objAttributeSet);
44 nsAutoCString name;
45 rv = propElem->GetKey(name);
46 NS_ENSURE_SUCCESS(rv, objAttributeSet);
48 nsAutoString value;
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
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.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")) {
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];
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);
93 // libatk-adaptor will free it
94 return objAttributeSet;
97 static void
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("*"));
107 extern "C" {
109 static gchar*
110 getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
112 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
113 if (!accWrap)
114 return nullptr;
116 HyperTextAccessible* text = accWrap->AsHyperText();
117 if (!text || !text->IsTextRole())
118 return nullptr;
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;
130 static gchar*
131 getTextAfterOffsetCB(AtkText *aText, gint aOffset,
132 AtkTextBoundary aBoundaryType,
133 gint *aStartOffset, gint *aEndOffset)
135 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
136 if (!accWrap)
137 return nullptr;
139 HyperTextAccessible* text = accWrap->AsHyperText();
140 if (!text || !text->IsTextRole())
141 return nullptr;
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;
155 static gchar*
156 getTextAtOffsetCB(AtkText *aText, gint aOffset,
157 AtkTextBoundary aBoundaryType,
158 gint *aStartOffset, gint *aEndOffset)
160 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
161 if (!accWrap)
162 return nullptr;
164 HyperTextAccessible* text = accWrap->AsHyperText();
165 if (!text || !text->IsTextRole())
166 return nullptr;
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;
179 static gunichar
180 getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
182 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
183 if (!accWrap)
184 return 0;
186 HyperTextAccessible* text = accWrap->AsHyperText();
187 if (!text || !text->IsTextRole())
188 return 0;
190 // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
191 return static_cast<gunichar>(text->CharAt(aOffset));
194 static gchar*
195 getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
196 AtkTextBoundary aBoundaryType,
197 gint *aStartOffset, gint *aEndOffset)
199 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
200 if (!accWrap)
201 return nullptr;
203 HyperTextAccessible* text = accWrap->AsHyperText();
204 if (!text || !text->IsTextRole())
205 return nullptr;
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;
219 static gint
220 getCaretOffsetCB(AtkText *aText)
222 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
223 if (!accWrap)
224 return 0;
226 HyperTextAccessible* text = accWrap->AsHyperText();
227 if (!text || !text->IsTextRole())
228 return 0;
230 return static_cast<gint>(text->CaretOffset());
233 static AtkAttributeSet*
234 getRunAttributesCB(AtkText *aText, gint aOffset,
235 gint *aStartOffset,
236 gint *aEndOffset)
238 *aStartOffset = -1;
239 *aEndOffset = -1;
241 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
242 if (!accWrap)
243 return nullptr;
245 HyperTextAccessible* text = accWrap->AsHyperText();
246 if (!text || !text->IsTextRole())
247 return nullptr;
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));
263 if (!accWrap)
264 return nullptr;
266 HyperTextAccessible* text = accWrap->AsHyperText();
267 if (!text || !text->IsTextRole())
268 return nullptr;
270 nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes();
271 return ConvertToAtkTextAttributeSet(attributes);
274 static void
275 getCharacterExtentsCB(AtkText *aText, gint aOffset,
276 gint *aX, gint *aY,
277 gint *aWidth, gint *aHeight,
278 AtkCoordType aCoords)
280 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
281 if(!accWrap || !aX || !aY || !aWidth || !aHeight)
282 return;
284 HyperTextAccessible* text = accWrap->AsHyperText();
285 if (!text || !text->IsTextRole())
286 return;
288 uint32_t geckoCoordType;
289 if (aCoords == ATK_XY_SCREEN)
290 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
291 else
292 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
294 nsIntRect rect = text->CharBounds(aOffset, geckoCoordType);
295 *aX = rect.x;
296 *aY = rect.y;
297 *aWidth = rect.width;
298 *aHeight = rect.height;
301 static void
302 getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
303 AtkCoordType aCoords, AtkTextRectangle *aRect)
305 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
306 if(!accWrap || !aRect)
307 return;
309 HyperTextAccessible* text = accWrap->AsHyperText();
310 if (!text || !text->IsTextRole())
311 return;
313 uint32_t geckoCoordType;
314 if (aCoords == ATK_XY_SCREEN)
315 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
316 else
317 geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
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;
326 static gint
327 getCharacterCountCB(AtkText *aText)
329 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
330 if (!accWrap)
331 return 0;
333 HyperTextAccessible* textAcc = accWrap->AsHyperText();
334 return textAcc->IsDefunct() ?
335 0 : static_cast<gint>(textAcc->CharacterCount());
338 static gint
339 getOffsetAtPointCB(AtkText *aText,
340 gint aX, gint aY,
341 AtkCoordType aCoords)
343 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
344 if (!accWrap)
345 return -1;
347 HyperTextAccessible* text = accWrap->AsHyperText();
348 if (!text || !text->IsTextRole())
349 return -1;
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)));
358 static gint
359 getTextSelectionCountCB(AtkText *aText)
361 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
362 if (!accWrap)
363 return 0;
365 HyperTextAccessible* text = accWrap->AsHyperText();
366 if (!text || !text->IsTextRole())
367 return 0;
369 return text->SelectionCount();
372 static gchar*
373 getTextSelectionCB(AtkText *aText, gint aSelectionNum,
374 gint *aStartOffset, gint *aEndOffset)
376 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
377 if (!accWrap)
378 return nullptr;
380 HyperTextAccessible* text = accWrap->AsHyperText();
381 if (!text || !text->IsTextRole())
382 return nullptr;
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);
393 // set methods
394 static gboolean
395 addTextSelectionCB(AtkText *aText,
396 gint aStartOffset,
397 gint aEndOffset)
399 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
400 if (!accWrap)
401 return FALSE;
403 HyperTextAccessible* text = accWrap->AsHyperText();
404 if (!text || !text->IsTextRole())
405 return FALSE;
407 return text->AddToSelection(aStartOffset, aEndOffset);
410 static gboolean
411 removeTextSelectionCB(AtkText *aText,
412 gint aSelectionNum)
414 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
415 if (!accWrap)
416 return FALSE;
418 HyperTextAccessible* text = accWrap->AsHyperText();
419 if (!text || !text->IsTextRole())
420 return FALSE;
422 return text->RemoveFromSelection(aSelectionNum);
425 static gboolean
426 setTextSelectionCB(AtkText *aText, gint aSelectionNum,
427 gint aStartOffset, gint aEndOffset)
429 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
430 if (!accWrap)
431 return FALSE;
433 HyperTextAccessible* text = accWrap->AsHyperText();
434 if (!text || !text->IsTextRole())
435 return FALSE;
437 return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
440 static gboolean
441 setCaretOffsetCB(AtkText *aText, gint aOffset)
443 AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
444 if (!accWrap)
445 return FALSE;
447 HyperTextAccessible* text = accWrap->AsHyperText();
448 if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset))
449 return FALSE;
451 text->SetCaretOffset(aOffset);
452 return TRUE;
456 void
457 textInterfaceInitCB(AtkTextIface* aIface)
459 NS_ASSERTION(aIface, "Invalid aIface");
460 if (MOZ_UNLIKELY(!aIface))
461 return;
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;
478 // set methods
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));