Bug 1417327 part 2: Accessible handler: Cache IAccessibleTableCell row/column indexes/extents. r?marcoz draft
authorJames Teh <jteh@mozilla.com>
Thu, 16 Nov 2017 11:47:28 +1000
changeset 698860 6ff52a3d0294b1a1319f9670a5aa3705d3636a06
parent 698859 484b7bc50e02a7d9a67b6831ba5b319f7990b26e
child 698895 b462b3748944994c2774707e5d790630eff3d720
child 699030 a248449e6ca0c98bfd77a6907ad92f96f023bbab
push id89377
push userbmo:jteh@mozilla.com
push dateThu, 16 Nov 2017 05:20:32 +0000
reviewersmarcoz
bugs1417327
milestone59.0a1
Bug 1417327 part 2: Accessible handler: Cache IAccessibleTableCell row/column indexes/extents. r?marcoz MozReview-Commit-ID: 8hMzyJZ5zFI
accessible/ipc/win/HandlerProvider.cpp
accessible/ipc/win/handler/AccessibleHandler.cpp
accessible/ipc/win/handler/AccessibleHandler.h
accessible/ipc/win/handler/HandlerData.idl
--- a/accessible/ipc/win/HandlerProvider.cpp
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -358,16 +358,31 @@ HandlerProvider::BuildDynamicIA2Data(Dyn
     getter_AddRefs(action));
   if (SUCCEEDED(hr)) {
     hr = action->nActions(&aOutIA2Data->mNActions);
     if (FAILED(hr)) {
       return;
     }
   }
 
+  RefPtr<IAccessibleTableCell> cell;
+  // It is not an error if this fails.
+  hr = mTargetUnk.get()->QueryInterface(IID_IAccessibleTableCell,
+    getter_AddRefs(cell));
+  if (SUCCEEDED(hr)) {
+    hr = cell->get_rowColumnExtents(&aOutIA2Data->mRowIndex,
+                                    &aOutIA2Data->mColumnIndex,
+                                    &aOutIA2Data->mRowExtent,
+                                    &aOutIA2Data->mColumnExtent,
+                                    &aOutIA2Data->mCellIsSelected);
+    if (FAILED(hr)) {
+      return;
+    }
+  }
+
   // NB: get_uniqueID should be the final property retrieved in this method,
   // as its presence is used to determine whether the rest of this data
   // retrieval was successful.
   hr = target->get_uniqueID(&aOutIA2Data->mUniqueId);
 }
 
 void
 HandlerProvider::ClearDynamicIA2Data(DynamicIA2Data& aData)
--- a/accessible/ipc/win/handler/AccessibleHandler.cpp
+++ b/accessible/ipc/win/handler/AccessibleHandler.cpp
@@ -62,16 +62,17 @@ AccessibleHandler::Create(IUnknown* aOut
 }
 
 AccessibleHandler::AccessibleHandler(IUnknown* aOuter, HRESULT* aResult)
   : mscom::Handler(aOuter, aResult)
   , mDispatch(nullptr)
   , mIA2PassThru(nullptr)
   , mServProvPassThru(nullptr)
   , mIAHyperlinkPassThru(nullptr)
+  , mIATableCellPassThru(nullptr)
   , mCachedData()
   , mCacheGen(0)
 {
   RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetOrCreateSingleton());
   MOZ_ASSERT(ctl);
   if (!ctl) {
     if (aResult) {
       *aResult = E_UNEXPECTED;
@@ -130,16 +131,39 @@ AccessibleHandler::ResolveIAHyperlink()
     // (see comments in AccesssibleHandler.h)
     mIAHyperlinkPassThru->Release();
   }
 
   return hr;
 }
 
 HRESULT
+AccessibleHandler::ResolveIATableCell()
+{
+  if (mIATableCellPassThru) {
+    return S_OK;
+  }
+
+  RefPtr<IUnknown> proxy(GetProxy());
+  if (!proxy) {
+    return E_UNEXPECTED;
+  }
+
+  HRESULT hr = proxy->QueryInterface(IID_IAccessibleTableCell,
+    reinterpret_cast<void**>(&mIATableCellPassThru));
+  if (SUCCEEDED(hr)) {
+    // mIATableCellPassThru is a weak reference
+    // (see comments in AccesssibleHandler.h)
+    mIATableCellPassThru->Release();
+  }
+
+  return hr;
+}
+
+HRESULT
 AccessibleHandler::MaybeUpdateCachedData()
 {
   RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetOrCreateSingleton());
   if (!ctl) {
     return E_OUTOFMEMORY;
   }
 
   uint32_t gen = ctl->GetCacheGen();
