Bug 855232 - revamp UIABridge such that it queries for element state in real-time rather than relying on accessible observer events. r=bbondy
authorJim Mathies <jmathies@mozilla.com>
Fri, 05 Apr 2013 05:33:41 -0500
changeset 134555 1225c6016d106c0d9207b6aa7247fb13189e8f59
parent 134554 10bcc9c3ca1d36c5cb186dd18d29c202ece77500
child 134556 85c51fb7a1ec625e79374985e081209a6548ed9a
push idunknown
push userunknown
push dateunknown
reviewersbbondy
bugs855232
milestone23.0a1
Bug 855232 - revamp UIABridge such that it queries for element state in real-time rather than relying on accessible observer events. r=bbondy
widget/windows/winrt/UIAAccessibilityBridge.cpp
widget/windows/winrt/UIABridge.cpp
widget/windows/winrt/UIABridge.idl
widget/windows/winrt/UIABridgePrivate.h
--- a/widget/windows/winrt/UIAAccessibilityBridge.cpp
+++ b/widget/windows/winrt/UIAAccessibilityBridge.cpp
@@ -14,26 +14,16 @@
 #include "nsIAccessibleEditableText.h"
 #include "nsIPersistentProperties2.h"
 
 // generated
 #include "UIABridge.h"
 
 #include <wrl/implements.h>
 
-//#define DEBUG_BRIDGE
-#if !defined(DEBUG_BRIDGE)
-#undef LogThread
-#undef LogFunction
-#undef Log
-#define LogThread() 
-#define LogFunction()
-#define Log(...)
-#endif
-
 using namespace mozilla::a11y;
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
 using namespace Microsoft::WRL;
 
@@ -44,99 +34,22 @@ AccessibilityBridge::Observe(nsISupports
 {
   nsCOMPtr<nsIAccessibleEvent> ev = do_QueryInterface(aSubject);
   if (!ev) {
     return NS_OK;
   }
 
   uint32_t eventType = 0;
   ev->GetEventType(&eventType);
-
-  switch (eventType) {
-    case nsIAccessibleEvent::EVENT_FOCUS:
-      Log(L"EVENT_FOCUS");
-      {
-        nsCOMPtr<nsIAccessible> item;
-        ev->GetAccessible(getter_AddRefs(item));
-        Accessible* access = (Accessible*)item.get();
-        Log(L"Focus element flags: %d %d %d",
-          ((access->NativeState() & mozilla::a11y::states::EDITABLE) > 0),
-          ((access->NativeState() & mozilla::a11y::states::FOCUSABLE) > 0),
-          ((access->NativeState() & mozilla::a11y::states::READONLY) > 0)
-          );
-        bool focusable = (((access->NativeState() & mozilla::a11y::states::EDITABLE) > 0) &&
-                          ((access->NativeState() & mozilla::a11y::states::READONLY) == 0));
-
-        if (focusable) {
-          Log(L"focus item can be focused");
-          // we have a text input
-          Microsoft::WRL::ComPtr<IUIAElement> bridgePtr;
-          mBridge.As(&bridgePtr);
-          if (bridgePtr) {
-            bridgePtr->SetFocusInternal(reinterpret_cast<LONG_PTR>(item.get()));
-          }
-        } else {
-          Log(L"focus item can't have focus");
-          Microsoft::WRL::ComPtr<IUIAElement> bridgePtr;
-          mBridge.As(&bridgePtr);
-          if (bridgePtr) {
-            bridgePtr->ClearFocus();
-          }
-        }
-      }
-    break;
-    /*
-    case nsIAccessibleEvent::EVENT_SHOW:
-      Log(L"EVENT_SHOW");
-    break;
-    case nsIAccessibleEvent::EVENT_HIDE:
-      Log(L"EVENT_HIDE");
-    break;
-    case nsIAccessibleEvent::EVENT_STATE_CHANGE:
-      Log(L"EVENT_STATE_CHANGE");
-    break;
-    case nsIAccessibleEvent::EVENT_SELECTION:
-      Log(L"EVENT_SELECTION");
-    break;
-    case nsIAccessibleEvent::EVENT_SELECTION_ADD:
-      Log(L"EVENT_SELECTION_ADD");
-    break;
-    case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
-      Log(L"EVENT_SELECTION_REMOVE");
-    break;
-    case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
-      Log(L"EVENT_SELECTION_WITHIN");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
-      Log(L"EVENT_TEXT_CARET_MOVED");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_CHANGED:
-      Log(L"EVENT_TEXT_CHANGED");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
-      Log(L"EVENT_TEXT_INSERTED");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
-      Log(L"EVENT_TEXT_REMOVED");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_UPDATED:
-      Log(L"EVENT_TEXT_UPDATED");
-    break;
-    case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
-      Log(L"EVENT_TEXT_SELECTION_CHANGED");
-    break;
-    case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
-      Log(L"EVENT_SECTION_CHANGED");
-    break;
-    case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
-      Log(L"EVENT_WINDOW_ACTIVATE");
-    break;
-    */
-    default:
-    return NS_OK;
+  if (eventType == nsIAccessibleEvent::EVENT_FOCUS) {
+    Microsoft::WRL::ComPtr<IUIABridge> bridgePtr;
+    mBridge.As(&bridgePtr);
+    if (bridgePtr) {
+      bridgePtr->FocusChangeEvent();
+    }
   }
 
   return NS_OK;
 }
 
 } } }
 
 #endif // ACCESSIBILITY
