Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/accessible/atk/nsMaiInterfaceText.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "mozilla/a11y/PDocAccessible.h"
9
#include "Accessible-inl.h"
10
#include "HyperTextAccessible-inl.h"
11
#include "nsMai.h"
12
#include "ProxyAccessible.h"
13
14
#include "nsIAccessibleTypes.h"
15
#include "nsIPersistentProperties2.h"
16
#include "nsISimpleEnumerator.h"
17
#include "nsUTF8Utils.h"
18
19
#include "mozilla/Likely.h"
20
21
#include "DOMtoATK.h"
22
23
using namespace mozilla;
24
using namespace mozilla::a11y;
25
26
static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED];
27
28
void
29
ConvertTextAttributeToAtkAttribute(const nsACString& aName,
30
                                   const nsAString& aValue,
31
                                   AtkAttributeSet** aAttributeSet)
32
0
{
33
0
  // Handle attributes where atk has its own name.
34
0
  const char* atkName = nullptr;
35
0
  nsAutoString atkValue;
36
0
  if (aName.EqualsLiteral("color")) {
37
0
    // The format of the atk attribute is r,g,b and the gecko one is
38
0
    // rgb(r, g, b).
39
0
    atkValue = Substring(aValue, 4, aValue.Length() - 5);
40
0
    atkValue.StripWhitespace();
41
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR];
42
0
  } else if (aName.EqualsLiteral("background-color")) {
43
0
    // The format of the atk attribute is r,g,b and the gecko one is
44
0
    // rgb(r, g, b).
45
0
    atkValue = Substring(aValue, 4, aValue.Length() - 5);
46
0
    atkValue.StripWhitespace();
47
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR];
48
0
  } else if (aName.EqualsLiteral("font-family")) {
49
0
    atkValue = aValue;
50
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME];
51
0
  } else if (aName.EqualsLiteral("font-size")) {
52
0
    // ATK wants the number of pixels without px at the end.
53
0
    atkValue = StringHead(aValue, aValue.Length() - 2);
54
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE];
55
0
  } else if (aName.EqualsLiteral("font-weight")) {
56
0
    atkValue = aValue;
57
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT];
58
0
  } else if (aName.EqualsLiteral("invalid")) {
59
0
    atkValue = aValue;
60
0
    atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID];
61
0
  }
62
0
63
0
  if (atkName) {
64
0
    AtkAttribute* objAttr =
65
0
      static_cast<AtkAttribute*>(g_malloc(sizeof(AtkAttribute)));
66
0
    objAttr->name = g_strdup(atkName);
67
0
    objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get());
68
0
    *aAttributeSet = g_slist_prepend(*aAttributeSet, objAttr);
69
0
  }
70
0
}
71
72
static AtkAttributeSet*
73
ConvertToAtkTextAttributeSet(nsTArray<Attribute>& aAttributes)
74
0
{
75
0
  AtkAttributeSet* objAttributeSet = nullptr;
76
0
  for (size_t i = 0; i < aAttributes.Length(); ++i) {
77
0
    AtkAttribute* objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
78
0
    objAttr->name = g_strdup(aAttributes[i].Name().get());
79
0
    objAttr->value =
80
0
      g_strdup(NS_ConvertUTF16toUTF8(aAttributes[i].Value()).get());
81
0
    objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
82
0
    ConvertTextAttributeToAtkAttribute(aAttributes[i].Name(),
83
0
                                       aAttributes[i].Value(),
84
0
                                       &objAttributeSet);
85
0
  }
86
0
  return objAttributeSet;
87
0
}
88
89
static AtkAttributeSet*
90
ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes)
91
0
{
92
0
  if (!aAttributes)
93
0
    return nullptr;
94
0
95
0
  AtkAttributeSet* objAttributeSet = nullptr;
96
0
  nsCOMPtr<nsISimpleEnumerator> propEnum;
97
0
  nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
98
0
  NS_ENSURE_SUCCESS(rv, nullptr);
99
0
100
0
  bool hasMore = false;
101
0
  while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
102
0
    nsCOMPtr<nsISupports> sup;
103
0
    rv = propEnum->GetNext(getter_AddRefs(sup));
104
0
    NS_ENSURE_SUCCESS(rv, objAttributeSet);
105
0
106
0
    nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
107
0
    NS_ENSURE_TRUE(propElem, objAttributeSet);
108
0
109
0
    nsAutoCString name;
110
0
    rv = propElem->GetKey(name);
111
0
    NS_ENSURE_SUCCESS(rv, objAttributeSet);
112
0
113
0
    nsAutoString value;
114
0
    rv = propElem->GetValue(value);
115
0
    NS_ENSURE_SUCCESS(rv, objAttributeSet);
116
0
117
0
    AtkAttribute* objAttr = (AtkAttribute*)g_malloc(sizeof(AtkAttribute));
118
0
    objAttr->name = g_strdup(name.get());
119
0
    objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
120
0
    objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
121
0
122
0
    ConvertTextAttributeToAtkAttribute(name, value, &objAttributeSet);
123
0
  }
