forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			465 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			465 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 "AccAttributes.h"
 | |
| #include "AccessibilityEvent.h"
 | |
| #include "HyperTextAccessible.h"
 | |
| #include "JavaBuiltins.h"
 | |
| #include "RootAccessibleWrap.h"
 | |
| #include "nsAccessibilityService.h"
 | |
| #include "nsViewManager.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);
 | |
|       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(), data.Attributes());
 | |
|       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
 | 