--- a/widget/windows/winrt/UIABridge.cpp
+++ b/widget/windows/winrt/UIABridge.cpp
@@ -72,145 +72,195 @@ UIATextElement_CreateInstance(IRawElemen
     return S_OK;
   }
   return hr;
 }
 
 // IUIABridge
 
 HRESULT
-UIABridge::Init(IInspectable* view, IInspectable* window, LONG_PTR inner)
+UIABridge::Init(IInspectable* aView, IInspectable* aWindow, LONG_PTR aInnerPtr)
 {
   LogFunction();
-  NS_ASSERTION(view, "invalid framework view pointer");
-  NS_ASSERTION(window, "invalid window pointer");
-  NS_ASSERTION(inner, "invalid Accessible pointer");
+  NS_ASSERTION(aView, "invalid framework view pointer");
+  NS_ASSERTION(aWindow, "invalid window pointer");
+  NS_ASSERTION(aInnerPtr, "invalid Accessible pointer");
 
 #if defined(ACCESSIBILITY)
-  window->QueryInterface(IID_PPV_ARGS(&mWindow));
+  // init AccessibilityBridge and connect to accessibility
+  mAccBridge = new AccessibilityBridge();
+  if (!mAccBridge->Init(CastToUnknown(), (Accessible*)aInnerPtr)) {
+    return E_FAIL;
+  }
+
+  aWindow->QueryInterface(IID_PPV_ARGS(&mWindow));
 
   if (FAILED(UIATextElement_CreateInstance(this)))
     return E_FAIL;
 
-  // init AccessibilityBridge and connect to accessibility
-  mBridge = new AccessibilityBridge();
-  if (!mBridge->Init(CastToUnknown(), (Accessible*)inner))
-    return E_FAIL;
+  mAccessible = (Accessible*)aInnerPtr;
 
-  mConnected = true;
   return S_OK;
 #endif
   return E_FAIL;
 }
 
 HRESULT