124
0
125
0
  // libatk-adaptor will free it
126
0
  return objAttributeSet;
127
0
}
128
129
static void
130
ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
131
0
{
132
0
  // convert each char to "*" when it's "password text"
133
0
  if (accWrap->IsPassword()) {
134
0
    DOMtoATK::ConvertTexttoAsterisks(aString);
135
0
  }
136
0
}
137
138
extern "C" {
139
140
static gchar*
141
getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
142
0
{
143
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
144
0
  nsAutoString autoStr;
145
0
  if (accWrap) {
146
0
    HyperTextAccessible* text = accWrap->AsHyperText();
147
0
    if (!text || !text->IsTextRole() || text->IsDefunct())
148
0
      return nullptr;
149
0
150
0
    return DOMtoATK::NewATKString(text, aStartOffset, aEndOffset,
151
0
         accWrap->IsPassword() ?
152
0
           DOMtoATK::AtkStringConvertFlags::ConvertTextToAsterisks :
153
0
           DOMtoATK::AtkStringConvertFlags::None);
154
0
155
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
156
0
    return DOMtoATK::NewATKString(proxy, aStartOffset, aEndOffset,
157
0
         DOMtoATK::AtkStringConvertFlags::None);
158
0
  }
159
0
160
0
  return nullptr;
161
0
}
162
163
static gint getCharacterCountCB(AtkText* aText);
164
165
// Note: this does not support magic offsets, which is fine for its callers
166
// which do not implement any.
167
static gchar*
168
getCharTextAtOffset(AtkText* aText, gint aOffset,
169
                    gint* aStartOffset, gint* aEndOffset)
170
0
{
171
0
  gint end = aOffset + 1;
172
0
  gint count = getCharacterCountCB(aText);
173
0
174
0
  if (aOffset > count) {
175
0
    aOffset = count;
176
0
  }
177
0
  if (end > count) {
178
0
    end = count;
179
0
  }
180
0
  if (aOffset < 0) {
181
0
    aOffset = 0;
182
0
  }
183
0
  if (end < 0) {
184
0
    end = 0;
185
0
  }
186
0
  *aStartOffset = aOffset;
187
0
  *aEndOffset = end;
188
0
189
0
  return getTextCB(aText, aOffset, end);
190
0
}
191
192
static gchar*
193
getTextAfterOffsetCB(AtkText *aText, gint aOffset,
194
                     AtkTextBoundary aBoundaryType,
195
                     gint *aStartOffset, gint *aEndOffset)
196
0
{
197
0
  if (aBoundaryType == ATK_TEXT_BOUNDARY_CHAR) {
198
0
    return getCharTextAtOffset(aText, aOffset + 1, aStartOffset, aEndOffset);
199
0
  }
200
0
201
0
    nsAutoString autoStr;
202
0
  int32_t startOffset = 0, endOffset = 0;
203
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
204
0
  if (accWrap) {
205
0
    HyperTextAccessible* text = accWrap->AsHyperText();
206
0
    if (!text || !text->IsTextRole())
207
0
      return nullptr;
208
0
209
0
    text->TextAfterOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
210
0
    ConvertTexttoAsterisks(accWrap, autoStr);
211
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
212
0
    proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
213
0
                              &endOffset);
214
0
  }
215
0
216
0
  *aStartOffset = startOffset;
217
0
  *aEndOffset = endOffset;
218
0
219
0
  // libspi will free it.
220
0
  return DOMtoATK::Convert(autoStr);
221
0
}
222
223
static gchar*
224
getTextAtOffsetCB(AtkText *aText, gint aOffset,
225
                  AtkTextBoundary aBoundaryType,
226
                  gint *aStartOffset, gint *aEndOffset)
