Bug 1187995 - Add proxy handling to mozTextAccessible r=tbsaunde
authorLorien Hu <lorien@lorienhu.com>
Wed, 05 Aug 2015 21:55:13 -0400
changeset 256442 e323de7f0ac981ec884bed04a6d093490c5510e3
parent 256441 49948c2762104eeece44f79a4e2479e3a899e13c
child 256443 b4b5caf0208e81ad7f1375e61be72cc6778bebde
push id63334
push userlhu@mozilla.com
push dateThu, 06 Aug 2015 01:57:11 +0000
treeherdermozilla-inbound@b4b5caf0208e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde
bugs1187995
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1187995 - Add proxy handling to mozTextAccessible r=tbsaunde
accessible/ipc/DocAccessibleChild.cpp
accessible/ipc/DocAccessibleChild.h
accessible/ipc/PDocAccessible.ipdl
accessible/ipc/ProxyAccessible.cpp
accessible/ipc/ProxyAccessible.h
accessible/mac/mozTextAccessible.mm
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleChild.h"
 
 #include "Accessible-inl.h"
 #include "ProxyAccessible.h"
 #include "Relation.h"
 #include "HyperTextAccessible-inl.h"
+#include "TextLeafAccessible.h"
 #include "ImageAccessible.h"
 #include "TableAccessible.h"
 #include "TableCellAccessible.h"
 #include "nsIPersistentProperties2.h"
 #include "nsISimpleEnumerator.h"
 #include "nsAccUtils.h"
 
 namespace mozilla {
@@ -92,16 +93,23 @@ DocAccessibleChild::IdToAccessibleSelect
 
 HyperTextAccessible*
 DocAccessibleChild::IdToHyperTextAccessible(const uint64_t& aID) const
 {
   Accessible* acc = IdToAccessible(aID);
   return acc && acc->IsHyperText() ? acc->AsHyperText() : nullptr;
 }
 
+TextLeafAccessible*
+DocAccessibleChild::IdToTextLeafAccessible(const uint64_t& aID) const
+{
+  Accessible* acc = IdToAccessible(aID);
+  return acc && acc->IsTextLeaf() ? acc->AsTextLeaf() : nullptr;
+}
+
 ImageAccessible*
 DocAccessibleChild::IdToImageAccessible(const uint64_t& aID) const
 {
   Accessible* acc = IdToAccessible(aID);
   return (acc && acc->IsImage()) ? acc->AsImage() : nullptr;
 }
 
 TableCellAccessible*
@@ -338,16 +346,24 @@ DocAccessibleChild::RecvARIARoleAtom(con
       roleAtom->ToString(*aRole);
     }
   }
 
   return true;
 }
 
 bool
+DocAccessibleChild::RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
+{
+  HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
+  *aLineNumber = acc && acc->IsTextRole() ? acc->CaretLineNumber() : 0;
+  return true;
+}
+
+bool
 DocAccessibleChild::RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   *aOffset = acc && acc->IsTextRole() ? acc->CaretOffset() : 0;
   return true;
 }
 
 bool
@@ -631,16 +647,27 @@ DocAccessibleChild::RecvScrollSubstringT
   if (acc) {
     acc->ScrollSubstringToPoint(aStartOffset, aEndOffset, aCoordinateType,
                                 aX, aY);
   }
 
   return true;
 }
 
