sfx2/source/control/bindings.cxx | 1 + sw/qa/extras/unowriter/unowriter.cxx | 21 +++++++++++++++++++++ sw/source/core/unocore/unoobj.cxx | 12 +++++++++--- vcl/win/dtrans/MtaOleClipb.cxx | 35 +++++++++++++++++++++-------------- vcl/win/dtrans/WinClipboard.cxx | 14 +++++++++----- 5 files changed, 61 insertions(+), 22 deletions(-)
New commits: commit 1c52e94b2d926875d1a108c54988dbcb2dc9d017 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed Mar 20 16:24:07 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Mar 21 17:51:23 2024 +0100 tdf#160278: restore cursor bounds properly The passed string length is not a correct measure of how many steps should the selection expand in the resulting text: the cursor goes over glyphs, not over UTF-16 code units. Thus, it's easier to store the position prior to insertion, and restore it from the indexes. Change-Id: I1d592ff30199007ba3a99d7e1a6d2db2da35f1cb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165056 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/qa/extras/unowriter/unowriter.cxx b/sw/qa/extras/unowriter/unowriter.cxx index c4bcbb7f5dd6..a11e928e8c1d 100644 --- a/sw/qa/extras/unowriter/unowriter.cxx +++ b/sw/qa/extras/unowriter/unowriter.cxx @@ -1200,6 +1200,27 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf129841) CPPUNIT_ASSERT_EQUAL(aRefColor, aColor); } +CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf160278) +{ + createSwDoc(); + auto xTextDocument(mxComponent.queryThrow<css::text::XTextDocument>()); + auto xText(xTextDocument->getText()); + xText->setString(u"123"_ustr); + CPPUNIT_ASSERT_EQUAL(u"123"_ustr, xText->getString()); + auto xCursor = xText->createTextCursorByRange(xText->getEnd()); + xCursor->goLeft(1, true); + CPPUNIT_ASSERT_EQUAL(u"3"_ustr, xCursor->getString()); + // Insert an SMP character U+1f702 (so it's two UTF-16 code units, 0xd83d 0xdf02): + xCursor->setString(u"🜂"_ustr); + // Without the fix, the replacement would expand the cursor one too many characters to the left, + // and the cursor text would become "2🜂", failing the next test: + CPPUNIT_ASSERT_EQUAL(u"🜂"_ustr, xCursor->getString()); + xCursor->setString(u"test"_ustr); + CPPUNIT_ASSERT_EQUAL(u"test"_ustr, xCursor->getString()); + // This test would fail, too; the text would be "1test": + CPPUNIT_ASSERT_EQUAL(u"12test"_ustr, xText->getString()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index 3c5f34f1940a..69fa9d3be300 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -752,13 +752,19 @@ void SwXTextCursor::DeleteAndInsert(std::u16string_view aText, } if(nTextLen) { + // Store node and content indexes prior to insertion: to select the inserted text, + // we need to account for possible surrogate pairs, combining characters, etc.; it + // is easier to just restore the correct position from the indexes. + const auto start = pCurrent->Start(); + const auto nodeIndex = start->GetNodeIndex(); + const auto contentIndex = start->GetContentIndex(); const bool bSuccess( SwUnoCursorHelper::DocInsertStringSplitCR( - rDoc, *pCurrent, aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints))); + rDoc, SwPaM(*start, pCurrent), aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints))); OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." ); - SwUnoCursorHelper::SelectPam(*pUnoCursor, true); - pCurrent->Left(aText.size()); + pCurrent->SetMark(); + pCurrent->GetPoint()->Assign(nodeIndex, contentIndex); } pCurrent = pCurrent->GetNext(); } while (pCurrent != pUnoCursor); commit f4ade8244bf984712e65c2eb82cf3319d2679eeb Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Mar 21 10:01:36 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Mar 21 17:51:14 2024 +0100 Downgrade sfx::SfxBindings aAutoTimer to an idle This is a follow-up to commit f45402ae3f5241b460d9f1dcb04183893e1f91f7 (Fix a spurious JunitTest_sw_unoapi_3 failure, 2024-03-15). As noted by Stephan, the failure persisted; it was because the update of slots also accessed the changing document model, and it wasn't prevented by IdlesLockGuard, because aAutoTimer had a default priority. Change-Id: Iad8dfadcd35d9611e61e4c011511d6155a343f58 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165090 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx index 549a9fc45e67..458ef0431fc7 100644 --- a/sfx2/source/control/bindings.cxx +++ b/sfx2/source/control/bindings.cxx @@ -148,6 +148,7 @@ SfxBindings::SfxBindings() // all caches are valid (no pending invalidate-job) // create the list of caches + pImpl->aAutoTimer.SetPriority(TaskPriority::HIGH_IDLE); pImpl->aAutoTimer.SetInvokeHandler( LINK(this, SfxBindings, NextJob) ); } commit 7132e2975c354dbd29775c7167c324b53032bca6 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Mar 21 10:00:44 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Mar 21 17:51:09 2024 +0100 Only hold clipboard mutexes to obtain the values, to avoid deadlocks Change-Id: I36a2f6e444b8a5397b96d3cba475a8d06ea86459 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165089 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/vcl/win/dtrans/MtaOleClipb.cxx b/vcl/win/dtrans/MtaOleClipb.cxx index fcf16df1adf1..a62f4a1c0c72 100644 --- a/vcl/win/dtrans/MtaOleClipb.cxx +++ b/vcl/win/dtrans/MtaOleClipb.cxx @@ -707,25 +707,32 @@ unsigned __stdcall CMtaOleClipboard::clipboardChangedNotifierThreadProc(void* pP MsgWaitForMultipleObjects(2, pInst->m_hClipboardChangedNotifierEvents, false, INFINITE, QS_ALLINPUT | QS_ALLPOSTMESSAGE); - std::unique_lock aGuard2( pInst->m_ClipboardChangedEventCountMutex ); - - if ( pInst->m_ClipboardChangedEventCount > 0 ) + bool hadEvents; { - pInst->m_ClipboardChangedEventCount--; - if ( 0 == pInst->m_ClipboardChangedEventCount ) - ResetEvent( pInst->m_hClipboardChangedEvent ); - - aGuard2.unlock( ); + std::unique_lock aGuard2(pInst->m_ClipboardChangedEventCountMutex); + hadEvents = pInst->m_ClipboardChangedEventCount > 0; + if (hadEvents) + { + pInst->m_ClipboardChangedEventCount--; + if (0 == pInst->m_ClipboardChangedEventCount) + ResetEvent(pInst->m_hClipboardChangedEvent); + } + } - // nobody should touch m_pfncClipViewerCallback while we do - std::unique_lock aClipViewerGuard( pInst->m_pfncClipViewerCallbackMutex ); + if (hadEvents) + { + LPFNC_CLIPVIEWER_CALLBACK_t pClipViewerCallback; + { + // nobody should touch m_pfncClipViewerCallback while we do + // but don't hold the mutex while calling the callback itself: it could deadlock + std::unique_lock aClipViewerGuard(pInst->m_pfncClipViewerCallbackMutex); + pClipViewerCallback = pInst->m_pfncClipViewerCallback; + } // notify all clipboard listener - if ( pInst->m_pfncClipViewerCallback ) - pInst->m_pfncClipViewerCallback( ); + if (pClipViewerCallback) + pClipViewerCallback(); } - else - aGuard2.unlock( ); } return 0; diff --git a/vcl/win/dtrans/WinClipboard.cxx b/vcl/win/dtrans/WinClipboard.cxx index 1a8eaea151b5..5f46bebecfd2 100644 --- a/vcl/win/dtrans/WinClipboard.cxx +++ b/vcl/win/dtrans/WinClipboard.cxx @@ -370,13 +370,17 @@ void CWinClipboard::unregisterClipboardViewer() { m_MtaOleClipboard.registerClip void WINAPI CWinClipboard::onClipboardContentChanged() { - osl::MutexGuard aGuard(s_aClipboardSingletonMutex); + rtl::Reference<CWinClipboard> pWinClipboard; + { + // Only hold the mutex to obtain a safe reference to the impl, to avoid deadlock + osl::MutexGuard aGuard(s_aClipboardSingletonMutex); + pWinClipboard.set(s_pCWinClipbImpl); + } - // reassociation to instance through static member - if (nullptr != s_pCWinClipbImpl) + if (pWinClipboard) { - s_pCWinClipbImpl->m_foreignContent.clear(); - s_pCWinClipbImpl->notifyAllClipboardListener(); + pWinClipboard->m_foreignContent.clear(); + pWinClipboard->notifyAllClipboardListener(); } }