227
0
{
228
0
  if (aBoundaryType == ATK_TEXT_BOUNDARY_CHAR) {
229
0
    return getCharTextAtOffset(aText, aOffset, aStartOffset, aEndOffset);
230
0
  }
231
0
232
0
  nsAutoString autoStr;
233
0
  int32_t startOffset = 0, endOffset = 0;
234
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
235
0
  if (accWrap) {
236
0
    HyperTextAccessible* text = accWrap->AsHyperText();
237
0
    if (!text || !text->IsTextRole())
238
0
      return nullptr;
239
0
240
0
    text->TextAtOffset(aOffset, aBoundaryType, &startOffset, &endOffset, autoStr);
241
0
    ConvertTexttoAsterisks(accWrap, autoStr);
242
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
243
0
    proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
244
0
                           &endOffset);
245
0
  }
246
0
247
0
  *aStartOffset = startOffset;
248
0
  *aEndOffset = endOffset;
249
0
250
0
  // libspi will free it.
251
0
  return DOMtoATK::Convert(autoStr);
252
0
}
253
254
static gunichar
255
getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
256
0
{
257
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
258
0
  if (accWrap) {
259
0
    HyperTextAccessible* text = accWrap->AsHyperText();
260
0
    if (!text || !text->IsTextRole()) {
261
0
      return 0;
262
0
    }
263
0
    return DOMtoATK::ATKCharacter(text, aOffset);
264
0
  }
265
0
266
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
267
0
    return DOMtoATK::ATKCharacter(proxy, aOffset);
268
0
  }
269
0
270
0
  return 0;
271
0
}
272
273
static gchar*
274
getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
275
                      AtkTextBoundary aBoundaryType,
276
                      gint *aStartOffset, gint *aEndOffset)
277
0
{
278
0
  if (aBoundaryType == ATK_TEXT_BOUNDARY_CHAR) {
279
0
    return getCharTextAtOffset(aText, aOffset - 1, aStartOffset, aEndOffset);
280
0
  }
281
0
282
0
  nsAutoString autoStr;
283
0
  int32_t startOffset = 0, endOffset = 0;
284
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
285
0
  if (accWrap) {
286
0
    HyperTextAccessible* text = accWrap->AsHyperText();
287
0
    if (!text || !text->IsTextRole())
288
0
      return nullptr;
289
0
290
0
    text->TextBeforeOffset(aOffset, aBoundaryType,
291
0
                           &startOffset, &endOffset, autoStr);
292
0
    ConvertTexttoAsterisks(accWrap, autoStr);
293
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
294
0
    proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
295
0
                               &endOffset);
296
0
  }
297
0
298
0
  *aStartOffset = startOffset;
299
0
  *aEndOffset = endOffset;
300
0
301
0
  // libspi will free it.
302
0
  return DOMtoATK::Convert(autoStr);
303
0
}
304
305
static gint
306
getCaretOffsetCB(AtkText *aText)
307
0
{
308
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
309
0
  if (accWrap) {
310
0
    HyperTextAccessible* text = accWrap->AsHyperText();
311
0
    if (!text || !text->IsTextRole()) {
312
0
      return 0;
313
0
    }
314
0
315
0
    return static_cast<gint>(text->CaretOffset());
316
0
  }
317
0
318
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
319
0
    return static_cast<gint>(proxy->CaretOffset());
320
0
  }