@@ -242,16 +266,23 @@ AccessibleHandler::QueryHandlerInterface
 
   if (aIid == IID_IAccessibleAction || aIid == IID_IAccessibleHyperlink) {
     RefPtr<IAccessibleHyperlink> iaLink(
       static_cast<IAccessibleHyperlink*>(this));
     iaLink.forget(aOutInterface);
     return S_OK;
   }
 
+  if (aIid == IID_IAccessibleTableCell) {
+    RefPtr<IAccessibleTableCell> iaCell(
+      static_cast<IAccessibleTableCell*>(this));
+    iaCell.forget(aOutInterface);
+    return S_OK;
+  }
+
   if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
       aIid == IID_IAccessibleHypertext2) {
     RefPtr<IAccessibleHypertext2> textTearoff(new AccessibleTextTearoff(this));
     textTearoff.forget(aOutInterface);
     return S_OK;
   }
 
   if (aIid == IID_IProvideClassInfo) {
@@ -1311,16 +1342,182 @@ AccessibleHandler::get_valid(boolean* va
 {
   HRESULT hr = ResolveIAHyperlink();
   if (FAILED(hr)) {
     return hr;
   }
   return mIAHyperlinkPassThru->get_valid(valid);
 }
 
+/*** IAccessibleTableCell ***/
+
+HRESULT
+AccessibleHandler::get_columnExtent(long* nColumnsSpanned)
+{
+  if (!nColumnsSpanned) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_columnExtent(nColumnsSpanned);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mColumnExtent, *nColumnsSpanned);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_columnHeaderCells(IUnknown*** cellAccessibles,
+                                     long* nColumnHeaderCells)
+{
+  HRESULT hr = ResolveIATableCell();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return mIATableCellPassThru->get_columnHeaderCells(cellAccessibles,
+             nColumnHeaderCells);
+}
+
+HRESULT
+AccessibleHandler::get_columnIndex(long* columnIndex)
+{
+  if (!columnIndex) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_columnIndex(columnIndex);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mColumnIndex, *columnIndex);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_rowExtent(long* nRowsSpanned)
+{
+  if (!nRowsSpanned) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_rowExtent(nRowsSpanned);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mRowExtent, *nRowsSpanned);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_rowHeaderCells(IUnknown*** cellAccessibles,
+                                  long* nRowHeaderCells)
+{
+  HRESULT hr = ResolveIATableCell();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return mIATableCellPassThru->get_rowHeaderCells(cellAccessibles,
+             nRowHeaderCells);
+}
+
+HRESULT
+AccessibleHandler::get_rowIndex(long* rowIndex)
+{
+  if (!rowIndex) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_rowIndex(rowIndex);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mRowIndex, *rowIndex);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_isSelected(boolean* isSelected)
+{
+  if (!isSelected) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_isSelected(isSelected);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mCellIsSelected, *isSelected);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_rowColumnExtents(long* row, long* column,
+                                     long* rowExtents, long* columnExtents,
+                                     boolean* isSelected)
+{
+  if (!row || !column || !rowExtents || !columnExtents || !isSelected) {
+    return E_INVALIDARG;
+  }
+
+  if (!HasPayload()) {
+    HRESULT hr = ResolveIATableCell();
+    if (FAILED(hr)) {
+      return hr;
+    }
+    return mIATableCellPassThru->get_rowColumnExtents(row, column, rowExtents,
+               columnExtents, isSelected);
+  }
+
+  BEGIN_CACHE_ACCESS;
+  GET_FIELD(mRowIndex, *row);
+  GET_FIELD(mColumnIndex, *column);
+  GET_FIELD(mRowExtent, *rowExtents);
+  GET_FIELD(mColumnExtent, *columnExtents);
+  GET_FIELD(mCellIsSelected, *isSelected);
+  return S_OK;
+}
+
+HRESULT
+AccessibleHandler::get_table(IUnknown** table)
+{
+  HRESULT hr = ResolveIATableCell();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return mIATableCellPassThru->get_table(table);
+}
+
 } // namespace a11y
 } // namespace mozilla
 
 extern "C" HRESULT __stdcall
 ProxyDllCanUnloadNow();
 
 extern "C" HRESULT __stdcall
 DllCanUnloadNow()
--- a/accessible/ipc/win/handler/AccessibleHandler.h
+++ b/accessible/ipc/win/handler/AccessibleHandler.h
@@ -31,31 +31,33 @@ import NEWEST_IA2_IDL;
 #include "HandlerData.h"
 
 #include <windows.h>
 
 #if !defined(MOZILLA_INTERNAL_API)
 
 #include "Accessible2_3.h"
 #include "AccessibleHyperlink.h"
