sw/source/core/access/accpara.cxx | 2 - winaccessibility/source/UAccCOM/MAccessible.cxx | 28 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-)
New commits: commit 56cf4d70bf09b027df31d8f4fbcad4830a88d454 Author: Michael Stahl <[email protected]> AuthorDate: Thu Nov 27 20:34:38 2025 +0100 Commit: Michael Stahl <[email protected]> CommitDate: Tue Dec 2 17:41:45 2025 +0100 tdf#167362 sw: fix footnote hang with JAWS When moving the cursor to a line with a footnote, JAWS tries to retrieve the text attributes, gets an E_FAIL, but never gives up trying again. The problem is that some entirely undocumented magic number is stuffed into an uno::Any as `long` but the "CharEscapement" property is actually `short` and thus reading the property in AccessibleTextAttributeHelper::ConvertUnoToIAccessible2TextAttributes() throws and this is caught by CAccTextBase::get_attributes() and E_FAIL is returned. > vcllo.dll!o3tl::doAccess<short>(const com::sun::star::uno::Any & any) Line 284 vcllo.dll!AccessibleTextAttributeHelper::ConvertUnoToIAccessible2TextAttributes(const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & rUnoAttributes, IA2AttributeType eAttributeType) Line 271 vcllo.dll!AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(com::sun::star::uno::Reference<com::sun::star::accessibility::XAccessibleText> xText, IA2AttributeType eAttributeType, long nOffset, long & rStartOffset, long & rEndOffset) Line 346 UAccCOM.dll!CAccTextBase::get_attributes(long offset, long * startOffset, long * endOffset, wchar_t * * textAttributes) Line 145 UAccCOM.dll!CAccText::get_attributes(long offset, long * startOffset, long * endOffset, wchar_t * * textAttributes) Line 54 FSDomNodeSymphony.dll!00007ff93f0fea12() ^ JAWS Change-Id: I6c487f9d2db462b787034df3d5ba2f2822d14746 (cherry picked from commit 776662481583935ca148930de1e91ea499c53b3a) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194736 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Stephan Bergmann <[email protected]> (cherry picked from commit fac7e501d77a009fcd0bb1796a3ce8cee0c5e1f7) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194869 Tested-by: Michael Stahl <[email protected]> diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx index 67578811a996..f6252ac87ce4 100644 --- a/sw/source/core/access/accpara.cxx +++ b/sw/source/core/access/accpara.cxx @@ -2008,7 +2008,7 @@ void SwAccessibleParagraph::_correctValues( const sal_Int32 nIndex, { if ( GetPortionData().IsIndexInFootnode(nIndex) ) { - rValue.Value <<= sal_Int32(101); + rValue.Value <<= sal_Int16(101); } continue; } commit aa45dfe5e208efb41e1fdac7c72faf7242f5ac99 Author: Michael Stahl <[email protected]> AuthorDate: Thu Nov 27 16:52:12 2025 +0100 Commit: Michael Stahl <[email protected]> CommitDate: Tue Dec 2 17:41:42 2025 +0100 tdf#168897 winaccessibility: fix JAWS crash with CAccTable stack: UAccCOM.dll!ATL::CComObjectRootBase::OuterAddRef() Line 2631 UAccCOM.dll!ATL::CComContainedObject<CAccImage>::AddRef() Line 3719 AccEventCache.dll!00007ffd2039be28() AccEventCache.dll!00007ffd20355677() AccEventCache.dll!00007ffd20346d41() AccEventCache.dll!00007ffd20347f9a() AccEventCache.dll!00007ffd20338ba2() AccEventCache.dll!00007ffd20380dd8() AccEventCache.dll!00007ffd2037fd7b() AccEventCache.dll!00007ffd2037f7ee() AccEventCache.dll!00007ffd2037d9e6() AccEventCache.dll!00007ffd2037d07f() ^ JAWS GlobalHooksDispatcher.dll!00007ffd214daed4() GlobalHooksDispatcher.dll!00007ffd214d8d84() user32.dll!00007ffd492068ac() ntdll.dll!00007ffd4ae71424() win32u.dll!NtUserNotifyWinEvent() winaccessibility.dll!AccObjectWinManager::NotifyAccEvent(com::sun::star::accessibility::XAccessible * pXAcc, UnoMSAAEvent eEvent) Line 182 ^ selfAccObj looks very dead here but that is a red herring! winaccessibility.dll!AccContainerEventListener::FireStateFocusedChange(bool enable) Line 351 winaccessibility.dll!AccContainerEventListener::SetComponentState(__int64 state, bool enable) Line 178 winaccessibility.dll!AccParagraphEventListener::SetComponentState(__int64 state, bool enable) Line 123 winaccessibility.dll!AccContainerEventListener::HandleStateChangedEvent(com::sun::star::uno::Any oldValue, com::sun::star::uno::Any newValue) Line 106 winaccessibility.dll!AccContainerEventListener::notifyEvent(const com::sun::star::accessibility::AccessibleEventObject & aEvent) Line 72 winaccessibility.dll!AccParagraphEventListener::notifyEvent(const com::sun::star::accessibility::AccessibleEventObject & aEvent) Line 77 comphelper.dll!comphelper::AccessibleEventNotifier::addEvent(const unsigned long _nClient, const com::sun::star::accessibility::AccessibleEventObject & _rEvent) Line 256 swlo.dll!SwAccessibleContext::FireAccessibleEvent(com::sun::star::accessibility::AccessibleEventObject & rEvent) Line 457 swlo.dll!SwAccessibleContext::FireStateChangedEvent(__int64 nState, bool bNewState) Line 478 swlo.dll!SwAccessibleParagraph::InvalidateFocus_() Line 397 swlo.dll!SwAccessibleContext::InvalidateFocus() Line 1314 swlo.dll!SwAccessibleMap::InvalidateFocus() Line 2695 swlo.dll!SwViewShell::InvalidateAccessibleFocus() Line 2597 swlo.dll!SwEditWin::GetFocus() Line 5569 vcllo.dll!vcl::Window::CompatGetFocus() Line 3891 vcllo.dll!vcl::Window::ImplGrabFocus(GetFocusFlags nFlags) Line 385 vcllo.dll!vcl::Window::GrabFocus() Line 2983 sfxlo.dll!SfxFrame::GrabFocusOnComponent_Impl() Line 650 The problem is quite simply that CMAccessible::SmartQI() returns a pointer that is the result of querying the newly created COM aggregation for IID_IUnknown instead of the requested `iid` interface. Apparently the wrong result happens to work in many cases, but the CAccTable actually has 2 interfaces IAccessibleTable and IAccessibleTable2, and the COM aggravation for IAccessibleTable2 is the one that crashes; in this case the correct pointer is an offset of 8 to the start of CAccTable, while in the working cases there is no offset. So likely the bug was introduced by commits 3b86569fcba210eb6570fabef7ff8abf6aff91f0 and d0e8e6e3cd51736583603e37f0ba2ff7bdf29f5c but only started to crash with 839dbf9ecf9f8fbec7de983d1a2e16d7de6f868c. Change-Id: I7c7d295c8032b95fe7f64b8da4dd9bc3212563f9 (cherry picked from commit 9502a9f76731afa0f5105e6d79b069222677f88d) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194727 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Stephan Bergmann <[email protected]> (cherry picked from commit 7dc79ac270e855f58d24b2dedebe06a209a4bc66) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194868 Tested-by: Michael Stahl <[email protected]> diff --git a/winaccessibility/source/UAccCOM/MAccessible.cxx b/winaccessibility/source/UAccCOM/MAccessible.cxx index a6454f3c39f8..9d4271f41988 100644 --- a/winaccessibility/source/UAccCOM/MAccessible.cxx +++ b/winaccessibility/source/UAccCOM/MAccessible.cxx @@ -2340,15 +2340,31 @@ HRESULT WINAPI CMAccessible::SmartQI(void* /*pv*/, REFIID iid, void** ppvObject) assert(hr == S_OK); if(hr == S_OK) { + // does it matter which IID was used to query before it is + // put into the map? probably not, and currently + // QueryInterface is called after lookup anyway... m_containedObjects.emplace(*rEntry.piid, static_cast<IUnknown*>(*ppvObject)); + // very nonobvious: this QI only succeeds on an IID_IUnknown + // pointer because that one points directly to the + // CComAggObject whereas the other-IID ones point into + // CAcc* objects and end up forward back here to SmartQI + // which firstly doesn't know IID_IUNOXWrapper and secondly + // it would be useless to return a new instance for it, it + // *must* be the same CAcc* instance that was just created. + // Also, it's not possible to get the CAccTable out of the + // CComAggObject because it is private. + // However for the aggregated objects this here is also the + // *only* place where this interface is called; every other + // call is on a non-aggregated object - so it's sufficient + // if it works once right after construction. IUNOXWrapper* wrapper = nullptr; static_cast<IUnknown*>(*ppvObject)->QueryInterface(IID_IUNOXWrapper, reinterpret_cast<void**>(&wrapper)); - if(wrapper) - { - wrapper->put_XInterface( - reinterpret_cast<hyper>(m_xAccessible.get())); - wrapper->Release(); - } + assert(wrapper); // every map entry implements it currently + wrapper->put_XInterface( + reinterpret_cast<hyper>(m_xAccessible.get())); + wrapper->Release(); + // ppvObject is IID_IUnknown - Query for requested target! + static_cast<IUnknown*>(*ppvObject)->QueryInterface(iid, ppvObject); return S_OK; } }