321
0
322
0
  return 0;
323
0
}
324
325
static AtkAttributeSet*
326
getRunAttributesCB(AtkText *aText, gint aOffset,
327
                   gint *aStartOffset,
328
                   gint *aEndOffset)
329
0
{
330
0
  *aStartOffset = -1;
331
0
  *aEndOffset = -1;
332
0
  int32_t startOffset = 0, endOffset = 0;
333
0
334
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
335
0
  if (accWrap) {
336
0
    HyperTextAccessible* text = accWrap->AsHyperText();
337
0
    if (!text || !text->IsTextRole()) {
338
0
      return nullptr;
339
0
    }
340
0
341
0
    nsCOMPtr<nsIPersistentProperties> attributes =
342
0
      text->TextAttributes(false, aOffset, &startOffset, &endOffset);
343
0
344
0
    *aStartOffset = startOffset;
345
0
    *aEndOffset = endOffset;
346
0
347
0
    return ConvertToAtkTextAttributeSet(attributes);
348
0
  }
349
0
350
0
  ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
351
0
  if (!proxy) {
352
0
    return nullptr;
353
0
  }
354
0
355
0
  AutoTArray<Attribute, 10> attrs;
356
0
  proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset);
357
0
  *aStartOffset = startOffset;
358
0
  *aEndOffset = endOffset;
359
0
  return ConvertToAtkTextAttributeSet(attrs);
360
0
}
361
362
static AtkAttributeSet*
363
getDefaultAttributesCB(AtkText *aText)
364
0
{
365
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
366
0
  if (accWrap) {
367
0
    HyperTextAccessible* text = accWrap->AsHyperText();
368
0
    if (!text || !text->IsTextRole()) {
369
0
      return nullptr;
370
0
    }
371
0
372
0
    nsCOMPtr<nsIPersistentProperties> attributes = text->DefaultTextAttributes();
373
0
    return ConvertToAtkTextAttributeSet(attributes);
374
0
  }
375
0
376
0
  ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText));
377
0
  if (!proxy) {
378
0
    return nullptr;
379
0
  }
380
0
381
0
  AutoTArray<Attribute, 10> attrs;
382
0
  proxy->DefaultTextAttributes(&attrs);
383
0
  return ConvertToAtkTextAttributeSet(attrs);
384
0
}
385
386
static void
387
getCharacterExtentsCB(AtkText *aText, gint aOffset,
388
                      gint *aX, gint *aY,
389
                      gint *aWidth, gint *aHeight,
390
                      AtkCoordType aCoords)
391
0
{
392
0
  if(!aX || !aY || !aWidth || !aHeight) {
393
0
    return;
394
0
  }
395
0
396
0
  nsIntRect rect;
397
0
  uint32_t geckoCoordType;
398
0
  if (aCoords == ATK_XY_SCREEN) {
399
0
    geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
400
0
  } else {
401
0
    geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
402
0
  }
403
0
404
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
405
0
  if (accWrap) {
406
0
    HyperTextAccessible* text = accWrap->AsHyperText();
407
0
    if (!text || !text->IsTextRole()) {
408
0
      return;
409
0
    }
410
0
411
0
    rect = text->CharBounds(aOffset, geckoCoordType);
412
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
413
0
    rect = proxy->CharBounds(aOffset, geckoCoordType);
414
0
  } else {
415
0
    return;
416
0
  }
417
0
418
0
  *aX = rect.x;
419
0
  *aY = rect.y;
420
0
  *aWidth = rect.width;
421
0
  *aHeight = rect.height;
422
0
}
423
424
static void
425
getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset,
426
                  AtkCoordType aCoords, AtkTextRectangle *aRect)
427
0
{
428
0
  if (!aRect) {
429
0
    return;
430
0
  }
431
0
432
0
  nsIntRect rect;
433
0
  uint32_t geckoCoordType;
434
0
  if (aCoords == ATK_XY_SCREEN) {
435
0
    geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE;
436
0
  } else {
437
0
    geckoCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE;
438
0
  }
439
0
440
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
441
0
  if(accWrap) {
442
0
    HyperTextAccessible* text = accWrap->AsHyperText();
443
0
    if (!text || !text->IsTextRole()) {
444
0
      return;
445
0
    }
446
0
447
0
    rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
448
0
  } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
449
0
    rect = proxy->TextBounds(aStartOffset, aEndOffset, geckoCoordType);
450
0
  } else {
451
0
    return;
452
0
  }
