tdf#131431 Move next node if pCurrentCursor hasn't moved in replaceAll
...to avoid an infinite loop
This commit addresses an issue where replacing an attribute at the
end of a paragraph with a new line results in an infinite loop.
The loop occurs because the cursor fails to advance
past the node boundary.
The root cause is an additional constraint that skips moving to the next node
when the cursor is at the beginning/end of the node. Introduced in commit
7087eb75b0, the additional check aimed to
ensure that attributes in empty lines are not skipped.
This commit adds a check to detect when pCurrentCursor does not
advance and moves it forward.
Change-Id: I18ef6d38842ee4b06a72c9ae144eb69f2353cac9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185135
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Tested-by: Jenkins
This commit is contained in:
committed by
Noel Grandin
parent
a94cf807f3
commit
17c9b49f3d
Binary file not shown.
@@ -364,6 +364,53 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTextSearch)
|
||||
pCursor->GetPointNode().GetTextNode()->GetText());
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTdf131431)
|
||||
{
|
||||
// the goal of this test is to check if replaceAll does not go into an infinite loop
|
||||
|
||||
// load document with underlined text with empty and non empty lines
|
||||
createSwDoc("tdf131431.odt");
|
||||
|
||||
// setup search for any underline text
|
||||
uno::Sequence<beans::PropertyValue> aSearchAttribute(comphelper::InitPropertySequence(
|
||||
{ { "CharUnderline", uno::Any(sal_Int32(css::awt::FontUnderline::NONE)) } }));
|
||||
|
||||
// setup replace with green highlight color
|
||||
uno::Sequence<beans::PropertyValue> aReplaceAttribute(
|
||||
comphelper::InitPropertySequence({ { "CharBackColor", uno::Any(sal_Int32(0x00FF00)) } }));
|
||||
|
||||
uno::Reference<util::XReplaceable> xReplace(mxComponent, uno::UNO_QUERY_THROW);
|
||||
uno::Reference<util::XReplaceDescriptor> xReplaceDes = xReplace->createReplaceDescriptor();
|
||||
uno::Reference<util::XPropertyReplace> xPropReplace(xReplaceDes, uno::UNO_QUERY_THROW);
|
||||
xPropReplace->setSearchAttributes(aSearchAttribute);
|
||||
xPropReplace->setReplaceAttributes(aReplaceAttribute);
|
||||
|
||||
// time out after 30 seconds if replaceAll hasn't returned
|
||||
std::atomic<bool> completed{ false };
|
||||
std::thread TimeoutThread([&completed]() {
|
||||
for (int i = 0; i < 300; ++i)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (completed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
CPPUNIT_FAIL("Test timed out after 30 seconds - infinite loop detected");
|
||||
});
|
||||
|
||||
// actual test
|
||||
sal_Int32 nReplaceCount = xReplace->replaceAll(xReplaceDes);
|
||||
|
||||
completed = true;
|
||||
TimeoutThread.join();
|
||||
|
||||
// ideally should be 9, but due to some bugs it reports more
|
||||
// CPPUNIT_ASSERT_EQUAL(sal_Int32(9), nReplaceCount);
|
||||
CPPUNIT_ASSERT_GREATEREQUAL(sal_Int32(8), nReplaceCount);
|
||||
CPPUNIT_ASSERT_LESSEQUAL(sal_Int32(14), nReplaceCount);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTdf147583_backwardSearch)
|
||||
{
|
||||
createSwDoc("tdf147583_backwardSearch.odt");
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <memory>
|
||||
#include <comphelper/lok.hxx>
|
||||
#include <editsh.hxx>
|
||||
#include <pamtyp.hxx>
|
||||
|
||||
#include <viewopt.hxx>
|
||||
#include <annotationmark.hxx>
|
||||
@@ -797,7 +798,7 @@ static sal_Int32 lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurrentCurso
|
||||
// independent from search direction: SPoint is always bigger than mark
|
||||
// if the search area is valid
|
||||
SwPosition *pSttPos = aRegion.GetMark(),
|
||||
*pEndPos = aRegion.GetPoint();
|
||||
*pEndPos = aRegion.GetPoint();
|
||||
*pSttPos = *pTmpCursor->Start();
|
||||
*pEndPos = *pTmpCursor->End();
|
||||
if( bSrchBkwrd )
|
||||
@@ -807,7 +808,7 @@ static sal_Int32 lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurrentCurso
|
||||
pPHdl.reset(new PercentHdl( aRegion ));
|
||||
|
||||
// as long as found and not at same position
|
||||
while( *pSttPos <= *pEndPos )
|
||||
while( *pSttPos <= *pEndPos )
|
||||
{
|
||||
nFndRet = rParas.DoFind(*pCurrentCursor, fnMove, aRegion, bInReadOnly, xSearchItem);
|
||||
if( 0 == nFndRet ||
|
||||
@@ -855,6 +856,20 @@ static sal_Int32 lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurrentCurso
|
||||
}
|
||||
}
|
||||
|
||||
// tdf#131431 move pCurrentCursor if it hasn't moved to avoid an infinte loop
|
||||
if( bSrchBkwrd && *pEndPos == *pCurrentCursor->Start() )
|
||||
{
|
||||
(*fnMove.fnPos)( pCurrentCursor->GetMark(), false );
|
||||
}
|
||||
else if ( !bSrchBkwrd && *pSttPos == *pCurrentCursor->End() )
|
||||
{
|
||||
(*fnMove.fnPos)( pCurrentCursor->GetPoint(), false );
|
||||
}
|
||||
|
||||
if( *pSttPos == *pEndPos )
|
||||
// in area but at the end => done
|
||||
break;
|
||||
|
||||
if( bSrchBkwrd )
|
||||
// move pEndPos in front of the found area
|
||||
*pEndPos = *pCurrentCursor->Start();
|
||||
@@ -862,10 +877,6 @@ static sal_Int32 lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurrentCurso
|
||||
// move pSttPos behind the found area
|
||||
*pSttPos = *pCurrentCursor->End();
|
||||
|
||||
if( *pSttPos == *pEndPos )
|
||||
// in area but at the end => done
|
||||
break;
|
||||
|
||||
if( !nCursorCnt && pPHdl )
|
||||
{
|
||||
pPHdl->NextPos( *aRegion.GetMark() );
|
||||
|
||||
Reference in New Issue
Block a user