+#include "AccessibleTableCell.h"
 #include "Handler.h"
 #include "mozilla/mscom/StructStream.h"
 #include "mozilla/UniquePtr.h"
 
 #include <ocidl.h>
 #include <servprov.h>
 
 namespace mozilla {
 namespace a11y {
 
 class AccessibleHandler final : public mscom::Handler
                               , public NEWEST_IA2_INTERFACE
                               , public IServiceProvider
                               , public IProvideClassInfo
                               , public IAccessibleHyperlink
+                              , public IAccessibleTableCell
 {
 public:
   static HRESULT Create(IUnknown* aOuter, REFIID aIid, void** aOutInterface);
 
   // mscom::Handler
   HRESULT QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid,
                                 void** aOutInterface) override;
   HRESULT ReadHandlerPayload(IStream* aStream, REFIID aIid) override;
@@ -168,23 +170,39 @@ public:
 
   // IAccessibleHyperlink
   STDMETHODIMP get_anchor(long index, VARIANT* anchor) override;
   STDMETHODIMP get_anchorTarget(long index, VARIANT* anchorTarget) override;
   STDMETHODIMP get_startIndex(long* index) override;
   STDMETHODIMP get_endIndex(long* index) override;
   STDMETHODIMP get_valid(boolean* valid) override;
 
+  // IAccessibleTableCell
+  STDMETHODIMP get_columnExtent(long* nColumnsSpanned) override;
+  STDMETHODIMP get_columnHeaderCells(IUnknown*** cellAccessibles,
+                                     long* nColumnHeaderCells) override;
+  STDMETHODIMP get_columnIndex(long* columnIndex) override;
+  STDMETHODIMP get_rowExtent(long* nRowsSpanned) override;
+  STDMETHODIMP get_rowHeaderCells(IUnknown*** cellAccessibles,
+                                  long* nRowHeaderCells) override;
+  STDMETHODIMP get_rowIndex(long* rowIndex) override;
+  STDMETHODIMP get_isSelected(boolean* isSelected) override;
+  STDMETHODIMP get_rowColumnExtents(long* row, long* column,
+                                    long* rowExtents, long* columnExtents,
+                                    boolean* isSelected) override;
+  STDMETHODIMP get_table(IUnknown** table) override;
+
 private:
   AccessibleHandler(IUnknown* aOuter, HRESULT* aResult);
   virtual ~AccessibleHandler();
 
   HRESULT ResolveIA2();
   HRESULT ResolveIDispatch();
   HRESULT ResolveIAHyperlink();
+  HRESULT ResolveIATableCell();
   HRESULT MaybeUpdateCachedData();
 
   RefPtr<IUnknown>                  mDispatchUnk;
   /**
    * Handlers aggregate their proxies. This means that their proxies delegate
    * their IUnknown implementation to us.
    *
    * mDispatchUnk and the result of Handler::GetProxy() are both strong
@@ -201,16 +219,17 @@ private:
    *
    * It is safe for us to use these raw pointers because the aggregated
    * objects's lifetimes are proper subsets of our own lifetime.
    */
   IDispatch*                        mDispatch;         // weak
   NEWEST_IA2_INTERFACE*             mIA2PassThru;      // weak
   IServiceProvider*                 mServProvPassThru; // weak
   IAccessibleHyperlink*             mIAHyperlinkPassThru; // weak
+  IAccessibleTableCell*             mIATableCellPassThru; // weak
   IA2Payload                        mCachedData;
   UniquePtr<mscom::StructToStream>  mSerializer;
   uint32_t                          mCacheGen;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/ipc/win/handler/HandlerData.idl
+++ b/accessible/ipc/win/handler/HandlerData.idl
@@ -46,16 +46,22 @@ typedef struct _DynamicIA2Data
   BSTR              mName;
   BSTR              mDescription;
   BSTR              mDefaultAction;
   BSTR              mValue;
   BSTR              mAttributes;
   IA2Locale         mIA2Locale;
   // From IAccessibleAction
   long              mNActions;
+  // From IAccessibleTableCell
+  long              mRowIndex;
+  long              mColumnIndex;
+  long              mRowExtent;
+  long              mColumnExtent;
+  boolean           mCellIsSelected;
   // From IAccessible2
   long              mUniqueId;
 } DynamicIA2Data;
 
 interface IGeckoBackChannel;
 
 // We define different CLSIDs and IIDs depending on channel and officiality.
 // This prevents handlers from installing overtop one another when multiple