453
0
454
0
  aRect->x = rect.x;
455
0
  aRect->y = rect.y;
456
0
  aRect->width = rect.width;
457
0
  aRect->height = rect.height;
458
0
}
459
460
static gint
461
getCharacterCountCB(AtkText *aText)
462
0
{
463
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
464
0
  if (accWrap) {
465
0
    HyperTextAccessible* textAcc = accWrap->AsHyperText();
466
0
    return !textAcc || textAcc->IsDefunct() ?
467
0
        0 : static_cast<gint>(textAcc->CharacterCount());
468
0
  }
469
0
470
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
471
0
    return proxy->CharacterCount();
472
0
  }
473
0
474
0
  return 0;
475
0
}
476
477
static gint
478
getOffsetAtPointCB(AtkText *aText,
479
                   gint aX, gint aY,
480
                   AtkCoordType aCoords)
481
0
{
482
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
483
0
  if (accWrap) {
484
0
    HyperTextAccessible* text = accWrap->AsHyperText();
485
0
    if (!text || !text->IsTextRole()) {
486
0
      return -1;
487
0
    }
488
0
489
0
    return static_cast<gint>(
490
0
      text->OffsetAtPoint(aX, aY,
491
0
                          (aCoords == ATK_XY_SCREEN ?
492
0
                           nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
493
0
                           nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
494
0
  }
495
0
496
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
497
0
    return static_cast<gint>(
498
0
      proxy->OffsetAtPoint(aX, aY,
499
0
                           (aCoords == ATK_XY_SCREEN ?
500
0
                            nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE :
501
0
                            nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE)));
502
0
  }
503
0
504
0
  return -1;
505
0
}
506
507
static gint
508
getTextSelectionCountCB(AtkText *aText)
509
0
{
510
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
511
0
  if (accWrap) {
512
0
    HyperTextAccessible* text = accWrap->AsHyperText();
513
0
    if (!text || !text->IsTextRole()) {
514
0
      return 0;
515
0
    }
516
0
517
0
    return text->SelectionCount();
518
0
  }
519
0
520
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
521
0
    return proxy->SelectionCount();
522
0
  }
523
0
524
0
  return 0;
525
0
}
526
527
static gchar*
528
getTextSelectionCB(AtkText *aText, gint aSelectionNum,
529
                   gint *aStartOffset, gint *aEndOffset)
530
0
{
531
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
532
0
  int32_t startOffset = 0, endOffset = 0;
533
0
  if (accWrap) {
534
0
    HyperTextAccessible* text = accWrap->AsHyperText();
535
0
    if (!text || !text->IsTextRole()) {
536
0
      return nullptr;
537
0
    }
538
0
539
0
    text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset);
540
0
    *aStartOffset = startOffset;
541
0
    *aEndOffset = endOffset;
542
0
543
0
    return getTextCB(aText, *aStartOffset, *aEndOffset);
544
0
  }
545
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
546
0
    nsString data;
547
0
    proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset);
548
0
    *aStartOffset = startOffset;
549
0
    *aEndOffset = endOffset;
550
0
551
0
    NS_ConvertUTF16toUTF8 dataAsUTF8(data);
552
0
    return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr;
553
0
  }
554
0
  return nullptr;
555
0
}
556
557
// set methods
558
static gboolean
559
addTextSelectionCB(AtkText *aText,
560
                   gint aStartOffset,
561
                   gint aEndOffset)
562
0
{
563
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
564
0
  if (accWrap) {
565
0
    HyperTextAccessible* text = accWrap->AsHyperText();
566
0
    if (!text || !text->IsTextRole()) {
567
0
      return FALSE;
568
0
    }
569
0
570
0
    return text->AddToSelection(aStartOffset, aEndOffset);
571
0
  }
572
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
573
0
    return proxy->AddToSelection(aStartOffset, aEndOffset);
574
0
  }