+bool
+DocAccessibleChild::RecvText(const uint64_t& aID,
+                             nsString* aText)
+{
+  TextLeafAccessible* acc = IdToTextLeafAccessible(aID);
+  if (acc) {
+    *aText = acc->Text();
+  }
+
+  return true;
+}
 
 bool
 DocAccessibleChild::RecvReplaceText(const uint64_t& aID,
                                     const nsString& aText)
 {
   HyperTextAccessible* acc = IdToHyperTextAccessible(aID);
   if (acc && acc->IsTextRole()) {
     acc->ReplaceText(aText);
--- a/accessible/ipc/DocAccessibleChild.h
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -10,16 +10,17 @@
 #include "mozilla/a11y/DocAccessible.h"
 #include "mozilla/a11y/PDocAccessibleChild.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace a11y {
 class Accessible;
 class HyperTextAccessible;
+class TextLeafAccessible;
 class ImageAccessible;
 class TableAccessible;
 class TableCellAccessible;
 class AccShowEvent;
 
   /*
    * These objects handle content side communication for an accessible document,
    * and their lifetime is the same as the document they represent.
@@ -91,16 +92,18 @@ public:
 
   virtual bool RecvLandmarkRole(const uint64_t& aID, nsString* aLandmark) override;
 
   virtual bool RecvARIARoleAtom(const uint64_t& aID, nsString* aRole) override;
 
   virtual bool RecvAttributes(const uint64_t& aID,
                               nsTArray<Attribute> *aAttributes) override;
 
+  virtual bool RecvCaretLineNumber(const uint64_t& aID, int32_t* aLineNumber)
+    override;
   virtual bool RecvCaretOffset(const uint64_t& aID, int32_t* aOffset)
     override;
   virtual bool RecvSetCaretOffset(const uint64_t& aID, const int32_t& aOffset,
                                   bool* aValid) override;
 
   virtual bool RecvCharacterCount(const uint64_t& aID, int32_t* aCount)
      override;
   virtual bool RecvSelectionCount(const uint64_t& aID, int32_t* aCount)
@@ -189,16 +192,19 @@ public:
 
   virtual bool RecvScrollSubstringToPoint(const uint64_t& aID,
                                           const int32_t& aStartOffset,
                                           const int32_t& aEndOffset,
                                           const uint32_t& aCoordinateType,
                                           const int32_t& aX,
                                           const int32_t& aY) override;
 
+  virtual bool RecvText(const uint64_t& aID,
+                        nsString* aText) override;
+
   virtual bool RecvReplaceText(const uint64_t& aID,
                                const nsString& aText) override;
 
   virtual bool RecvInsertText(const uint64_t& aID,
                               const nsString& aText,
                               const int32_t& aPosition, bool* aValid) override;
 
   virtual bool RecvCopyText(const uint64_t& aID,
@@ -455,16 +461,17 @@ public:
                                       nsString* aDocType,
                                       nsString* aMimeType) override;
 private:
 
   Accessible* IdToAccessible(const uint64_t& aID) const;
   Accessible* IdToAccessibleLink(const uint64_t& aID) const;
   Accessible* IdToAccessibleSelect(const uint64_t& aID) const;
   HyperTextAccessible* IdToHyperTextAccessible(const uint64_t& aID) const;
+  TextLeafAccessible* IdToTextLeafAccessible(const uint64_t& aID) const;
   ImageAccessible* IdToImageAccessible(const uint64_t& aID) const;
   TableCellAccessible* IdToTableCellAccessible(const uint64_t& aID) const;
   TableAccessible* IdToTableAccessible(const uint64_t& aID) const;
 
   bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
                                    nsTArray<Attribute>* aAttributes);
 
   DocAccessible* mDoc;
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -84,16 +84,17 @@ child:
   prio(high) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
   prio(high) sync IsSearchbox(uint64_t aID) returns(bool retval);
   prio(high) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
   prio(high) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
 
   // AccessibleText
 
   // TextSubstring is getText in IDL.
+  prio(high) sync CaretLineNumber(uint64_t aID) returns(int32_t aLineNumber);
   prio(high) sync CaretOffset(uint64_t aID) returns(int32_t aOffset);
   prio(high) sync SetCaretOffset(uint64_t aID, int32_t aOffset) returns (bool aValid);
   prio(high) sync CharacterCount(uint64_t aID) returns(int32_t aCount);
   prio(high) sync SelectionCount(uint64_t aID) returns(int32_t aCount);
   prio(high) sync TextSubstring(uint64_t aID, int32_t aStartOffset, int32_t
                                 aEndOffset) returns(nsString aText, bool aValid);
   prio(high) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
     returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
@@ -130,16 +131,17 @@ child:
   ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
                     uint32_t aScrollType);
   ScrollSubstringToPoint(uint64_t aID,
                          int32_t aStartOffset,
                          int32_t aEndOffset,
                          uint32_t aCoordinateType,
                          int32_t aX, int32_t aY);
 
+  prio(high) sync Text(uint64_t aID) returns(nsString aText);
   prio(high) sync ReplaceText(uint64_t aID, nsString aText);
   prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
     returns(bool aValid);
   prio(high) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
   prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
   prio(high) sync DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
--- a/accessible/ipc/ProxyAccessible.cpp
+++ b/accessible/ipc/ProxyAccessible.cpp
@@ -187,16 +187,24 @@ nsIAtom*
 ProxyAccessible::ARIARoleAtom() const
 {
   nsString role;
   unused << mDoc->SendARIARoleAtom(mID, &role);
   return NS_GetStaticAtom(role);
 }
 
 int32_t
+ProxyAccessible::CaretLineNumber()
+{
+  int32_t line = -1;
+  unused << mDoc->SendCaretOffset(mID, &line);
+  return line;
+}
+
+int32_t
 ProxyAccessible::CaretOffset()
 {
   int32_t offset = 0;
   unused << mDoc->SendCaretOffset(mID, &offset);
   return offset;
 }
 
 bool
@@ -367,16 +375,22 @@ ProxyAccessible::ScrollSubstringToPoint(
                                         uint32_t aCoordinateType,
                                         int32_t aX, int32_t aY)
 {
   unused << mDoc->SendScrollSubstringToPoint(mID, aStartOffset, aEndOffset,
                                              aCoordinateType, aX, aY);
 }
 
 void
+ProxyAccessible::Text(nsString* aText)
+{
+  unused << mDoc->SendText(mID, aText);
+}
+
+void
 ProxyAccessible::ReplaceText(const nsString& aText)
 {
   unused << mDoc->SendReplaceText(mID, aText);
 }
 
 bool
 ProxyAccessible::InsertText(const nsString& aText, int32_t aPosition)
 {
--- a/accessible/ipc/ProxyAccessible.h
+++ b/accessible/ipc/ProxyAccessible.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_ProxyAccessible_h
 #define mozilla_a11y_ProxyAccessible_h
 
 #include "mozilla/a11y/Role.h"
 #include "nsIAccessibleText.h"
+#include "nsIAccessibleTypes.h"
 #include "Accessible.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRect.h"
 #include "Accessible.h"
 
 namespace mozilla {
 namespace a11y {
@@ -121,16 +122,17 @@ public:
                  nsTArray<nsTArray<ProxyAccessible*>>* aTargetSets) const;
 
   bool IsSearchbox() const;
 
   nsIAtom* LandmarkRole() const;
 
   nsIAtom* ARIARoleAtom() const;
 
+  int32_t CaretLineNumber();
   int32_t CaretOffset();
   bool SetCaretOffset(int32_t aOffset);
 
   int32_t CharacterCount();
   int32_t SelectionCount();
 
   /**
    * Get the text between the given offsets.
@@ -155,17 +157,17 @@ public:
   void TextAttributes(bool aIncludeDefAttrs,
                       const int32_t aOffset,
                       nsTArray<Attribute>* aAttributes,
                       int32_t* aStartOffset,
                       int32_t* aEndOffset);
   void DefaultTextAttributes(nsTArray<Attribute>* aAttrs);
 
   nsIntRect TextBounds(int32_t aStartOffset, int32_t aEndOffset,
-                       uint32_t aCoordType);
+                       uint32_t aCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE);
 
   nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType);
 
   int32_t OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType);
 
   bool SelectionBoundsAt(int32_t aSelectionNum,
                          nsString& aData,
                          int32_t* aStartOffset,
@@ -183,16 +185,18 @@ public:
   void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset,
                          uint32_t aScrollType);
 
   void ScrollSubstringToPoint(int32_t aStartOffset,
                               int32_t aEndOffset,
                               uint32_t aCoordinateType,
                               int32_t aX, int32_t aY);
 
+  void Text(nsString* aText);
+
   void ReplaceText(const nsString& aText);
 
   bool InsertText(const nsString& aText, int32_t aPosition);
 
   bool CopyText(int32_t aStartPos, int32_t aEndPos);
 
   bool CutText(int32_t aStartPos, int32_t aEndPos);
 
--- a/accessible/mac/mozTextAccessible.mm
+++ b/accessible/mac/mozTextAccessible.mm
@@ -109,23 +109,33 @@ ToNSString(id aValue)
     if ([[self role] isEqualToString:NSAccessibilityStaticTextRole]) {
       NSString* selectedText = [self selectedText];
       return (selectedText && [selectedText length]) ? selectedText : [self text];
     }
 
     return [self text];
   }
 
-  AccessibleWrap* accWrap = [self getGeckoAccessible];
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    if ([attribute isEqualToString:@"AXRequired"]) {
+      return [NSNumber numberWithBool:!!(accWrap->State() & states::REQUIRED)];
+    }
 
-  if ([attribute isEqualToString:@"AXRequired"])
-    return [NSNumber numberWithBool:!!(accWrap->State() & states::REQUIRED)];
+    if ([attribute isEqualToString:@"AXInvalid"]) {
+      return [NSNumber numberWithBool:!!(accWrap->State() & states::INVALID)];
+    }
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    if ([attribute isEqualToString:@"AXRequired"]) {
+      return [NSNumber numberWithBool:!!(proxy->State() & states::REQUIRED)];
+    }
 
-  if ([attribute isEqualToString:@"AXInvalid"])
-    return [NSNumber numberWithBool:!!(accWrap->State() & states::INVALID)];
+    if ([attribute isEqualToString:@"AXInvalid"]) {
+      return [NSNumber numberWithBool:!!(proxy->State() & states::INVALID)];
+    }
+  }
 
   if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
     return [self visibleCharacterRange];
 
   // let mozAccessible handle all other attributes
   return [super accessibilityAttributeValue:attribute];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
@@ -152,18 +162,20 @@ ToNSString(id aValue)
     ];
   }
   return supportedParametrizedAttributes;
 }
 
 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
 {
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
+
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  if (!textAcc)
+  if (!textAcc && !proxy)
     return nil;
 
   if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
     NSRange range;
     if (!ToNSRange(parameter, &range)) {
 #if DEBUG
       NSLog(@"%@: range not set", attribute);
 #endif
@@ -201,17 +213,22 @@ ToNSString(id aValue)
 #if DEBUG
       NSLog(@"%@:no range", attribute);
 #endif
       return nil;
     }
 
     int32_t start = range.location;
     int32_t end = start + range.length;
-    nsIntRect bounds = textAcc->TextBounds(start, end);
+    nsIntRect bounds;
+    if (textAcc) {
+      bounds = textAcc->TextBounds(start, end);
+    } else if (proxy) {
+      bounds = proxy->TextBounds(start, end);
+    }
 
     return [NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(bounds)];
   }
 
 #if DEBUG
   NSLog(@"unhandled attribute:%@ forParameter:%@", attribute, parameter);
 #endif
 
@@ -235,57 +252,76 @@ ToNSString(id aValue)
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
+
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  if (!textAcc)
+  if (!textAcc && !proxy)
     return;
 
   if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
     [self setText:ToNSString(value)];
 
     return;
   }
 
   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
     NSString* stringValue = ToNSString(value);
     if (!stringValue)
       return;
 
     int32_t start = 0, end = 0;
-    textAcc->SelectionBoundsAt(0, &start, &end);
-    textAcc->DeleteText(start, end - start);
-
     nsString text;
-    nsCocoaUtils::GetStringForNSString(stringValue, text);
-    textAcc->InsertText(text, start);
+    if (textAcc) {
+      textAcc->SelectionBoundsAt(0, &start, &end);
+      textAcc->DeleteText(start, end - start);
+      nsCocoaUtils::GetStringForNSString(stringValue, text);
+      textAcc->InsertText(text, start);
+    } else if (proxy) {
+      nsString data;
+      proxy->SelectionBoundsAt(0, data, &start, &end);
+      proxy->DeleteText(start, end - start);
+      nsCocoaUtils::GetStringForNSString(stringValue, text);
+      proxy->InsertText(text, start);
+    }
   }
 
   if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
     NSRange range;
     if (!ToNSRange(value, &range))
       return;
 
-    textAcc->SetSelectionBoundsAt(0, range.location,
+    if (textAcc) {
+      textAcc->SetSelectionBoundsAt(0, range.location,
+                                    range.location + range.length);
+    } else if (proxy) {
+      proxy->SetSelectionBoundsAt(0, range.location,
                                   range.location + range.length);
+    }
     return;
   }
 
   if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
     NSRange range;
     if (!ToNSRange(value, &range))
       return;
 
-    textAcc->ScrollSubstringTo(range.location, range.location + range.length,
+    if (textAcc) {
+      textAcc->ScrollSubstringTo(range.location, range.location + range.length,
+                                 nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
+    } else if (proxy) {
+      proxy->ScrollSubstringTo(range.location, range.location + range.length,
                                nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE);
+    }
     return;
   }
 
   [super accessibilitySetValue:value forAttribute:attribute];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
@@ -306,145 +342,194 @@ ToNSString(id aValue)
   if ([[self role] isEqualToString:NSAccessibilityStaticTextRole])
     return YES;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
   if (textAcc)
     return (accWrap->State() & states::READONLY) == 0;
 
+  if (ProxyAccessible* proxy = [self getProxyAccessible])
+    return (proxy->State() & states::READONLY) == 0;
+
   return NO;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 - (NSNumber*)caretLineNumber
 {
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  int32_t lineNumber = textAcc ?
-    textAcc->CaretLineNumber() - 1 : -1;
+
+  int32_t lineNumber = -1;
+  if (textAcc) {
+    lineNumber = textAcc->CaretLineNumber() - 1;
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    lineNumber = proxy->CaretLineNumber() - 1;
+  }
 
   return (lineNumber >= 0) ? [NSNumber numberWithInt:lineNumber] : nil;
 }
 
 - (void)setText:(NSString*)aNewString
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
+
+  nsString text;
+  nsCocoaUtils::GetStringForNSString(aNewString, text);
   if (textAcc) {
-    nsString text;
-    nsCocoaUtils::GetStringForNSString(aNewString, text);
     textAcc->ReplaceText(text);
+  } else if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    proxy->ReplaceText(text);
   }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 - (NSString*)text
 {
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  if (!accWrap || !textAcc)
+  if (!textAcc && !proxy)
     return nil;
 
   // A password text field returns an empty value
   if (mRole == roles::PASSWORD_TEXT)
     return @"";
 
   nsAutoString text;
-  textAcc->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
+  if (textAcc) {
+    textAcc->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
+  } else if (proxy) {
+    proxy->TextSubstring(0, nsIAccessibleText::TEXT_OFFSET_END_OF_TEXT, text);
+  }
+
   return nsCocoaUtils::ToNSString(text);
 }
 
 - (long)textLength
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  if (!accWrap || !textAcc)
+  if (!textAcc && !proxy)
     return 0;
 
-  return textAcc ? textAcc->CharacterCount() : 0;
+  return textAcc ? textAcc->CharacterCount() : proxy->CharacterCount();
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
 }
 
 - (long)selectedTextLength
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
+  if (!textAcc && !proxy)
+    return 0;
+
+  int32_t start = 0, end = 0;
   if (textAcc) {
-    int32_t start = 0, end = 0;
     textAcc->SelectionBoundsAt(0, &start, &end);
-    return (end - start);
+  } else if (proxy) {
+    nsString data;
+    proxy->SelectionBoundsAt(0, data, &start, &end);
   }
-  return 0;
+  return (end - start);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
 }
 
 - (NSString*)selectedText
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
+  if (!textAcc && !proxy)
+    return nil;
+
+  int32_t start = 0, end = 0;
+  nsAutoString selText;
   if (textAcc) {
-    int32_t start = 0, end = 0;
     textAcc->SelectionBoundsAt(0, &start, &end);
     if (start != end) {
-      nsAutoString selText;
       textAcc->TextSubstring(start, end, selText);
-      return nsCocoaUtils::ToNSString(selText);
     }
+  } else if (proxy) {
+    proxy->SelectionBoundsAt(0, selText, &start, &end);
   }
-  return nil;
+
+  return nsCocoaUtils::ToNSString(selText);
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (NSValue*)selectedTextRange
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
+
+  int32_t start = 0;
+  int32_t end = 0;
+  int32_t count = 0;
   if (textAcc) {
-    int32_t start = 0;
-    int32_t end = 0;
-    int32_t count = textAcc->SelectionCount();
-
+    count = textAcc->SelectionCount();
     if (count) {
       textAcc->SelectionBoundsAt(0, &start, &end);
       return [NSValue valueWithRange:NSMakeRange(start, end - start)];
     }
 
     start = textAcc->CaretOffset();
-    return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)]; 
+    return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)];
   }
+
+  if (proxy) {
+    count = proxy->SelectionCount();
+    if (count) {
+      nsString data;
+      proxy->SelectionBoundsAt(0, data, &start, &end);
+      return [NSValue valueWithRange:NSMakeRange(start, end - start)];
+    }
+
+    start = proxy->CaretOffset();
+    return [NSValue valueWithRange:NSMakeRange(start != -1 ? start : 0, 0)];
+  }
+
   return [NSValue valueWithRange:NSMakeRange(0, 0)];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (NSValue*)visibleCharacterRange
 {
   // XXX this won't work with Textarea and such as we actually don't give
   // the visible character range.
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
+  if (!textAcc && !proxy)
+    return 0;
+
   return [NSValue valueWithRange:
     NSMakeRange(0, textAcc ?
-                textAcc->CharacterCount() : 0)];
+                textAcc->CharacterCount() : proxy->CharacterCount())];
 }
 
 - (void)valueDidChange
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   NSAccessibilityPostNotification(GetObjectOrRepresentedView(self),
                                   NSAccessibilityValueChangedNotification);
@@ -458,23 +543,30 @@ ToNSString(id aValue)
                                   NSAccessibilitySelectedTextChangedNotification);
 }
 
 - (NSString*)stringFromRange:(NSRange*)range
 {
   NS_PRECONDITION(range, "no range");
 
   AccessibleWrap* accWrap = [self getGeckoAccessible];
+  ProxyAccessible* proxy = [self getProxyAccessible];
   HyperTextAccessible* textAcc = accWrap? accWrap->AsHyperText() : nullptr;
-  if (!textAcc)
+  if (!textAcc && !proxy)
     return nil;
 
   nsAutoString text;
-  textAcc->TextSubstring(range->location,
-                         range->location + range->length, text);
+  if (textAcc) {
+    textAcc->TextSubstring(range->location,
+                           range->location + range->length, text);
+  } else if (proxy) {
+    proxy->TextSubstring(range->location,
+                           range->location + range->length, text);
+  }
+
   return nsCocoaUtils::ToNSString(text);
 }
 
 @end
 
 @implementation mozTextLeafAccessible
 
 - (NSArray*)accessibilityAttributeNames
@@ -496,25 +588,37 @@ ToNSString(id aValue)
   if ([attribute isEqualToString:NSAccessibilityValueAttribute])
     return [self text];
 
   return [super accessibilityAttributeValue:attribute];
 }
 
 - (NSString*)text
 {
-  AccessibleWrap* accWrap = [self getGeckoAccessible];
-  if (!accWrap)
-    return nil;
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    return nsCocoaUtils::ToNSString(accWrap->AsTextLeaf()->Text());
+  }
 
-  return nsCocoaUtils::ToNSString(accWrap->AsTextLeaf()->Text());
+  if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    nsString text;
+    proxy->Text(&text);
+    return nsCocoaUtils::ToNSString(text);
+  }
+
+  return nil;
 }
 
 - (long)textLength
 {
-  AccessibleWrap* accWrap = [self getGeckoAccessible];
-  if (!accWrap)
-    return 0;
+  if (AccessibleWrap* accWrap = [self getGeckoAccessible]) {
+    return accWrap->AsTextLeaf()->Text().Length();
+  }
 
-  return accWrap->AsTextLeaf()->Text().Length();
+  if (ProxyAccessible* proxy = [self getProxyAccessible]) {
+    nsString text;
+    proxy->Text(&text);
+    return text.Length();
+  }
+
+  return 0;
 }
 
 @end