forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			467 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			467 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
 | 
						|
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * 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/. */
 | 
						|
 | 
						|
#include "SessionAccessibility.h"
 | 
						|
#include "LocalAccessible-inl.h"
 | 
						|
#include "AndroidUiThread.h"
 | 
						|
#include "DocAccessibleParent.h"
 | 
						|
#include "nsThreadUtils.h"
 | 
						|
#include "AccessibilityEvent.h"
 | 
						|
#include "HyperTextAccessible.h"
 | 
						|
#include "JavaBuiltins.h"
 | 
						|
#include "RootAccessibleWrap.h"
 | 
						|
#include "nsAccessibilityService.h"
 | 
						|
#include "nsViewManager.h"
 | 
						|
#include "nsIPersistentProperties2.h"
 | 
						|
 | 
						|
#include "mozilla/PresShell.h"
 | 
						|
#include "mozilla/dom/BrowserParent.h"
 | 
						|
#include "mozilla/a11y/DocAccessibleParent.h"
 | 
						|
#include "mozilla/a11y/DocManager.h"
 | 
						|
#include "mozilla/jni/GeckoBundleUtils.h"
 | 
						|
#include "mozilla/widget/GeckoViewSupport.h"
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
#  include <android/log.h>
 | 
						|
#  define AALOG(args...) \
 | 
						|
    __android_log_print(ANDROID_LOG_INFO, "GeckoAccessibilityNative", ##args)
 | 
						|
#else
 | 
						|
#  define AALOG(args...) \
 | 
						|
    do {                 \
 | 
						|
    } while (0)
 | 
						|
#endif
 | 
						|
 | 
						|
#define FORWARD_ACTION_TO_ACCESSIBLE(funcname, ...)         \
 | 
						|
  if (RootAccessibleWrap* rootAcc = GetRoot()) {            \
 | 
						|
    AccessibleWrap* acc = rootAcc->FindAccessibleById(aID); \
 | 
						|
    if (!acc) {                                             \
 | 
						|
      return;                                               \
 | 
						|
    }                                                       \
 | 
						|
                                                            \
 | 
						|
    acc->funcname(__VA_ARGS__);                             \
 | 
						|
  }
 | 
						|
 | 
						|
using namespace mozilla::a11y;
 | 
						|
 | 
						|
class Settings final
 | 
						|
    : public mozilla::java::SessionAccessibility::Settings::Natives<Settings> {
 | 
						|
 public:
 | 
						|
  static void ToggleNativeAccessibility(bool aEnable) {
 | 
						|
    if (aEnable) {
 | 
						|
      GetOrCreateAccService();
 | 
						|
    } else {
 | 
						|
      MaybeShutdownAccService(nsAccessibilityService::ePlatformAPI);
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
SessionAccessibility::SessionAccessibility(
 | 
						|
    jni::NativeWeakPtr<widget::GeckoViewSupport> aWindow,
 | 
						|
    java::SessionAccessibility::NativeProvider::Param aSessionAccessibility)
 | 
						|
    : mWindow(aWindow), mSessionAccessibility(aSessionAccessibility) {
 | 
						|
  SetAttached(true, nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SetAttached(bool aAttached,
 | 
						|
                                       already_AddRefed<Runnable> aRunnable) {
 | 
						|
  if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
 | 
						|
    uiThread->Dispatch(NS_NewRunnableFunction(
 | 
						|
        "SessionAccessibility::Attach",
 | 
						|
        [aAttached,
 | 
						|
         sa = java::SessionAccessibility::NativeProvider::GlobalRef(
 | 
						|
             mSessionAccessibility),
 | 
						|
         runnable = RefPtr<Runnable>(aRunnable)] {
 | 
						|
          sa->SetAttached(aAttached);
 | 
						|
          if (runnable) {
 | 
						|
            runnable->Run();
 | 
						|
          }
 | 
						|
        }));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Init() {
 | 
						|
  java::SessionAccessibility::NativeProvider::Natives<
 | 
						|
      SessionAccessibility>::Init();
 | 
						|
  Settings::Init();
 | 
						|
}
 | 
						|
 | 
						|
mozilla::jni::Object::LocalRef SessionAccessibility::GetNodeInfo(int32_t aID) {
 | 
						|
  java::GeckoBundle::GlobalRef ret = nullptr;
 | 
						|
  RefPtr<SessionAccessibility> self(this);
 | 
						|
  nsAppShell::SyncRunEvent([this, self, aID, &ret] {
 | 
						|
    if (RootAccessibleWrap* rootAcc = GetRoot()) {
 | 
						|
      AccessibleWrap* acc = rootAcc->FindAccessibleById(aID);
 | 
						|
      if (acc) {
 | 
						|
        ret = acc->ToBundle();
 | 
						|
      } else {
 | 
						|
        AALOG("oops, nothing for %d", aID);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  });
 | 
						|
 | 
						|
  return mozilla::jni::Object::Ref::From(ret);
 | 
						|
}
 | 
						|
 | 
						|
RootAccessibleWrap* SessionAccessibility::GetRoot() {
 | 
						|
  auto acc(mWindow.Access());
 | 
						|
  if (!acc) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsWindow* gkWindow = acc->GetNsWindow();
 | 
						|
  if (!gkWindow) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return static_cast<RootAccessibleWrap*>(gkWindow->GetRootAccessible());
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SetText(int32_t aID, jni::String::Param aText) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(SetTextContents, aText->ToString());
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Click(int32_t aID) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(DoAction, 0);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Pivot(int32_t aID, int32_t aGranularity,
 | 
						|
                                 bool aForward, bool aInclusive) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(PivotTo, aGranularity, aForward, aInclusive);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::ExploreByTouch(int32_t aID, float aX, float aY) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(ExploreByTouch, aX, aY);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::NavigateText(int32_t aID, int32_t aGranularity,
 | 
						|
                                        int32_t aStartOffset,
 | 
						|
                                        int32_t aEndOffset, bool aForward,
 | 
						|
                                        bool aSelect) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(NavigateText, aGranularity, aStartOffset,
 | 
						|
                               aEndOffset, aForward, aSelect);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SetSelection(int32_t aID, int32_t aStart,
 | 
						|
                                        int32_t aEnd) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(SetSelection, aStart, aEnd);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Cut(int32_t aID) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(Cut);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Copy(int32_t aID) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(Copy);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::Paste(int32_t aID) {
 | 
						|
  FORWARD_ACTION_TO_ACCESSIBLE(Paste);
 | 
						|
}
 | 
						|
 | 
						|
RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
 | 
						|
    RemoteAccessible* aAccessible) {
 | 
						|
  auto tab =
 | 
						|
      static_cast<dom::BrowserParent*>(aAccessible->Document()->Manager());
 | 
						|
  dom::Element* frame = tab->GetOwnerElement();
 | 
						|
  MOZ_ASSERT(frame);
 | 
						|
  if (!frame) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  LocalAccessible* chromeDoc = GetExistingDocAccessible(frame->OwnerDoc());
 | 
						|
  return chromeDoc ? GetInstanceFor(chromeDoc) : nullptr;
 | 
						|
}
 | 
						|
 | 
						|
RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
 | 
						|
    LocalAccessible* aAccessible) {
 | 
						|
  RootAccessible* rootAcc = aAccessible->RootAccessible();
 | 
						|
  nsViewManager* vm = rootAcc->PresShellPtr()->GetViewManager();
 | 
						|
  if (!vm) {
 | 
						|
    return nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  nsCOMPtr<nsIWidget> rootWidget;
 | 
						|
  vm->GetRootWidget(getter_AddRefs(rootWidget));
 | 
						|
  // `rootWidget` can be one of several types. Here we make sure it is an
 | 
						|
  // android nsWindow.
 | 
						|
  if (RefPtr<nsWindow> window = nsWindow::From(rootWidget)) {
 | 
						|
    return window->GetSessionAccessibility();
 | 
						|
  }
 | 
						|
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendAccessibilityFocusedEvent(
 | 
						|
    AccessibleWrap* aAccessible) {
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_ACCESSIBILITY_FOCUSED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), nullptr);
 | 
						|
  aAccessible->ScrollTo(nsIAccessibleScrollType::SCROLL_TYPE_ANYWHERE);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendHoverEnterEvent(AccessibleWrap* aAccessible) {
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_HOVER_ENTER,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendFocusEvent(AccessibleWrap* aAccessible) {
 | 
						|
  // Suppress focus events from about:blank pages.
 | 
						|
  // This is important for tests.
 | 
						|
  if (aAccessible->IsDoc() && aAccessible->ChildCount() == 0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_FOCUSED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendScrollingEvent(AccessibleWrap* aAccessible,
 | 
						|
                                              int32_t aScrollX,
 | 
						|
                                              int32_t aScrollY,
 | 
						|
                                              int32_t aMaxScrollX,
 | 
						|
                                              int32_t aMaxScrollY) {
 | 
						|
  int32_t virtualViewId = aAccessible->VirtualViewID();
 | 
						|
 | 
						|
  if (virtualViewId != AccessibleWrap::kNoID) {
 | 
						|
    // XXX: Support scrolling in subframes
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "scrollX", java::sdk::Integer::ValueOf(aScrollX));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "scrollY", java::sdk::Integer::ValueOf(aScrollY));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "maxScrollX",
 | 
						|
                  java::sdk::Integer::ValueOf(aMaxScrollX));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "maxScrollY",
 | 
						|
                  java::sdk::Integer::ValueOf(aMaxScrollY));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_SCROLLED, virtualViewId,
 | 
						|
      aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendWindowContentChangedEvent() {
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_WINDOW_CONTENT_CHANGED,
 | 
						|
      AccessibleWrap::kNoID, java::SessionAccessibility::CLASSNAME_WEBVIEW,
 | 
						|
      nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendWindowStateChangedEvent(
 | 
						|
    AccessibleWrap* aAccessible) {
 | 
						|
  // Suppress window state changed events from about:blank pages.
 | 
						|
  // This is important for tests.
 | 
						|
  if (aAccessible->IsDoc() && aAccessible->ChildCount() == 0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_WINDOW_STATE_CHANGED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), nullptr);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendTextSelectionChangedEvent(
 | 
						|
    AccessibleWrap* aAccessible, int32_t aCaretOffset) {
 | 
						|
  int32_t fromIndex = aCaretOffset;
 | 
						|
  int32_t startSel = -1;
 | 
						|
  int32_t endSel = -1;
 | 
						|
  if (aAccessible->GetSelectionBounds(&startSel, &endSel)) {
 | 
						|
    fromIndex = startSel == aCaretOffset ? endSel : startSel;
 | 
						|
  }
 | 
						|
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "fromIndex",
 | 
						|
                  java::sdk::Integer::ValueOf(fromIndex));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "toIndex",
 | 
						|
                  java::sdk::Integer::ValueOf(aCaretOffset));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_TEXT_SELECTION_CHANGED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendTextChangedEvent(AccessibleWrap* aAccessible,
 | 
						|
                                                const nsString& aStr,
 | 
						|
                                                int32_t aStart, uint32_t aLen,
 | 
						|
                                                bool aIsInsert,
 | 
						|
                                                bool aFromUser) {
 | 
						|
  if (!aFromUser) {
 | 
						|
    // Only dispatch text change events from users, for now.
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  nsAutoString text;
 | 
						|
  aAccessible->GetTextContents(text);
 | 
						|
  nsAutoString beforeText(text);
 | 
						|
  if (aIsInsert) {
 | 
						|
    beforeText.Cut(aStart, aLen);
 | 
						|
  } else {
 | 
						|
    beforeText.Insert(aStr, aStart);
 | 
						|
  }
 | 
						|
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "text", jni::StringParam(text));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "beforeText", jni::StringParam(beforeText));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "addedCount",
 | 
						|
                  java::sdk::Integer::ValueOf(aIsInsert ? aLen : 0));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "removedCount",
 | 
						|
                  java::sdk::Integer::ValueOf(aIsInsert ? 0 : aLen));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_TEXT_CHANGED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendTextTraversedEvent(AccessibleWrap* aAccessible,
 | 
						|
                                                  int32_t aStartOffset,
 | 
						|
                                                  int32_t aEndOffset) {
 | 
						|
  nsAutoString text;
 | 
						|
  aAccessible->GetTextContents(text);
 | 
						|
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "text", jni::StringParam(text));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "fromIndex",
 | 
						|
                  java::sdk::Integer::ValueOf(aStartOffset));
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "toIndex",
 | 
						|
                  java::sdk::Integer::ValueOf(aEndOffset));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::
 | 
						|
          TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendClickedEvent(AccessibleWrap* aAccessible,
 | 
						|
                                            uint32_t aFlags) {
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "flags", java::sdk::Integer::ValueOf(aFlags));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_CLICKED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendSelectedEvent(AccessibleWrap* aAccessible,
 | 
						|
                                             bool aSelected) {
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  // Boolean::FALSE/TRUE gets clobbered by a macro, so ugh.
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "selected",
 | 
						|
                  java::sdk::Integer::ValueOf(aSelected ? 1 : 0));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_VIEW_SELECTED,
 | 
						|
      aAccessible->VirtualViewID(), aAccessible->AndroidClass(), eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::SendAnnouncementEvent(AccessibleWrap* aAccessible,
 | 
						|
                                                 const nsString& aAnnouncement,
 | 
						|
                                                 uint16_t aPriority) {
 | 
						|
  GECKOBUNDLE_START(eventInfo);
 | 
						|
  GECKOBUNDLE_PUT(eventInfo, "text", jni::StringParam(aAnnouncement));
 | 
						|
  GECKOBUNDLE_FINISH(eventInfo);
 | 
						|
 | 
						|
  // Announcements should have the root as their source, so we ignore the
 | 
						|
  // accessible of the event.
 | 
						|
  mSessionAccessibility->SendEvent(
 | 
						|
      java::sdk::AccessibilityEvent::TYPE_ANNOUNCEMENT, AccessibleWrap::kNoID,
 | 
						|
      java::SessionAccessibility::CLASSNAME_WEBVIEW, eventInfo);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::ReplaceViewportCache(
 | 
						|
    const nsTArray<AccessibleWrap*>& aAccessibles,
 | 
						|
    const nsTArray<BatchData>& aData) {
 | 
						|
  auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
 | 
						|
  for (size_t i = 0; i < aAccessibles.Length(); i++) {
 | 
						|
    AccessibleWrap* acc = aAccessibles.ElementAt(i);
 | 
						|
    if (!acc) {
 | 
						|
      MOZ_ASSERT_UNREACHABLE("Updated accessible is gone.");
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (aData.Length() == aAccessibles.Length()) {
 | 
						|
      const BatchData& data = aData.ElementAt(i);
 | 
						|
      auto bundle = acc->ToBundle(
 | 
						|
          data.State(), data.Bounds(), data.ActionCount(), data.Name(),
 | 
						|
          data.TextValue(), data.DOMNodeID(), data.Description());
 | 
						|
      infos->SetElement(i, bundle);
 | 
						|
    } else {
 | 
						|
      infos->SetElement(i, acc->ToBundle(true));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mSessionAccessibility->ReplaceViewportCache(infos);
 | 
						|
  SendWindowContentChangedEvent();
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::ReplaceFocusPathCache(
 | 
						|
    const nsTArray<AccessibleWrap*>& aAccessibles,
 | 
						|
    const nsTArray<BatchData>& aData) {
 | 
						|
  auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
 | 
						|
  for (size_t i = 0; i < aAccessibles.Length(); i++) {
 | 
						|
    AccessibleWrap* acc = aAccessibles.ElementAt(i);
 | 
						|
    if (!acc) {
 | 
						|
      MOZ_ASSERT_UNREACHABLE("Updated accessible is gone.");
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (aData.Length() == aAccessibles.Length()) {
 | 
						|
      const BatchData& data = aData.ElementAt(i);
 | 
						|
      nsCOMPtr<nsIPersistentProperties> props =
 | 
						|
          AccessibleWrap::AttributeArrayToProperties(data.Attributes());
 | 
						|
      auto bundle =
 | 
						|
          acc->ToBundle(data.State(), data.Bounds(), data.ActionCount(),
 | 
						|
                        data.Name(), data.TextValue(), data.DOMNodeID(),
 | 
						|
                        data.Description(), data.CurValue(), data.MinValue(),
 | 
						|
                        data.MaxValue(), data.Step(), props);
 | 
						|
      infos->SetElement(i, bundle);
 | 
						|
    } else {
 | 
						|
      infos->SetElement(i, acc->ToBundle());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mSessionAccessibility->ReplaceFocusPathCache(infos);
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::UpdateCachedBounds(
 | 
						|
    const nsTArray<AccessibleWrap*>& aAccessibles,
 | 
						|
    const nsTArray<BatchData>& aData) {
 | 
						|
  auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
 | 
						|
  for (size_t i = 0; i < aAccessibles.Length(); i++) {
 | 
						|
    AccessibleWrap* acc = aAccessibles.ElementAt(i);
 | 
						|
    if (!acc) {
 | 
						|
      MOZ_ASSERT_UNREACHABLE("Updated accessible is gone.");
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (aData.Length() == aAccessibles.Length()) {
 | 
						|
      const BatchData& data = aData.ElementAt(i);
 | 
						|
      auto bundle = acc->ToBundle(
 | 
						|
          data.State(), data.Bounds(), data.ActionCount(), data.Name(),
 | 
						|
          data.TextValue(), data.DOMNodeID(), data.Description());
 | 
						|
      infos->SetElement(i, bundle);
 | 
						|
    } else {
 | 
						|
      infos->SetElement(i, acc->ToBundle(true));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mSessionAccessibility->UpdateCachedBounds(infos);
 | 
						|
  SendWindowContentChangedEvent();
 | 
						|
}
 | 
						|
 | 
						|
void SessionAccessibility::UpdateAccessibleFocusBoundaries(
 | 
						|
    AccessibleWrap* aFirst, AccessibleWrap* aLast) {
 | 
						|
  mSessionAccessibility->UpdateAccessibleFocusBoundaries(
 | 
						|
      aFirst ? aFirst->VirtualViewID() : AccessibleWrap::kNoID,
 | 
						|
      aLast ? aLast->VirtualViewID() : AccessibleWrap::kNoID);
 | 
						|
}
 | 
						|
#undef FORWARD_ACTION_TO_ACCESSIBLE
 |