575
0
576
0
  return FALSE;
577
0
}
578
579
static gboolean
580
removeTextSelectionCB(AtkText *aText,
581
                      gint aSelectionNum)
582
0
{
583
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
584
0
  if (accWrap) {
585
0
    HyperTextAccessible* text = accWrap->AsHyperText();
586
0
    if (!text || !text->IsTextRole()) {
587
0
      return FALSE;
588
0
    }
589
0
590
0
    return text->RemoveFromSelection(aSelectionNum);
591
0
  }
592
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
593
0
    return proxy->RemoveFromSelection(aSelectionNum);
594
0
  }
595
0
596
0
  return FALSE;
597
0
}
598
599
static gboolean
600
setTextSelectionCB(AtkText *aText, gint aSelectionNum,
601
                   gint aStartOffset, gint aEndOffset)
602
0
{
603
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
604
0
  if (accWrap) {
605
0
    HyperTextAccessible* text = accWrap->AsHyperText();
606
0
    if (!text || !text->IsTextRole()) {
607
0
      return FALSE;
608
0
    }
609
0
610
0
    return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
611
0
  }
612
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
613
0
    return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset);
614
0
  }
615
0
616
0
  return FALSE;
617
0
}
618
619
static gboolean
620
setCaretOffsetCB(AtkText *aText, gint aOffset)
621
0
{
622
0
  AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
623
0
  if (accWrap) {
624
0
    HyperTextAccessible* text = accWrap->AsHyperText();
625
0
    if (!text || !text->IsTextRole() || !text->IsValidOffset(aOffset)) {
626
0
      return FALSE;
627
0
    }
628
0
629
0
    text->SetCaretOffset(aOffset);
630
0
    return TRUE;
631
0
  }
632
0
633
0
  if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
634
0
    proxy->SetCaretOffset(aOffset);
635
0
    return TRUE;
636
0
  }
637
0
638
0
  return FALSE;
639
0
}
640
}
641
642
void
643
textInterfaceInitCB(AtkTextIface* aIface)
644
0
{
645
0
  NS_ASSERTION(aIface, "Invalid aIface");
646
0
  if (MOZ_UNLIKELY(!aIface))
647
0
    return;
648
0
649
0
  aIface->get_text = getTextCB;
650
0
  aIface->get_text_after_offset = getTextAfterOffsetCB;
651
0
  aIface->get_text_at_offset = getTextAtOffsetCB;
652
0
  aIface->get_character_at_offset = getCharacterAtOffsetCB;
653
0
  aIface->get_text_before_offset = getTextBeforeOffsetCB;
654
0
  aIface->get_caret_offset = getCaretOffsetCB;
655
0
  aIface->get_run_attributes = getRunAttributesCB;
656
0
  aIface->get_default_attributes = getDefaultAttributesCB;
657
0
  aIface->get_character_extents = getCharacterExtentsCB;
658
0
  aIface->get_range_extents = getRangeExtentsCB;
659
0
  aIface->get_character_count = getCharacterCountCB;
660
0
  aIface->get_offset_at_point = getOffsetAtPointCB;
661
0
  aIface->get_n_selections = getTextSelectionCountCB;
662
0
  aIface->get_selection = getTextSelectionCB;
663
0
664
0
    // set methods
665
0
  aIface->add_selection = addTextSelectionCB;
666
0
  aIface->remove_selection = removeTextSelectionCB;
667
0
  aIface->set_selection = setTextSelectionCB;
668
0
  aIface->set_caret_offset = setCaretOffsetCB;
669
0
670
0
  // Cache the string values of the atk text attribute names.
671
0
  for (uint32_t i = 0; i < ArrayLength(sAtkTextAttrNames); i++)
672
0
    sAtkTextAttrNames[i] =
673
0
      atk_text_attribute_get_name(static_cast<AtkTextAttribute>(i));
674
0
}