-UIABridge::CheckFocus(int x, int y)
-{
-  LogFunction();
-  VARIANT_BOOL val = VARIANT_FALSE;
-  gElement->CheckFocus(x, y);
-  gElement->HasFocus(&val);
-  mHasFocus = (val == VARIANT_TRUE);
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
-  return S_OK;
-}
-
-HRESULT
-UIABridge::ClearFocus()
-{
-  LogFunction();
-  mHasFocus = false;
-  gElement->ClearFocus();
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
-  return S_OK;
-}
-
-HRESULT
-UIABridge::HasFocus(VARIANT_BOOL * hasFocus)
-{
-  LogFunction();
-  *hasFocus = mHasFocus ? VARIANT_TRUE : VARIANT_FALSE;
-  return S_OK;
-}
-
-HRESULT
 UIABridge::Disconnect()
 {
   LogFunction();
 #if defined(ACCESSIBILITY)
-  mBridge->Disconnect();
-  mBridge = nullptr;
+  mAccBridge->Disconnect();
+  mAccessible = nullptr;
 #endif
-  mConnected = false;
   mWindow = nullptr;
   return S_OK;
 }
 
+bool
+UIABridge::Connected()
+{
+  return !!mAccessible;
+}
+
 // IUIAElement
 
 HRESULT
 UIABridge::SetFocusInternal(LONG_PTR aAccessible)
 {
-  LogFunction();
-  mHasFocus = true;
-  ComPtr<IUIAElement> doc;
-  gElement.As(&doc);
-  if (doc)
-    doc->SetFocusInternal(aAccessible);
+  return S_OK;
+}
+
+HRESULT
+UIABridge::ClearFocus()
+{
   return S_OK;
 }
 
-bool
-UIABridge::Connected()
+static void
+DumpChildInfo(nsCOMPtr<nsIAccessible>& aChild)
+{
+#ifdef DEBUG
+  if (!aChild) {
+    return;
+  }
+  nsString str;
+  aChild->GetName(str);
+  Log(L"name: %s", str.BeginReading());
+  aChild->GetDescription(str);
+  Log(L"description: %s", str.BeginReading());
+#endif
+}
+
+static bool
+ChildHasFocus(nsCOMPtr<nsIAccessible>& aChild)
 {
-#if defined(ACCESSIBILITY)
-  return !(!mConnected || !mBridge->Connected());
-#else
-  return false;
-#endif
+  Accessible* access = (Accessible*)aChild.get();
+  Log(L"Focus element flags: %d %d %d",
+    ((access->NativeState() & mozilla::a11y::states::EDITABLE) > 0),
+    ((access->NativeState() & mozilla::a11y::states::FOCUSABLE) > 0),
+    ((access->NativeState() & mozilla::a11y::states::READONLY) > 0));
+  return (((access->NativeState() & mozilla::a11y::states::EDITABLE) > 0) &&
+           ((access->NativeState() & mozilla::a11y::states::READONLY) == 0));
+}
+
+// Accessibility calls here to let us know about focus related changes.
+// The only event we are concerned with is lost focus, so that we can
+// signal UIA that the focus on our child has been lost.
+HRESULT
+UIABridge::FocusChangeEvent()
+{
+  LogFunction();
+
+  if (!Connected()) {
+    return UIA_E_ELEMENTNOTAVAILABLE;
+  }
+
+  nsCOMPtr<nsIAccessible> child;
+  nsresult rv = mAccessible->GetFocusedChild(getter_AddRefs(child));
+  if (!child) {
+    return S_OK;
+  }
+
+  DumpChildInfo(child);
+
+  if (!ChildHasFocus(child)) {
+    ComPtr<IUIAElement> element;
+    gElement.As(&element);
+    if (!element) {
+      return S_OK;
+    }
+
+    element->ClearFocus();
+    UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
+  }
+
+  return S_OK;
 }
 
 // IRawElementProviderFragmentRoot
 
 HRESULT
 UIABridge::ElementProviderFromPoint(double x, double y, IRawElementProviderFragment ** retVal)
 {
   LogFunction();
   *retVal = nullptr;
   if (!Connected()) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
   gElement.Get()->QueryInterface(IID_PPV_ARGS(retVal));
   return S_OK;
 }
 
