Bug 1653421 - Part 3: Don't normalize marker beyond editable root. r=morgan
authorEitan Isaacson <eitan@monotonous.org>
Tue, 21 Jul 2020 23:02:57 +0000
changeset 541541 5972532c773757211b0d30ed34a3849bae0dc5a9
parent 541540 1d37ebf3d20ce8071c7482fbf7bcdc37834e950c
child 541542 f8de624ccd8a858132ffac2d66d80082acc3ae6a
push id122322
push usereisaacson@mozilla.com
push dateTue, 21 Jul 2020 23:11:09 +0000
treeherderautoland@88708e164b1a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmorgan
bugs1653421
milestone80.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 1653421 - Part 3: Don't normalize marker beyond editable root. r=morgan When in an editable container, text markers are expected to not go past or before the editable root. Differential Revision: https://phabricator.services.mozilla.com/D84055
accessible/mac/GeckoTextMarker.h
accessible/mac/GeckoTextMarker.mm
--- a/accessible/mac/GeckoTextMarker.h
+++ b/accessible/mac/GeckoTextMarker.h
@@ -51,16 +51,18 @@ class GeckoTextMarker final {
 
   bool operator<(const GeckoTextMarker& aPoint) const;
 
   AccessibleOrProxy mContainer;
   int32_t mOffset;
 
  private:
   uint32_t CharacterCount(const AccessibleOrProxy& aContainer);
+
+  bool IsEditableRoot();
 };
 
 class GeckoTextMarkerRange final {
  public:
   GeckoTextMarkerRange(const GeckoTextMarker& aStart, const GeckoTextMarker& aEnd)
       : mStart(aStart), mEnd(aEnd) {}
 
   GeckoTextMarkerRange(AccessibleOrProxy aDoc, AXTextMarkerRangeRef aTextMarkerRange);
--- a/accessible/mac/GeckoTextMarker.mm
+++ b/accessible/mac/GeckoTextMarker.mm
@@ -95,31 +95,51 @@ bool GeckoTextMarker::operator<(const Ge
       return child1.IndexInParent() < child2.IndexInParent();
     }
   }
 
   MOZ_ASSERT_UNREACHABLE("Broken tree?!");
   return false;
 }
 
+bool GeckoTextMarker::IsEditableRoot() {
+  uint64_t state =
+      mContainer.IsProxy() ? mContainer.AsProxy()->State() : mContainer.AsAccessible()->State();
+  if ((state & states::EDITABLE) == 0) {
+    return false;
+  }
+
+  AccessibleOrProxy parent = mContainer.Parent();
+  if (parent.IsNull()) {
+    // Not sure when this can happen, but it would technically be an editable root.
+    return true;
+  }
+
+  state = parent.IsProxy() ? parent.AsProxy()->State() : parent.AsAccessible()->State();
+
+  return (state & states::EDITABLE) == 0;
+}
+
 void GeckoTextMarker::NormalizeNext() {
   if (AtEnd()) {
     // If this is the end of the current container, mutate to its parent's
     // end offset.
     bool unused;
     uint32_t endOffset = mContainer.IsProxy() ? mContainer.AsProxy()->EndOffset(&unused)
                                               : mContainer.AsAccessible()->EndOffset();
 
     if (endOffset != 0) {
-      mContainer = mContainer.Parent();
-      mOffset = endOffset;
+      if (!IsEditableRoot()) {
+        mContainer = mContainer.Parent();
+        mOffset = endOffset;
 
-      // Call NormalizeNext recursively to get top-most link if at the end of one,
-      // or innermost link if at the beginning.
-      NormalizeNext();
+        // Call NormalizeNext recursively to get top-most link if at the end of one,
+        // or innermost link if at the beginning.
+        NormalizeNext();
+      }
     }
   } else {
     AccessibleOrProxy link;
 
     if (mContainer.IsProxy()) {
       ProxyAccessible* proxy = mContainer.AsProxy();
       link = proxy->LinkAt(proxy->LinkIndexAtOffset(mOffset));
     } else if (HyperTextAccessible* ht = mContainer.AsAccessible()->AsHyperText()) {
@@ -141,22 +161,24 @@ void GeckoTextMarker::NormalizeNext() {
 void GeckoTextMarker::NormalizePrevious() {
   if (mOffset == 0) {
     // If we are at the beginning of a container, mutate to its parent's start offset.
     bool unused;
     uint32_t startOffset = mContainer.IsProxy() ? mContainer.AsProxy()->StartOffset(&unused)
                                                 : mContainer.AsAccessible()->StartOffset();
 
     if (startOffset != 0) {
-      mContainer = mContainer.Parent();
-      mOffset = startOffset;
+      if (!IsEditableRoot()) {
+        mContainer = mContainer.Parent();
+        mOffset = startOffset;
 
-      // Call NormalizePrevious recursively to get top-most link if at the start of one,
-      // or innermost link if at the end.
-      NormalizePrevious();
+        // Call NormalizePrevious recursively to get top-most link if at the start of one,
+        // or innermost link if at the end.
+        NormalizePrevious();
+      }
     }
   } else {
     AccessibleOrProxy link;
 
     if (mContainer.IsProxy()) {
       ProxyAccessible* proxy = mContainer.AsProxy();
       link = proxy->LinkAt(proxy->LinkIndexAtOffset(mOffset - 1));
     } else if (HyperTextAccessible* ht = mContainer.AsAccessible()->AsHyperText()) {