+// Windows calls this looking for the current focus element. Windows
+// will call here before accessible sends up any observer events through
+// the accessibility bridge, so update child focus information.
 HRESULT
 UIABridge::GetFocus(IRawElementProviderFragment ** retVal)
 {
   LogFunction();
   if (!Connected()) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
-  if (!mHasFocus)
+
+  nsCOMPtr<nsIAccessible> child;
+  nsresult rv = mAccessible->GetFocusedChild(getter_AddRefs(child));
+  if (!child) {
     return S_OK;
+  }
 
-  gElement.Get()->QueryInterface(IID_PPV_ARGS(retVal));
+  DumpChildInfo(child);
+
+  ComPtr<IUIAElement> element;
+  gElement.As(&element);
+  if (!element) {
+    return S_OK;
+  }
+
+  if (!ChildHasFocus(child)) {
+    element->ClearFocus();
+  } else {
+    element->SetFocusInternal((LONG_PTR)child.get());
+    element.Get()->QueryInterface(IID_PPV_ARGS(retVal));
+  }
+
   return S_OK;
 }
 
 // IRawElementProviderFragment
 
 HRESULT
 UIABridge::Navigate(NavigateDirection direction, IRawElementProviderFragment ** retVal)
 {
   LogFunction();
   if (!Connected()) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
   *retVal = nullptr;
+
   switch(direction) {
     case NavigateDirection_Parent:
     break;
     case NavigateDirection_NextSibling:
     break;
     case NavigateDirection_PreviousSibling:
     break;
     case NavigateDirection_FirstChild:
@@ -234,43 +284,38 @@ UIABridge::GetRuntimeId(SAFEARRAY ** ret
 
   int runtimeId[2] = { UiaAppendRuntimeId, 1 }; // always 1
   *retVal = SafeArrayCreateVector(VT_I4, 0, ARRAYSIZE(runtimeId));
   if (*retVal != nullptr) {
     for (long index = 0; index < ARRAYSIZE(runtimeId); ++index) {
       SafeArrayPutElement(*retVal, &index, &runtimeId[index]);
     }
   } else {
-      return E_OUTOFMEMORY;
+    return E_OUTOFMEMORY;
   }
   return S_OK;
 }
 
 HRESULT
 UIABridge::get_BoundingRectangle(UiaRect * retVal)
 {
   LogFunction();
   if (!Connected() || !mWindow) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
 
-  // physical pixel value = (DIP x DPI) / 96
-  FLOAT dpi;
-  HRESULT hr;
-  ComPtr<ABI::Windows::Graphics::Display::IDisplayPropertiesStatics> dispProps;
-  hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), dispProps.GetAddressOf());
-  AssertRetHRESULT(hr, hr);
-  AssertRetHRESULT(hr = dispProps->get_LogicalDpi(&dpi), hr);
-
+  // returns logical pixels
   Rect bounds;
   mWindow->get_Bounds(&bounds);
-  retVal->left = ((bounds.X * dpi) / 96.0);
-  retVal->top = ((bounds.Y * dpi) / 96.0);
-  retVal->width = ((bounds.Width * dpi) / 96.0);
-  retVal->height = ((bounds.Height * dpi) / 96.0);
+
+  // we need to return physical pixels
+  retVal->left = MetroUtils::LogToPhys(bounds.X);
+  retVal->top = MetroUtils::LogToPhys(bounds.Y);
+  retVal->width = MetroUtils::LogToPhys(bounds.Width);
+  retVal->height = MetroUtils::LogToPhys(bounds.Height);
 
   return S_OK;
 }
 
 HRESULT
 UIABridge::GetEmbeddedFragmentRoots(SAFEARRAY ** retVal)
 {
   if (!Connected()) {
@@ -283,17 +328,16 @@ UIABridge::GetEmbeddedFragmentRoots(SAFE
 
 HRESULT
 UIABridge::SetFocus()
 {
   LogFunction();
   if (!Connected()) {
     return UIA_E_ELEMENTNOTAVAILABLE;
   }
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
   return S_OK;
 }
 
 HRESULT
 UIABridge::get_FragmentRoot(IRawElementProviderFragmentRoot ** retVal)
 {
   // we are the fragment root. Our children return us for this call.
   return QueryInterface(IID_PPV_ARGS(retVal));
@@ -358,17 +402,17 @@ UIABridge::GetPropertyValue(PROPERTYID i
     case UIA_IsControlElementPropertyId:
     case UIA_IsEnabledPropertyId:
       pRetVal->boolVal = VARIANT_TRUE;
       pRetVal->vt = VT_BOOL;
       break;
 
     case UIA_HasKeyboardFocusPropertyId:
       pRetVal->vt = VT_BOOL;
-      pRetVal->boolVal = mHasFocus ? VARIANT_TRUE : VARIANT_FALSE;
+      pRetVal->boolVal = VARIANT_FALSE;
       break;
 
     case UIA_NamePropertyId:
       pRetVal->bstrVal = SysAllocString(L"MozillaAccessibilityBridge");
       pRetVal->vt = VT_BSTR;
       break;
 
     case UIA_IsPasswordPropertyId:
@@ -404,65 +448,28 @@ UIABridge::get_HostRawElementProvider(IR
 ///////////////////////////////////////////////////////////////////////////////
 // Element
 
 HRESULT
 UIATextElement::SetFocusInternal(LONG_PTR aAccessible)
 {
   LogFunction();
 #if defined(ACCESSIBILITY)
-  nsCOMPtr<nsIAccessible> item = (nsIAccessible*)aAccessible;
-  NS_ASSERTION(item, "Bad accessible pointer");
-  if (item) {
-    int32_t docX = 0, docY = 0, docWidth = 0, docHeight = 0;
-    item->GetBounds(&docX, &docY, &docWidth, &docHeight);
-    mBounds.X = (float)docX;
-    mBounds.Y = (float)docY;
-    mBounds.Width = (float)docWidth;
-    mBounds.Height = (float)docHeight;
-    SetFocus();
-  }
+  NS_ASSERTION(mAccessItem, "Bad accessible pointer");
+  mAccessItem = (nsIAccessible*)aAccessible;
   return S_OK;
 #endif
   return E_FAIL;
 }
 
-static bool
-RectContains(const Rect& rect, int x, int y)
-{
-  return ((x >= rect.X && x <= (rect.X + rect.Width) &&
-          (y >= rect.Y && y <= (rect.Y + rect.Height))));
-}
-
-HRESULT
-UIATextElement::CheckFocus(int x, int y)
-{
-  LogFunction();
-  if (RectContains(mBounds, x, y))
-    return S_OK;
-  Log(L"UIATextElement::CheckFocus CLEAR!");
-  mHasFocus = false;
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
-  return S_OK;
-}
-
 HRESULT
 UIATextElement::ClearFocus()
 {
   LogFunction();
-  mHasFocus = false;
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
-  return S_OK;
-}
-
-HRESULT
-UIATextElement::HasFocus(VARIANT_BOOL * hasFocus)
-{
-  LogFunction();
-  *hasFocus = mHasFocus ? VARIANT_TRUE : VARIANT_FALSE;
+  mAccessItem = nullptr;
   return S_OK;
 }
 
 // IRawElementProviderFragment
 
 HRESULT
 UIATextElement::Navigate(NavigateDirection direction, IRawElementProviderFragment ** retVal)
 {
@@ -499,36 +506,42 @@ UIATextElement::GetRuntimeId(SAFEARRAY *
   }
   return S_OK;
 }
 
 HRESULT
 UIATextElement::get_BoundingRectangle(UiaRect * retVal)
 {
   LogFunction();
-  retVal->left = mBounds.X;
-  retVal->top = mBounds.Y;
-  retVal->width = mBounds.Width;
-  retVal->height = mBounds.Height;
+  
+  if (!mAccessItem) {
+    return UIA_E_ELEMENTNOTAVAILABLE;
+  }
+
+  // bounds are in physical pixels
+  int32_t docX = 0, docY = 0, docWidth = 0, docHeight = 0;
+  mAccessItem->GetBounds(&docX, &docY, &docWidth, &docHeight);
+  retVal->left = (float)docX;
+  retVal->top = (float)docY;
+  retVal->width = (float)docWidth;
+  retVal->height = (float)docHeight;
   return S_OK;
 }
 
 HRESULT
 UIATextElement::GetEmbeddedFragmentRoots(SAFEARRAY ** retVal)
 {
   *retVal = nullptr;
   return S_OK;
 }
 
 HRESULT
 UIATextElement::SetFocus()
 {
   LogFunction();
-  mHasFocus = true;
-  UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
   return S_OK;
 }
 
 HRESULT
 UIATextElement::get_FragmentRoot(IRawElementProviderFragmentRoot ** retVal)
 {
   return gProviderRoot.Get()->QueryInterface(IID_PPV_ARGS(retVal));
 }
@@ -602,20 +615,31 @@ UIATextElement::GetPropertyValue(PROPERT
       pRetVal->boolVal = VARIANT_TRUE;
       pRetVal->vt = VT_BOOL;
       break;
 
     case UIA_LocalizedControlTypePropertyId:
     case UIA_LabeledByPropertyId:
       break;
 
-    case UIA_HasKeyboardFocusPropertyId:
+    case UIA_HasKeyboardFocusPropertyId: 
+    {
+      if (mAccessItem) {
+        uint32_t state, extraState;
+        if (NS_SUCCEEDED(mAccessItem->GetState(&state, &extraState)) &&
+            (state & nsIAccessibleStates::STATE_FOCUSED)) {
+          pRetVal->vt = VT_BOOL;
+          pRetVal->boolVal = VARIANT_TRUE;
+          return S_OK;
+        }
+      }
       pRetVal->vt = VT_BOOL;
-      pRetVal->boolVal = mHasFocus ? VARIANT_TRUE : VARIANT_FALSE;
+      pRetVal->boolVal = VARIANT_FALSE;
       break;
+    }
 
     case UIA_NamePropertyId:
       pRetVal->bstrVal = SysAllocString(L"MozillaDocument");
       pRetVal->vt = VT_BSTR;
       break;
 
     case UIA_IsPasswordPropertyId:
       pRetVal->vt = VT_BOOL;
--- a/widget/windows/winrt/UIABridge.idl
+++ b/widget/windows/winrt/UIABridge.idl
@@ -7,17 +7,16 @@
 import "oaidl.idl";
 import "oleacc.idl";
 import "Inspectable.idl";
 
   [uuid(343159D8-B1E9-4464-82FC-B12C7A473CF1)]
   interface IUIABridge : IInspectable {
     HRESULT Init([in] IInspectable* view, [in] IInspectable* window, [in] LONG_PTR inner);
     HRESULT Disconnect();
+    HRESULT FocusChangeEvent();
   };
 
   [uuid(2153B284-F946-4209-908D-AB8AA1FED09C)]
   interface IUIAElement : IInspectable {
     HRESULT SetFocusInternal([in] LONG_PTR accessible);
-    HRESULT CheckFocus([in] int X, [in] int y);
     HRESULT ClearFocus();
-    HRESULT HasFocus([out, retval] VARIANT_BOOL * hasFocus);
   };
--- a/widget/windows/winrt/UIABridgePrivate.h
+++ b/widget/windows/winrt/UIABridgePrivate.h
@@ -5,18 +5,21 @@
 
 #pragma once
 
 #include <windows.system.h>
 #include <windows.ui.core.h>
 #include <UIAutomation.h>
 #include <UIAutomationCore.h>
 #include <UIAutomationCoreApi.h>
-#include <wrl.h>
+
+#include "mozwrlbase.h"
 
+#include "nsCOMPtr.h"
+#include "mozilla/a11y/Accessible.h"
 #include "UIAAccessibilityBridge.h"
 
 // generated
 #include "UIABridge.h"
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
@@ -32,30 +35,26 @@ class UIABridge : public RuntimeClass<Ru
   IRawElementProviderFragment,
   IRawElementProviderFragmentRoot>
 {
   typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow;
 
   InspectableClass(L"IUIABridge", BaseTrust);
 
 public:
-  UIABridge() :
-    mConnected(false),
-    mHasFocus(false)
-  {}
+  UIABridge() {}
 
   // IUIABridge
   IFACEMETHODIMP Init(IInspectable* view, IInspectable* window, LONG_PTR inner);
   IFACEMETHODIMP Disconnect();
+  IFACEMETHODIMP FocusChangeEvent();
 
   // IUIAElement
   IFACEMETHODIMP SetFocusInternal(LONG_PTR aAccessible);
-  IFACEMETHODIMP CheckFocus(int x, int y);
   IFACEMETHODIMP ClearFocus();
-  IFACEMETHODIMP HasFocus(VARIANT_BOOL * hasFocus);
 
   // IRawElementProviderFragmentRoot
   IFACEMETHODIMP ElementProviderFromPoint(double x, double y, IRawElementProviderFragment ** retVal);
   IFACEMETHODIMP GetFocus(IRawElementProviderFragment ** retVal);
 
   // IRawElementProviderFragment
   IFACEMETHODIMP Navigate(NavigateDirection direction, IRawElementProviderFragment ** retVal);
   IFACEMETHODIMP GetRuntimeId(SAFEARRAY ** retVal);
@@ -69,46 +68,42 @@ public:
   IFACEMETHODIMP GetPatternProvider(PATTERNID iid, IUnknown * * retVal);
   IFACEMETHODIMP GetPropertyValue(PROPERTYID idProp, VARIANT * retVal );
   IFACEMETHODIMP get_HostRawElementProvider(IRawElementProviderSimple ** retVal);
 
 protected:
   bool Connected();
 
 private:
-  bool mConnected;
   Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
 #if defined(ACCESSIBILITY)
-  nsRefPtr<AccessibilityBridge> mBridge;
+  nsRefPtr<AccessibilityBridge> mAccBridge;
+  nsRefPtr<mozilla::a11y::Accessible> mAccessible;
 #endif
-  bool mHasFocus;
 };
 
 [uuid("4438135F-F624-43DE-A417-275CE7A1A0CD")]
 class UIATextElement : public RuntimeClass<RuntimeClassFlags<RuntimeClassType::WinRtClassicComMix>,
   IUIAElement,
   IRawElementProviderSimple,
   IRawElementProviderFragment,
   ITextProvider,
   IValueProvider >
 {
   typedef ABI::Windows::Foundation::Rect Rect;
 
   InspectableClass(L"UIATextElement", BaseTrust);
 
 public:
-  UIATextElement() :
-    mHasFocus(false)
-  {}
+  UIATextElement() {}
 
   // IUIAElement
   IFACEMETHODIMP SetFocusInternal(LONG_PTR aAccessible);
-  IFACEMETHODIMP CheckFocus(int x, int y);
   IFACEMETHODIMP ClearFocus();
-  IFACEMETHODIMP HasFocus(VARIANT_BOOL * hasFocus);
+  IFACEMETHODIMP FocusChangeEvent();
 
   // IRawElementProviderFragment
   IFACEMETHODIMP Navigate(NavigateDirection direction, IRawElementProviderFragment ** retVal);
   IFACEMETHODIMP GetRuntimeId(SAFEARRAY ** retVal);
   IFACEMETHODIMP get_BoundingRectangle(UiaRect * retVal);
   IFACEMETHODIMP GetEmbeddedFragmentRoots(SAFEARRAY ** retVal);
   IFACEMETHODIMP SetFocus();
   IFACEMETHODIMP get_FragmentRoot(IRawElementProviderFragmentRoot * * retVal);
@@ -133,13 +128,12 @@ public:
   IFACEMETHODIMP get_IsReadOnly(BOOL *pRetVal);
 
   void SetIndexID(int id) {
     mIndexID = id;
   }
 
 private:
   int mIndexID;
-  Rect mBounds;
-  bool mHasFocus;
+  nsCOMPtr<nsIAccessible> mAccessItem;
 };
 
 } } }