[Libreoffice-commits] core.git: Branch 'feature/drawinglayercore' - 169 commits - accessibility/source basctl/source basegfx/source basegfx/test basic/source bin/check-missing-export-asserts.py canvas/source chart2/qa chart2/source comphelper/source compilerplugins/clang configure.ac connectivity/source cppcanvas/source cui/source dbaccess/source desktop/qa desktop/source download.lst drawinglayer/CppunitTest_drawinglayer_border.mk drawinglayer/inc drawinglayer/Library_drawinglayercore.mk drawinglayer/Library_drawinglayer.mk drawinglayer/Module_drawinglayer.mk drawinglayer/source dtrans/source editeng/source emfio/CppunitTest_emfio_emf_test.mk emfio/Library_emfio.mk emfio/source extensions/source extensions/test external/neon external/nss extras/source filter/Library_pdffilter.mk filter/Library_svgfilter.mk filter/source formula/source framework/inc framework/source helpcontent2 hwpfilter/source i18nlangtag/source i18npool/inc i18npool/source i18nutil/source icon-themes/colibre icon-themes/colibr e_svg include/basegfx include/comphelper include/drawinglayer include/editeng include/formula include/i18nlangtag include/o3tl include/svl include/svx include/tools include/vcl include/xmloff libreofficekit/qa linguistic/source lotuswordpro/source o3tl/qa offapi/com offapi/UnoApi_offapi.mk oox/source reportdesign/source Repository.mk sal/osl sal/rtl sax/source sc/CppunitTest_sc_ucalc.mk sc/inc sc/Library_sc.mk sc/qa sc/source sc/uiconfig sd/CppunitTest_sd_tiledrendering.mk sd/CppunitTest_sd_uimpress.mk sdext/source sd/inc sd/IwyuFilter_sd.yaml sd/Library_sd.mk sd/qa sd/source sfx2/Library_sfx.mk sfx2/source slideshow/source solenv/bin solenv/gbuild starmath/source stoc/source store/source svgio/CppunitTest_svgio.mk svgio/Library_svgio.mk svgio/source svl/qa svl/source svtools/source svx/CppunitTest_svx_unit.mk svx/Library_svxcore.mk svx/Library_svx.mk svx/source sw/CppunitTest_sw_uwriter.mk sw/inc sw/Library_sw.mk sw/Library_swui.mk sw/qa sw/source test/source toolkit/source tools/q a ucb/source UnoControls/source unotools/source vcl/CppunitTest_vcl_graphic_test.mk vcl/inc vcl/Library_vcl.mk vcl/osx vcl/qa vcl/quartz vcl/source vcl/unx writerfilter/source xmloff/inc xmloff/source xmloff/util

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Mon Jun 1 06:15:46 UTC 2020


Rebased ref, commits from common ancestor:
commit 5fe2f308b99bec00524a6db708d0612f4821f686
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 21:59:34 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:52 2020 +0200

    sd: allow to change the search string between searches
    
    Before this was missing, so even with a different search string,
    it still searched using the old string, which was a bug.
    
    Change-Id: I1655cb421e216e30ae593aabd3ead3a2d5c06299

diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 584d7b253994..065c53df7f1a 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -827,13 +827,19 @@ bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelecti
 
             if (mpImpl->mbCurrentIsVectorGraphic)
             {
+                OUString const & rString = mpSearchItem->GetSearchString();
                 bool bBackwards = mpSearchItem->GetBackward();
 
-                bool bResult = false;
-                if (bBackwards)
-                    bResult = mpImpl->mpVectorGraphicSearch->previous();
-                else
-                    bResult = mpImpl->mpVectorGraphicSearch->next();
+                SearchStartPosition eSearchStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin;
+                bool bResult = mpImpl->mpVectorGraphicSearch->search(rString, eSearchStartPosition);
+
+                if (bResult)
+                {
+                    if (bBackwards)
+                        bResult = mpImpl->mpVectorGraphicSearch->previous();
+                    else
+                        bResult = mpImpl->mpVectorGraphicSearch->next();
+                }
 
                 if (bResult)
                 {
commit 82edb60398ab13e713d613619c88e427815d3ecd
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 14:03:36 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:51 2020 +0200

    vcl: VectorGraphicSearch - support changing search string
    
    Initial implementation only allowed to set the search string once.
    This change allows to change the search string and still retain
    the last position of a found string, so the search continues
    from this positon forward or backwards. This mimicks how we search
    through the GUI (which is the main use for this functionallity
    anyway).
    
    Change-Id: I8a7aee4b6b6525f483f105feaa1f83c4a0ad9594

diff --git a/include/vcl/VectorGraphicSearch.hxx b/include/vcl/VectorGraphicSearch.hxx
index 2dc8cca3b76a..c9faaa51f1c9 100644
--- a/include/vcl/VectorGraphicSearch.hxx
+++ b/include/vcl/VectorGraphicSearch.hxx
@@ -32,8 +32,7 @@ private:
     std::unique_ptr<Implementation> mpImplementation;
     Graphic maGraphic;
 
-    bool searchPDF(std::shared_ptr<VectorGraphicData> const& rData, OUString const& rSearchString,
-                   SearchStartPosition eStartPosition);
+    bool searchPDF(std::shared_ptr<VectorGraphicData> const& rData);
 
 public:
     VectorGraphicSearch(Graphic const& rGraphic);
diff --git a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
index 5f65b4ba7e3d..8dbdcac0e2e1 100644
--- a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
+++ b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
@@ -27,10 +27,12 @@ class VectorGraphicSearchTest : public test::BootstrapFixtureBase
 
     void test();
     void testNextPrevious();
+    void testSearchStringChange();
 
     CPPUNIT_TEST_SUITE(VectorGraphicSearchTest);
     CPPUNIT_TEST(test);
     CPPUNIT_TEST(testNextPrevious);
+    CPPUNIT_TEST(testSearchStringChange);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -160,6 +162,37 @@ void VectorGraphicSearchTest::testNextPrevious()
     }
 }
 
+void VectorGraphicSearchTest::testSearchStringChange()
+{
+    OUString aURL = getFullUrl("Pangram.pdf");
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    aGraphic.makeAvailable();
+
+    VectorGraphicSearch aSearch(aGraphic);
+
+    // Set search to "lazy"
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.search("lazy"));
+
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+    // Change search to "fox"
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.search("fox"));
+
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(822, aSearch.index());
+
+    // Change search to "Quick"
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.search("Quick"));
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+    CPPUNIT_ASSERT_EQUAL(784, aSearch.index());
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(VectorGraphicSearchTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index db17df2539ec..07e4b19afc08 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -56,18 +56,18 @@ private:
 
 public:
     sal_Int32 mnPageIndex;
+    int mnCurrentIndex;
     OUString maSearchString;
     SearchStartPosition meStartPosition;
 
-    SearchContext(FPDF_DOCUMENT pPdfDocument, sal_Int32 nPageIndex, OUString const& rSearchString,
-                  SearchStartPosition eStartPosition)
+    SearchContext(FPDF_DOCUMENT pPdfDocument, sal_Int32 nPageIndex)
         : mpPdfDocument(pPdfDocument)
         , mpPage(nullptr)
         , mpTextPage(nullptr)
         , mpSearchHandle(nullptr)
         , mnPageIndex(nPageIndex)
-        , maSearchString(rSearchString)
-        , meStartPosition(eStartPosition)
+        , mnCurrentIndex(-1)
+        , meStartPosition(SearchStartPosition::Begin)
     {
     }
 
@@ -96,13 +96,30 @@ public:
         return aSize;
     }
 
-    bool initialize()
+    bool initialize(OUString const& rSearchString, SearchStartPosition eStartPosition)
     {
         if (!mpPdfDocument)
             return false;
+
+        if (rSearchString == maSearchString)
+            return true;
+
+        if (mpSearchHandle)
+            FPDFText_FindClose(mpSearchHandle);
+
+        if (mpTextPage)
+            FPDFText_ClosePage(mpTextPage);
+
+        if (mpPage)
+            FPDF_ClosePage(mpPage);
+
+        maSearchString = rSearchString;
+        meStartPosition = eStartPosition;
+
         mpPage = FPDF_LoadPage(mpPdfDocument, mnPageIndex);
         if (!mpPage)
             return false;
+
         mpTextPage = FPDFText_LoadPage(mpPage);
         if (!mpTextPage)
             return false;
@@ -112,6 +129,9 @@ public:
         // Index where to start to search. -1 => at the end
         int nStartIndex = meStartPosition == SearchStartPosition::End ? -1 : 0;
 
+        if (mnCurrentIndex >= 0)
+            nStartIndex = mnCurrentIndex;
+
         // FPDF_MATCHCASE, FPDF_MATCHWHOLEWORD, FPDF_CONSECUTIVE
         // FPDF_MATCHCASE - If not set, it will not match case by default.
         // FPDF_MATCHWHOLEWORD - If not set, it will not match the whole word by default.
@@ -125,15 +145,21 @@ public:
 
     bool next()
     {
-        if (mpSearchHandle)
-            return FPDFText_FindNext(mpSearchHandle);
+        if (mpSearchHandle && FPDFText_FindNext(mpSearchHandle))
+        {
+            mnCurrentIndex = index();
+            return true;
+        }
         return false;
     }
 
     bool previous()
     {
-        if (mpSearchHandle)
-            return FPDFText_FindPrev(mpSearchHandle);
+        if (mpSearchHandle && FPDFText_FindPrev(mpSearchHandle))
+        {
+            mnCurrentIndex = index();
+            return true;
+        }
         return false;
     }
 
@@ -200,22 +226,24 @@ VectorGraphicSearch::~VectorGraphicSearch() { mpImplementation.reset(); }
 
 bool VectorGraphicSearch::search(OUString const& rSearchString, SearchStartPosition eStartPosition)
 {
-    auto pData = maGraphic.getVectorGraphicData();
-
-    if (pData && pData->getVectorGraphicDataType() == VectorGraphicDataType::Pdf)
+    if (!mpImplementation->mpSearchContext)
     {
-        return searchPDF(pData, rSearchString, eStartPosition);
+        auto pData = maGraphic.getVectorGraphicData();
+
+        if (pData && pData->getVectorGraphicDataType() == VectorGraphicDataType::Pdf)
+        {
+            if (searchPDF(pData))
+            {
+                return mpImplementation->mpSearchContext->initialize(rSearchString, eStartPosition);
+            }
+        }
+        return false;
     }
-    return false;
+    return mpImplementation->mpSearchContext->initialize(rSearchString, eStartPosition);
 }
 
-bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData,
-                                    OUString const& rSearchString,
-                                    SearchStartPosition eStartPosition)
+bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData)
 {
-    if (rSearchString.isEmpty())
-        return false;
-
     mpImplementation->mpPdfDocument
         = FPDF_LoadMemDocument(rData->getVectorGraphicDataArray().getConstArray(),
                                rData->getVectorGraphicDataArrayLength(), /*password=*/nullptr);
@@ -247,10 +275,9 @@ bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rD
 
     sal_Int32 nPageIndex = std::max(rData->getPageIndex(), 0);
 
-    mpImplementation->mpSearchContext.reset(new SearchContext(
-        mpImplementation->mpPdfDocument, nPageIndex, rSearchString, eStartPosition));
-
-    return mpImplementation->mpSearchContext->initialize();
+    mpImplementation->mpSearchContext.reset(
+        new SearchContext(mpImplementation->mpPdfDocument, nPageIndex));
+    return true;
 }
 
 basegfx::B2DSize VectorGraphicSearch::pageSize()
commit 2e9123e8506734843428a888fde9e7522d6a9cb0
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 13:28:36 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:51 2020 +0200

    sd: add support to search backwards in PDF search
    
    Change-Id: I2c7f75d16a430dcfa892d28fb6b4f64118705ad2

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 2c1e1c0426a3..8c2a41eeca9e 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -56,6 +56,7 @@ public:
     void testSearchInPDFNonExisting();
     void testSearchInPDF();
     void testSearchInPDFInMultiplePages();
+    void testSearchInPDFInMultiplePagesBackwards();
     void testSearchIn2MixedObjects();
     void testSearchIn6MixedObjects();
 
@@ -69,6 +70,7 @@ public:
     CPPUNIT_TEST(testSearchInPDFNonExisting);
     CPPUNIT_TEST(testSearchInPDF);
     CPPUNIT_TEST(testSearchInPDFInMultiplePages);
+    CPPUNIT_TEST(testSearchInPDFInMultiplePagesBackwards);
     CPPUNIT_TEST(testSearchIn2MixedObjects);
     CPPUNIT_TEST(testSearchIn6MixedObjects);
     CPPUNIT_TEST_SUITE_END();
@@ -123,14 +125,14 @@ LOKitSearchTest::createDoc(const char* pName, const uno::Sequence<beans::Propert
 
 namespace
 {
-void lcl_search(const OUString& rKey, bool bFindAll = false)
+void lcl_search(const OUString& rKey, bool bFindAll = false, bool bBackwards = false)
 {
     Scheduler::ProcessEventsToIdle();
     SvxSearchCmd eSearch = bFindAll ? SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND;
 
     uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({
         { "SearchItem.SearchString", uno::makeAny(rKey) },
-        { "SearchItem.Backward", uno::makeAny(false) },
+        { "SearchItem.Backward", uno::makeAny(bBackwards) },
         { "SearchItem.Command", uno::makeAny(sal_uInt16(eSearch)) },
     }));
 
@@ -422,6 +424,104 @@ void LOKitSearchTest::testSearchInPDFInMultiplePages()
                          mpCallbackRecorder->m_aSearchResultSelection[0]);
 }
 
+void LOKitSearchTest::testSearchInPDFInMultiplePagesBackwards()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    {
+        SdrObject* pObject = pPage->GetObj(0);
+        CPPUNIT_ASSERT(pObject);
+
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+
+        Graphic aGraphic = pGraphicObject->GetGraphic();
+        auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Expected for backwards search is:
+    // - Start with Page 1
+    //   + search backwards through objects
+    //   + inside objects search backwards through text
+    // - Switch to Page 2
+    //   + search backwards through objects
+    //   + inside objects search backwards through text
+
+    // Search for "him"
+    lcl_search("him", /*FindAll*/ false, /*Backwards*/ true);
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("5592, 5038, 1100, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him", /*FindAll*/ false, /*Backwards*/ true);
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("9463, 3382, 1099, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him", /*FindAll*/ false, /*Backwards*/ true);
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("5592, 2964, 1100, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him", /*FindAll*/ false, /*Backwards*/ true);
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("9463, 1308, 1099, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him" - back to start
+    lcl_search("him", /*FindAll*/ false, /*Backwards*/ true);
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("5592, 5038, 1100, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+}
+
 // Test searching in document with mixed objects.
 // We have 2 objects: 1. Text Object, 2. Graphic Object with PDF
 void LOKitSearchTest::testSearchIn2MixedObjects()
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index bc3a4e8d8821..584d7b253994 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -827,7 +827,15 @@ bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelecti
 
             if (mpImpl->mbCurrentIsVectorGraphic)
             {
-                if (mpImpl->mpVectorGraphicSearch->next())
+                bool bBackwards = mpSearchItem->GetBackward();
+
+                bool bResult = false;
+                if (bBackwards)
+                    bResult = mpImpl->mpVectorGraphicSearch->previous();
+                else
+                    bResult = mpImpl->mpVectorGraphicSearch->next();
+
+                if (bResult)
                 {
                     nMatchCount = 1;
 
@@ -1228,12 +1236,19 @@ void SdOutliner::ProvideNextTextObject()
                     // contains a vector graphic
                     auto* pGraphicObject = static_cast<SdrGrafObj*>(mpObj);
                     OUString const & rString = mpSearchItem->GetSearchString();
+                    bool bBackwards = mpSearchItem->GetBackward();
+                    SearchStartPosition eSearchStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin;
 
                     mpImpl->mpVectorGraphicSearch = std::make_unique<VectorGraphicSearch>(pGraphicObject->GetGraphic());
 
-                    bool bResult = mpImpl->mpVectorGraphicSearch->search(rString);
+                    bool bResult = mpImpl->mpVectorGraphicSearch->search(rString, eSearchStartPosition);
                     if (bResult)
-                        bResult = mpImpl->mpVectorGraphicSearch->next();
+                    {
+                        if (bBackwards)
+                            bResult = mpImpl->mpVectorGraphicSearch->previous();
+                        else
+                            bResult = mpImpl->mpVectorGraphicSearch->next();
+                    }
 
                     if (bResult)
                     {
commit e6be6c54c4135b72de65448a97250be2397f4e4b
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 12:17:05 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:50 2020 +0200

    sd: add test to search inside PDF in multiple pages
    
    Change-Id: I246508a22a4e324bae1bb10c6e292790c04da4c0

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index ec9f7d95c5da..2c1e1c0426a3 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -55,6 +55,7 @@ public:
     void testDontSearchInMasterPages();
     void testSearchInPDFNonExisting();
     void testSearchInPDF();
+    void testSearchInPDFInMultiplePages();
     void testSearchIn2MixedObjects();
     void testSearchIn6MixedObjects();
 
@@ -67,6 +68,7 @@ public:
     CPPUNIT_TEST(testDontSearchInMasterPages);
     CPPUNIT_TEST(testSearchInPDFNonExisting);
     CPPUNIT_TEST(testSearchInPDF);
+    CPPUNIT_TEST(testSearchInPDFInMultiplePages);
     CPPUNIT_TEST(testSearchIn2MixedObjects);
     CPPUNIT_TEST(testSearchIn6MixedObjects);
     CPPUNIT_TEST_SUITE_END();
@@ -330,6 +332,96 @@ void LOKitSearchTest::testSearchInPDF()
                          mpCallbackRecorder->m_aSelection[0]);
 }
 
+void LOKitSearchTest::testSearchInPDFInMultiplePages()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    {
+        SdrObject* pObject = pPage->GetObj(0);
+        CPPUNIT_ASSERT(pObject);
+
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+
+        Graphic aGraphic = pGraphicObject->GetGraphic();
+        auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Search for "him"
+    lcl_search("him");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("9463, 3382, 1099, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("5592, 5038, 1100, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("9463, 1308, 1099, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him"
+    lcl_search("him");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("5592, 2964, 1100, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search for "him" - back to start
+    lcl_search("him");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(0, mpCallbackRecorder->m_aSearchResultPart[0]);
+    CPPUNIT_ASSERT_EQUAL(OString("9463, 3382, 1099, 499"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+}
+
 // Test searching in document with mixed objects.
 // We have 2 objects: 1. Text Object, 2. Graphic Object with PDF
 void LOKitSearchTest::testSearchIn2MixedObjects()
commit 76719168473852ba8b2be4d54e58fd5964a1f6da
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 12:13:59 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:50 2020 +0200

    vcl: use HAVE_FEATURE_PDFIUM in VectorGraphicSearch impl.
    
    Change-Id: Id6c30e8f1c5bdb0481b0c7d4680554e3e8caa323

diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index 0e50a045e911..db17df2539ec 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -10,6 +10,10 @@
 
 #include <vcl/VectorGraphicSearch.hxx>
 
+#include <config_features.h>
+
+#if HAVE_FEATURE_PDFIUM
+
 #include <vcl/filter/PDFiumLibrary.hxx>
 
 #include <sal/config.h>
@@ -286,4 +290,41 @@ std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
     return std::vector<basegfx::B2DRectangle>();
 }
 
+#else // !HAVE_FEATURE_PDFIUM
+
+VectorGraphicSearch::VectorGraphicSearch(Graphic const& rGraphic)
+    : maGraphic(rGraphic)
+{
+}
+
+VectorGraphicSearch::~VectorGraphicSearch() {}
+
+bool VectorGraphicSearch::search(OUString const& /*rSearchString*/,
+                                 SearchStartPosition /*eStartPosition*/)
+{
+    return false;
+}
+
+bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& /*rData*/,
+                                    OUString const& /*rSearchString*/,
+                                    SearchStartPosition /*eStartPosition*/)
+{
+    return false;
+}
+
+basegfx::B2DSize VectorGraphicSearch::pageSize() { return basegfx::B2DSize(); }
+
+bool VectorGraphicSearch::next() { return false; }
+
+bool VectorGraphicSearch::previous() { return false; }
+
+int VectorGraphicSearch::index() { return -1; }
+
+std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
+{
+    return std::vector<basegfx::B2DRectangle>();
+}
+
+#endif // HAVE_FEATURE_PDFIUM
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit f731cd851d969bb9371b26f80c79a8dbc2d10d6d
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 12:02:39 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:50 2020 +0200

    vcl: VectorGraphicSearch - move SearchContext into Implementation
    
    Change-Id: I3bbf085fd8b8b66a56e364168c1e70b4ce986467

diff --git a/include/vcl/VectorGraphicSearch.hxx b/include/vcl/VectorGraphicSearch.hxx
index b67c63a844d8..2dc8cca3b76a 100644
--- a/include/vcl/VectorGraphicSearch.hxx
+++ b/include/vcl/VectorGraphicSearch.hxx
@@ -19,8 +19,6 @@
 
 #include <memory>
 
-class SearchContext;
-
 enum class SearchStartPosition
 {
     Begin,
@@ -33,7 +31,6 @@ private:
     class Implementation;
     std::unique_ptr<Implementation> mpImplementation;
     Graphic maGraphic;
-    std::unique_ptr<SearchContext> mpSearchContext;
 
     bool searchPDF(std::shared_ptr<VectorGraphicData> const& rData, OUString const& rSearchString,
                    SearchStartPosition eStartPosition);
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index 9a1c966d9d69..0e50a045e911 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -17,12 +17,16 @@
 #include <fpdf_doc.h>
 #include <fpdf_text.h>
 
+class SearchContext;
+
 class VectorGraphicSearch::Implementation
 {
 public:
     std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
     FPDF_DOCUMENT mpPdfDocument;
 
+    std::unique_ptr<SearchContext> mpSearchContext;
+
     Implementation()
         : mpPDFium(vcl::pdf::PDFiumLibrary::get())
         , mpPdfDocument(nullptr)
@@ -31,6 +35,8 @@ public:
 
     ~Implementation()
     {
+        mpSearchContext.reset();
+
         if (mpPdfDocument)
             FPDF_CloseDocument(mpPdfDocument);
     }
@@ -186,11 +192,7 @@ VectorGraphicSearch::VectorGraphicSearch(Graphic const& rGraphic)
 {
 }
 
-VectorGraphicSearch::~VectorGraphicSearch()
-{
-    mpSearchContext.reset();
-    mpImplementation.reset();
-}
+VectorGraphicSearch::~VectorGraphicSearch() { mpImplementation.reset(); }
 
 bool VectorGraphicSearch::search(OUString const& rSearchString, SearchStartPosition eStartPosition)
 {
@@ -241,45 +243,45 @@ bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rD
 
     sal_Int32 nPageIndex = std::max(rData->getPageIndex(), 0);
 
-    mpSearchContext.reset(new SearchContext(mpImplementation->mpPdfDocument, nPageIndex,
-                                            rSearchString, eStartPosition));
+    mpImplementation->mpSearchContext.reset(new SearchContext(
+        mpImplementation->mpPdfDocument, nPageIndex, rSearchString, eStartPosition));
 
-    return mpSearchContext->initialize();
+    return mpImplementation->mpSearchContext->initialize();
 }
 
 basegfx::B2DSize VectorGraphicSearch::pageSize()
 {
     basegfx::B2DSize aSize;
-    if (mpSearchContext)
-        aSize = mpSearchContext->getPageSize();
+    if (mpImplementation->mpSearchContext)
+        aSize = mpImplementation->mpSearchContext->getPageSize();
     return aSize;
 }
 
 bool VectorGraphicSearch::next()
 {
-    if (mpSearchContext)
-        return mpSearchContext->next();
+    if (mpImplementation->mpSearchContext)
+        return mpImplementation->mpSearchContext->next();
     return false;
 }
 
 bool VectorGraphicSearch::previous()
 {
-    if (mpSearchContext)
-        return mpSearchContext->previous();
+    if (mpImplementation->mpSearchContext)
+        return mpImplementation->mpSearchContext->previous();
     return false;
 }
 
 int VectorGraphicSearch::index()
 {
-    if (mpSearchContext)
-        return mpSearchContext->index();
+    if (mpImplementation->mpSearchContext)
+        return mpImplementation->mpSearchContext->index();
     return -1;
 }
 
 std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
 {
-    if (mpSearchContext)
-        return mpSearchContext->getTextRectangles();
+    if (mpImplementation->mpSearchContext)
+        return mpImplementation->mpSearchContext->getTextRectangles();
 
     return std::vector<basegfx::B2DRectangle>();
 }
commit b971f704dace1af227ab3a0836461babba94c703
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 11:50:20 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:49 2020 +0200

    pdfium: only init pdfium library one and destroy on LO exit
    
    With more and more usage of PDFium, it is hard to keep track of
    the life-time of the PDFium library, so it can happen that a
    FPDF_DestroyLibrary happens when we still have another instance
    where PDFium is still use. The result of this is a crash. To
    prevent this, just initialize the library once and delete, when
    on LO exit.
    
    This can be improved in the future to only keep the library
    active when in actual use.
    
    Change-Id: I5c7e5de7f8b97d10efb394c67c7a61b976c8d57c

diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
new file mode 100644
index 000000000000..bc7912c17e81
--- /dev/null
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include <config_features.h>
+
+#if HAVE_FEATURE_PDFIUM
+
+#include <memory>
+#include <rtl/instance.hxx>
+#include <vcl/dllapi.h>
+
+namespace vcl::pdf
+{
+class VCL_DLLPUBLIC PDFium final
+{
+private:
+    PDFium(const PDFium&) = delete;
+    PDFium& operator=(const PDFium&) = delete;
+
+public:
+    PDFium();
+    ~PDFium();
+};
+
+struct PDFiumLibrary : public rtl::StaticWithInit<std::shared_ptr<PDFium>, PDFiumLibrary>
+{
+    std::shared_ptr<PDFium> operator()() { return std::make_shared<PDFium>(); }
+};
+
+} // namespace vcl::pdf
+
+#endif // HAVE_FEATURE_PDFIUM
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx
index 9b48eb1d30c5..1f02b2151594 100644
--- a/svx/source/inc/svdpdf.hxx
+++ b/svx/source/inc/svdpdf.hxx
@@ -42,6 +42,8 @@
 #include <postwin.h>
 #include <fpdfview.h>
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 // Forward Declarations
 
 class SfxItemSet;
@@ -100,6 +102,8 @@ class SVXCORE_DLLPUBLIC ImpSdrPdfImport final
     tools::Rectangle PointsToLogic(double left, double right, double top, double bottom) const;
     Point PointsToLogic(double x, double y) const;
 
+    std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
+
     // check for clip and evtl. fill maClip
     void checkClip();
     bool isClip() const;
diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx
index 5cd0c0765a29..188651be386c 100644
--- a/svx/source/svdraw/svdpdf.cxx
+++ b/svx/source/svdraw/svdpdf.cxx
@@ -116,6 +116,7 @@ ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools:
     , mnPageCount(0)
     , mdPageWidthPts(0)
     , mdPageHeightPts(0)
+    , mpPDFium(vcl::pdf::PDFiumLibrary::get())
 {
     mpVD->EnableOutput(false);
     mpVD->SetLineColor();
@@ -129,13 +130,6 @@ ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools:
                                               svl::Items<EE_ITEMS_START, EE_ITEMS_END>{});
     checkClip();
 
-    FPDF_LIBRARY_CONFIG aConfig;
-    aConfig.version = 2;
-    aConfig.m_pUserFontPaths = nullptr;
-    aConfig.m_pIsolate = nullptr;
-    aConfig.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&aConfig);
-
     // Load the buffer using pdfium.
     auto const& rVectorGraphicData = rGraphic.getVectorGraphicData();
     mpPdfDocument = FPDF_LoadMemDocument(
@@ -170,11 +164,7 @@ ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools:
     mnPageCount = FPDF_GetPageCount(mpPdfDocument);
 }
 
-ImpSdrPdfImport::~ImpSdrPdfImport()
-{
-    FPDF_CloseDocument(mpPdfDocument);
-    FPDF_DestroyLibrary();
-}
+ImpSdrPdfImport::~ImpSdrPdfImport() { FPDF_CloseDocument(mpPdfDocument); }
 
 void ImpSdrPdfImport::DoObjects(SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport,
                                 int nPageIndex)
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index b1422157df0e..50d6513be8b0 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -319,6 +319,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/pdf/ResourceDict \
     vcl/source/pdf/Matrix3 \
     vcl/source/pdf/XmpMetadata \
+    vcl/source/pdf/PDFiumLibrary \
     vcl/source/graphic/GraphicID \
     vcl/source/graphic/GraphicLoader \
     vcl/source/graphic/GraphicObject \
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 789b82ae42e6..45eb62921bcb 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -43,6 +43,8 @@
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <unotools/streamwrap.hxx>
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 using namespace ::com::sun::star;
 
 static std::ostream& operator<<(std::ostream& rStrm, const Color& rColor)
@@ -87,6 +89,7 @@ class PdfExportTest : public test::BootstrapFixture, public unotest::MacrosTest
     SvMemoryStream maMemory;
     // Export the document as PDF, then parse it with PDFium.
     DocumentHolder exportAndParse(const OUString& rURL, const utl::MediaDescriptor& rDescriptor);
+    std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
 
 public:
     PdfExportTest();
@@ -225,18 +228,11 @@ void PdfExportTest::setUp()
 
     mxDesktop.set(frame::Desktop::create(mxComponentContext));
 
-    FPDF_LIBRARY_CONFIG config;
-    config.version = 2;
-    config.m_pUserFontPaths = nullptr;
-    config.m_pIsolate = nullptr;
-    config.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&config);
+    mpPDFium = vcl::pdf::PDFiumLibrary::get();
 }
 
 void PdfExportTest::tearDown()
 {
-    FPDF_DestroyLibrary();
-
     if (mxComponent.is())
         mxComponent->dispose();
 
@@ -2061,14 +2057,6 @@ void PdfExportTest::testPdfImageResourceInlineXObjectRef()
     aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
     xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
 
-    // Init pdfium, vcl::ImportPDF() calls FPDF_DestroyLibrary after our setUp().
-    FPDF_LIBRARY_CONFIG config;
-    config.version = 2;
-    config.m_pUserFontPaths = nullptr;
-    config.m_pIsolate = nullptr;
-    config.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&config);
-
     // Parse the export result.
     SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ);
     maMemory.WriteStream(aFile);
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index 1df96ad46e72..2a7e7ce04198 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -21,6 +21,8 @@
 #include <bitmapwriteaccess.hxx>
 #include <unotools/ucbstreamhelper.hxx>
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 using namespace com::sun::star;
 
 namespace
@@ -82,12 +84,7 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream)
     else
     {
         // Downconvert to PDF-1.6.
-        FPDF_LIBRARY_CONFIG aConfig;
-        aConfig.version = 2;
-        aConfig.m_pUserFontPaths = nullptr;
-        aConfig.m_pIsolate = nullptr;
-        aConfig.m_v8EmbedderSlot = 0;
-        FPDF_InitLibraryWithConfig(&aConfig);
+        auto pPdfium = vcl::pdf::PDFiumLibrary::get();
 
         // Read input into a buffer.
         SvMemoryStream aInBuffer;
@@ -108,7 +105,6 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream)
             return false;
 
         FPDF_CloseDocument(pPdfDocument);
-        FPDF_DestroyLibrary();
 
         aWriter.m_aStream.Seek(STREAM_SEEK_TO_BEGIN);
         rOutStream.WriteStream(aWriter.m_aStream);
@@ -152,12 +148,7 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBi
                         const size_t nFirstPage, int nPages, const double fResolutionDPI)
 {
 #if HAVE_FEATURE_PDFIUM
-    FPDF_LIBRARY_CONFIG aConfig;
-    aConfig.version = 2;
-    aConfig.m_pUserFontPaths = nullptr;
-    aConfig.m_pIsolate = nullptr;
-    aConfig.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&aConfig);
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
 
     // Load the buffer using pdfium.
     FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(pBuffer, nSize, /*password=*/nullptr);
@@ -207,7 +198,6 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<Bitmap>& rBi
     }
 
     FPDF_CloseDocument(pPdfDocument);
-    FPDF_DestroyLibrary();
 
     return rBitmaps.size();
 #else
@@ -254,12 +244,7 @@ size_t ImportPDFUnloaded(const OUString& rURL, std::vector<std::pair<Graphic, Si
     auto pGfxLink = std::make_shared<GfxLink>(std::move(pGraphicContent), nGraphicContentSize,
                                               GfxLinkType::NativePdf);
 
-    FPDF_LIBRARY_CONFIG aConfig;
-    aConfig.version = 2;
-    aConfig.m_pUserFontPaths = nullptr;
-    aConfig.m_pIsolate = nullptr;
-    aConfig.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&aConfig);
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
 
     // Load the buffer using pdfium.
     FPDF_DOCUMENT pPdfDocument
@@ -298,7 +283,6 @@ size_t ImportPDFUnloaded(const OUString& rURL, std::vector<std::pair<Graphic, Si
     }
 
     FPDF_CloseDocument(pPdfDocument);
-    FPDF_DestroyLibrary();
 
     return rGraphics.size();
 #else
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index 2fa0d536442d..9a1c966d9d69 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -10,6 +10,8 @@
 
 #include <vcl/VectorGraphicSearch.hxx>
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 #include <sal/config.h>
 
 #include <fpdf_doc.h>
@@ -18,10 +20,12 @@
 class VectorGraphicSearch::Implementation
 {
 public:
+    std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
     FPDF_DOCUMENT mpPdfDocument;
 
     Implementation()
-        : mpPdfDocument(nullptr)
+        : mpPDFium(vcl::pdf::PDFiumLibrary::get())
+        , mpPdfDocument(nullptr)
     {
     }
 
@@ -180,19 +184,12 @@ VectorGraphicSearch::VectorGraphicSearch(Graphic const& rGraphic)
     : mpImplementation(std::make_unique<VectorGraphicSearch::Implementation>())
     , maGraphic(rGraphic)
 {
-    FPDF_LIBRARY_CONFIG aConfig;
-    aConfig.version = 2;
-    aConfig.m_pUserFontPaths = nullptr;
-    aConfig.m_pIsolate = nullptr;
-    aConfig.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&aConfig);
 }
 
 VectorGraphicSearch::~VectorGraphicSearch()
 {
     mpSearchContext.reset();
     mpImplementation.reset();
-    FPDF_DestroyLibrary();
 }
 
 bool VectorGraphicSearch::search(OUString const& rSearchString, SearchStartPosition eStartPosition)
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
new file mode 100644
index 000000000000..604807524bf9
--- /dev/null
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <config_features.h>
+
+#if HAVE_FEATURE_PDFIUM
+
+#include <vcl/filter/PDFiumLibrary.hxx>
+#include <fpdf_doc.h>
+
+namespace vcl::pdf
+{
+PDFium::PDFium()
+{
+    FPDF_LIBRARY_CONFIG aConfig;
+    aConfig.version = 2;
+    aConfig.m_pUserFontPaths = nullptr;
+    aConfig.m_pIsolate = nullptr;
+    aConfig.m_v8EmbedderSlot = 0;
+    FPDF_InitLibraryWithConfig(&aConfig);
+}
+
+PDFium::~PDFium() { FPDF_DestroyLibrary(); }
+
+} // end vcl::pdf
+
+#endif // HAVE_FEATURE_PDFIUM
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit a9875bb8870f868eeeaea2366631d95e14fe4f22
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 10:05:17 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:49 2020 +0200

    sd: rename testSearchInMixedObject(2) to more descriptive name
    
    testSearchInMixedObject -> testSearchIn2MixedObjects
    testSearchInMixedObject2 -> testSearchIn6MixedObjects
    
    Change-Id: Ifba20df38fd33bb86b072ba79085d123c914f916

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 7786bc1f1dae..ec9f7d95c5da 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -55,8 +55,8 @@ public:
     void testDontSearchInMasterPages();
     void testSearchInPDFNonExisting();
     void testSearchInPDF();
-    void testSearchInMixedObject();
-    void testSearchInMixedObject2();
+    void testSearchIn2MixedObjects();
+    void testSearchIn6MixedObjects();
 
     CPPUNIT_TEST_SUITE(LOKitSearchTest);
     CPPUNIT_TEST(testSearch);
@@ -67,8 +67,8 @@ public:
     CPPUNIT_TEST(testDontSearchInMasterPages);
     CPPUNIT_TEST(testSearchInPDFNonExisting);
     CPPUNIT_TEST(testSearchInPDF);
-    CPPUNIT_TEST(testSearchInMixedObject);
-    CPPUNIT_TEST(testSearchInMixedObject2);
+    CPPUNIT_TEST(testSearchIn2MixedObjects);
+    CPPUNIT_TEST(testSearchIn6MixedObjects);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -332,7 +332,7 @@ void LOKitSearchTest::testSearchInPDF()
 
 // Test searching in document with mixed objects.
 // We have 2 objects: 1. Text Object, 2. Graphic Object with PDF
-void LOKitSearchTest::testSearchInMixedObject()
+void LOKitSearchTest::testSearchIn2MixedObjects()
 {
     SdXImpressDocument* pXImpressDocument = createDoc("MixedTest1.odg");
     sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
@@ -417,7 +417,7 @@ void LOKitSearchTest::testSearchInMixedObject()
 }
 
 // Test searching in document with mixed objects. We have 6 objects.
-void LOKitSearchTest::testSearchInMixedObject2()
+void LOKitSearchTest::testSearchIn6MixedObjects()
 {
     SdXImpressDocument* pXImpressDocument = createDoc("MixedTest2.odg");
     sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
commit 03848655a4e1f9465f4a8a535a2892819480e815
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 09:58:26 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:49 2020 +0200

    sd: PDF search - reset mpVectorGraphicSearch at more places
    
    and simplify the case when the search doesn't find a match in
    the vector graphic.
    
    Change-Id: I3e086e8e36f8a578711eed6d4dcca65c0c4c6268

diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 0bea27890a84..bc3a4e8d8821 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -1160,6 +1160,7 @@ void SdOutliner::ProvideNextTextObject()
     mbFoundObject = false;
 
     // reset the vector search
+    mpImpl->mbCurrentIsVectorGraphic = false;
     mpImpl->mpVectorGraphicSearch.reset();
 
     mpView->UnmarkAllObj (mpView->GetSdrPageView());
@@ -1195,6 +1196,7 @@ void SdOutliner::ProvideNextTextObject()
             bool bForbiddenPage = comphelper::LibreOfficeKit::isActive() && (maCurrentPosition.mePageKind != PageKind::Standard || maCurrentPosition.meEditMode != EditMode::Page);
 
             mpImpl->mbCurrentIsVectorGraphic = false;
+            mpImpl->mpVectorGraphicSearch.reset();
 
             if (!bForbiddenPage)
             {
@@ -1228,34 +1230,30 @@ void SdOutliner::ProvideNextTextObject()
                     OUString const & rString = mpSearchItem->GetSearchString();
 
                     mpImpl->mpVectorGraphicSearch = std::make_unique<VectorGraphicSearch>(pGraphicObject->GetGraphic());
-                    if (mpImpl->mpVectorGraphicSearch->search(rString))
+
+                    bool bResult = mpImpl->mpVectorGraphicSearch->search(rString);
+                    if (bResult)
+                        bResult = mpImpl->mpVectorGraphicSearch->next();
+
+                    if (bResult)
                     {
-                        bool bResult = mpImpl->mpVectorGraphicSearch->next();
-                        if (bResult)
-                        {
-                            mpObj = SetObject(maCurrentPosition);
+                        mpObj = SetObject(maCurrentPosition);
 
-                            mbStringFound = true;
-                            mbMatchMayExist = true;
-                            mbFoundObject = true;
+                        mbStringFound = true;
+                        mbMatchMayExist = true;
+                        mbFoundObject = true;
 
-                            SdrPageView* pPageView = mpView->GetSdrPageView();
-                            mpView->UnmarkAllObj(pPageView);
+                        SdrPageView* pPageView = mpView->GetSdrPageView();
+                        mpView->UnmarkAllObj(pPageView);
 
-                            std::vector<basegfx::B2DRectangle> aSubSelections;
-                            basegfx::B2DRectangle aSubSelection = getPDFSelection(mpImpl->mpVectorGraphicSearch, mpObj);
-                            if (!aSubSelection.isEmpty())
-                                aSubSelections.push_back(aSubSelection);
+                        std::vector<basegfx::B2DRectangle> aSubSelections;
+                        basegfx::B2DRectangle aSubSelection = getPDFSelection(mpImpl->mpVectorGraphicSearch, mpObj);
+                        if (!aSubSelection.isEmpty())
+                            aSubSelections.push_back(aSubSelection);
 
-                            mpView->MarkObj(mpObj, pPageView, false, false, aSubSelections);
+                        mpView->MarkObj(mpObj, pPageView, false, false, aSubSelections);
 
-                            mpDrawDocument->GetDocSh()->SetWaitCursor( false );
-                        }
-                        else
-                        {
-                            mpImpl->mbCurrentIsVectorGraphic = false;
-                            mpImpl->mpVectorGraphicSearch.reset();
-                        }
+                        mpDrawDocument->GetDocSh()->SetWaitCursor( false );
                     }
                     else
                     {
@@ -1288,6 +1286,9 @@ void SdOutliner::ProvideNextTextObject()
         }
         else
         {
+            mpImpl->mbCurrentIsVectorGraphic = false;
+            mpImpl->mpVectorGraphicSearch.reset();
+
             if (meMode == SEARCH)
                 // Instead of doing a full-blown SetObject(), which would do the same -- but would also possibly switch pages.
                 mbStringFound = false;
commit ff3600dd5a4e7b61c2d71618b907c39ce4ba8b80
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 09:51:33 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:48 2020 +0200

    vcl: VectorGraphicSearch - clean-up SearchContext member vars.
    
    Change-Id: I1740be5ed1b47235da3794fa46e3533b17ca1fb8

diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index 4b2aedad1bdc..2fa0d536442d 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -34,26 +34,26 @@ public:
 
 class SearchContext
 {
-public:
-    bool bInitialized = false;
-
+private:
     FPDF_DOCUMENT mpPdfDocument;
-    sal_Int32 mnPageIndex;
     FPDF_PAGE mpPage;
     FPDF_TEXTPAGE mpTextPage;
+    FPDF_SCHHANDLE mpSearchHandle;
+
+public:
+    sal_Int32 mnPageIndex;
     OUString maSearchString;
     SearchStartPosition meStartPosition;
-    FPDF_SCHHANDLE mpSearchHandle;
 
     SearchContext(FPDF_DOCUMENT pPdfDocument, sal_Int32 nPageIndex, OUString const& rSearchString,
                   SearchStartPosition eStartPosition)
         : mpPdfDocument(pPdfDocument)
-        , mnPageIndex(nPageIndex)
         , mpPage(nullptr)
         , mpTextPage(nullptr)
+        , mpSearchHandle(nullptr)
+        , mnPageIndex(nPageIndex)
         , maSearchString(rSearchString)
         , meStartPosition(eStartPosition)
-        , mpSearchHandle(nullptr)
     {
     }
 
commit e8f2672093c90c58dc2e6504ea1f2874aa48ed47
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sat May 30 19:30:44 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:48 2020 +0200

    sd: Add another test of searching with mixed objects
    
    This is to make sure that we switch between different objects
    during the search correctly.
    
    Change-Id: I18aa5b251cbaadd3a9cb15a04ec1a1e5f267d2e3

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 24037a0780ba..7786bc1f1dae 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -56,6 +56,7 @@ public:
     void testSearchInPDFNonExisting();
     void testSearchInPDF();
     void testSearchInMixedObject();
+    void testSearchInMixedObject2();
 
     CPPUNIT_TEST_SUITE(LOKitSearchTest);
     CPPUNIT_TEST(testSearch);
@@ -67,6 +68,7 @@ public:
     CPPUNIT_TEST(testSearchInPDFNonExisting);
     CPPUNIT_TEST(testSearchInPDF);
     CPPUNIT_TEST(testSearchInMixedObject);
+    CPPUNIT_TEST(testSearchInMixedObject2);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -134,6 +136,15 @@ void lcl_search(const OUString& rKey, bool bFindAll = false)
     Scheduler::ProcessEventsToIdle();
 }
 
+SdrObject* lclGetSelectedObject(sd::ViewShell* pViewShell)
+{
+    SdrView* pSdrView = pViewShell->GetView();
+    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+    CPPUNIT_ASSERT_EQUAL(size_t(1), rMarkList.GetMarkCount());
+    SdrObject* pObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
+    return pObject;
+}
+
 } // end anonymous namespace
 
 void LOKitSearchTest::testSearch()
@@ -319,6 +330,8 @@ void LOKitSearchTest::testSearchInPDF()
                          mpCallbackRecorder->m_aSelection[0]);
 }
 
+// Test searching in document with mixed objects.
+// We have 2 objects: 1. Text Object, 2. Graphic Object with PDF
 void LOKitSearchTest::testSearchInMixedObject()
 {
     SdXImpressDocument* pXImpressDocument = createDoc("MixedTest1.odg");
@@ -334,7 +347,7 @@ void LOKitSearchTest::testSearchInMixedObject()
     SdPage* pPage = pViewShell->GetActualPage();
     CPPUNIT_ASSERT(pPage);
 
-    // Check page hase 2 objects only
+    // Check page has 2 objects only
     CPPUNIT_ASSERT_EQUAL(size_t(2), pPage->GetObjCount());
 
     // Check Object 1
@@ -403,6 +416,170 @@ void LOKitSearchTest::testSearchInMixedObject()
                          mpCallbackRecorder->m_aSearchResultSelection[0]);
 }
 
+// Test searching in document with mixed objects. We have 6 objects.
+void LOKitSearchTest::testSearchInMixedObject2()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("MixedTest2.odg");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    SdDrawDocument* pDocument = pXImpressDocument->GetDocShell()->GetDoc();
+    CPPUNIT_ASSERT(pDocument);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    // Check we have one page
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pDocument->GetSdPageCount(PageKind::Standard));
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    // Check page has 6 objects only
+    CPPUNIT_ASSERT_EQUAL(size_t(6), pPage->GetObjCount());
+
+    // Check we have the right objects that we expect
+
+    // Check Object 1
+    {
+        SdrObject* pObject = pPage->GetObj(0);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_TEXT), pObject->GetObjIdentifier());
+    }
+
+    // Check Object 2
+    {
+        SdrObject* pObject = pPage->GetObj(1);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_GRAF), pObject->GetObjIdentifier());
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+        auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Check Object 3
+    {
+        SdrObject* pObject = pPage->GetObj(2);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_CUSTOMSHAPE), pObject->GetObjIdentifier());
+    }
+
+    // Check Object 4
+    {
+        SdrObject* pObject = pPage->GetObj(3);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_CUSTOMSHAPE), pObject->GetObjIdentifier());
+    }
+
+    // Check Object 5
+    {
+        SdrObject* pObject = pPage->GetObj(4);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_GRAF), pObject->GetObjIdentifier());
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+        auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Svg,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Check Object 6
+    {
+        SdrObject* pObject = pPage->GetObj(5);
+        CPPUNIT_ASSERT(pObject);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_GRAF), pObject->GetObjIdentifier());
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+        auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Search "ABC" which is in all objects (2 times in Object 3)
+
+    // Object 1
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(0), lclGetSelectedObject(pViewShell));
+
+    // Object 2
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(1), lclGetSelectedObject(pViewShell));
+
+    // Object 3
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(2), lclGetSelectedObject(pViewShell));
+
+    // Object 3 again
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(4, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(2), lclGetSelectedObject(pViewShell));
+
+    // Object 4
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(5, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(3), lclGetSelectedObject(pViewShell));
+
+    // Object 5
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(6, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(4), lclGetSelectedObject(pViewShell));
+
+    // Object 6
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(7, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(5), lclGetSelectedObject(pViewShell));
+
+    // Loop to Object 1 again
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(8, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+    CPPUNIT_ASSERT_EQUAL(pPage->GetObj(0), lclGetSelectedObject(pViewShell));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(LOKitSearchTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/tiledrendering/data/MixedTest2.odg b/sd/qa/unit/tiledrendering/data/MixedTest2.odg
new file mode 100644
index 000000000000..2709707c1ba6
Binary files /dev/null and b/sd/qa/unit/tiledrendering/data/MixedTest2.odg differ
commit 0d733b8ed123e0156fd7618b28789a8db982af44
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sat May 30 15:47:35 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:47 2020 +0200

    sd: fix issue when PDF search doesn't send a search result + test
    
    This fixes the issue when PDF search doesn't send the search
    result, because of premature exit.
    
    Also add test which reproduces this issue and tests the behavior
    of searching in multiple objects.
    
    Change-Id: I3a676eeac36bde88c67e90a49583444b8595a346

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 8d8b11e43fa1..24037a0780ba 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -55,6 +55,7 @@ public:
     void testDontSearchInMasterPages();
     void testSearchInPDFNonExisting();
     void testSearchInPDF();
+    void testSearchInMixedObject();
 
     CPPUNIT_TEST_SUITE(LOKitSearchTest);
     CPPUNIT_TEST(testSearch);
@@ -65,6 +66,7 @@ public:
     CPPUNIT_TEST(testDontSearchInMasterPages);
     CPPUNIT_TEST(testSearchInPDFNonExisting);
     CPPUNIT_TEST(testSearchInPDF);
+    CPPUNIT_TEST(testSearchInMixedObject);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -317,6 +319,90 @@ void LOKitSearchTest::testSearchInPDF()
                          mpCallbackRecorder->m_aSelection[0]);
 }
 
+void LOKitSearchTest::testSearchInMixedObject()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("MixedTest1.odg");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    SdDrawDocument* pDocument = pXImpressDocument->GetDocShell()->GetDoc();
+    CPPUNIT_ASSERT(pDocument);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    // Check we have one page
+    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pDocument->GetSdPageCount(PageKind::Standard));
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    // Check page hase 2 objects only
+    CPPUNIT_ASSERT_EQUAL(size_t(2), pPage->GetObjCount());
+
+    // Check Object 1
+    {
+        SdrObject* pObject = pPage->GetObj(0);
+        CPPUNIT_ASSERT(pObject);
+
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_TEXT), pObject->GetObjIdentifier());
+    }
+
+    // Check Object 2
+    {
+        SdrObject* pObject = pPage->GetObj(1);
+        CPPUNIT_ASSERT(pObject);
+
+        CPPUNIT_ASSERT_EQUAL(sal_uInt16(OBJ_GRAF), pObject->GetObjIdentifier());
+
+        SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+        CPPUNIT_ASSERT(pGraphicObject);
+
+        Graphic aGraphic = pGraphicObject->GetGraphic();
+        auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT(pVectorGraphicData);
+
+        CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                             pVectorGraphicData->getVectorGraphicDataType());
+    }
+
+    // Let's try to search now
+
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(OString("3546, 3174, 738, 402"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search next
+
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(OString("8412, 6385, 519, 174"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+
+    // Search next again - we should get the first object again
+
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(3, mpCallbackRecorder->m_nSearchResultCount);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());
+
+    CPPUNIT_ASSERT_EQUAL(OString("3546, 3174, 738, 402"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(LOKitSearchTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/tiledrendering/data/MixedTest1.odg b/sd/qa/unit/tiledrendering/data/MixedTest1.odg
new file mode 100644
index 000000000000..db952318c735
Binary files /dev/null and b/sd/qa/unit/tiledrendering/data/MixedTest1.odg differ
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 50b2794973be..0bea27890a84 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -872,7 +872,7 @@ bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelecti
             {
                 ProvideNextTextObject ();
 
-                if (!mbEndOfSearch)
+                if (!mbEndOfSearch && !mpImpl->mbCurrentIsVectorGraphic)
                 {
                     // Remember the current position as the last one with a
                     // text object.
commit fcd40ce58f21cdb083589e9b1bb0c76373bc22ed
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sat May 30 13:10:04 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:47 2020 +0200

    sd: improve the test for LOKit search in PDF graphic
    
    Record how many times we het the search result back, so we can
    be sure that the search happend and don't just read the old
    values. Assert the search result selection rectangles and text
    selection rectangles.
    
    Add tools:Rectangle support for CPPUnit into sdmodeltestbase.hxx
    
    Change-Id: I0b22d2d2f66abdc0dd0d5ac13a1bfebaa470749a

diff --git a/sd/qa/unit/sdmodeltestbase.hxx b/sd/qa/unit/sdmodeltestbase.hxx
index 6469eba789fe..a0feaae81912 100644
--- a/sd/qa/unit/sdmodeltestbase.hxx
+++ b/sd/qa/unit/sdmodeltestbase.hxx
@@ -483,6 +483,22 @@ template<> struct assertion_traits<Color>
     }
 };
 
+template<> struct assertion_traits<tools::Rectangle>
+{
+    static bool equal( const tools::Rectangle& r1, const tools::Rectangle& r2 )
+    {
+        return r1 == r2;
+    }
+
+    static std::string toString( const tools::Rectangle& r)
+    {
+        OStringStream ost;
+        ost << "Rect P: [" << long(r.Top()) << ", " << long(r.Left()) << "]"
+            << "S: [" << long(r.GetWidth()) << ", " << long(r.GetHeight()) << "]";
+        return ost.str();
+    }
+};
+
 CPPUNIT_NS_END
 
 #endif
diff --git a/sd/qa/unit/tiledrendering/CallbackRecorder.hxx b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx
index fc5117cce6dc..7e6c8a42d07d 100644
--- a/sd/qa/unit/tiledrendering/CallbackRecorder.hxx
+++ b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx
@@ -51,6 +51,7 @@ struct CallbackRecorder
         , m_nPart(0)
         , m_nSelectionBeforeSearchResult(0)
         , m_nSelectionAfterSearchResult(0)
+        , m_nSearchResultCount(0)
     {
     }
 
@@ -62,6 +63,7 @@ struct CallbackRecorder
     std::vector<int> m_aSearchResultPart;
     int m_nSelectionBeforeSearchResult;
     int m_nSelectionAfterSearchResult;
+    int m_nSearchResultCount;
     /// For document size changed callback.
     osl::Condition m_aDocumentSizeCondition;
 
@@ -115,6 +117,7 @@ struct CallbackRecorder
             break;
             case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
             {
+                m_nSearchResultCount++;
                 m_aSearchResultSelection.clear();
                 m_aSearchResultPart.clear();
                 boost::property_tree::ptree aTree;
diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 33257f12d4ab..8d8b11e43fa1 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -292,21 +292,29 @@ void LOKitSearchTest::testSearchInPDF()
     CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
                          pVectorGraphicData->getVectorGraphicDataType());
 
+    // Search
     lcl_search("ABC");
 
     CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(1, mpCallbackRecorder->m_nSearchResultCount);
 
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(OString("3763, 1331, 1432, 483"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+    CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(3763, 1331), Size(1433, 484)),
+                         mpCallbackRecorder->m_aSelection[0]);
 
-    CPPUNIT_ASSERT_EQUAL(long(3763), mpCallbackRecorder->m_aSelection[0].Left());
-    CPPUNIT_ASSERT_EQUAL(long(1331), mpCallbackRecorder->m_aSelection[0].Top());
-    CPPUNIT_ASSERT_EQUAL(long(1433), mpCallbackRecorder->m_aSelection[0].GetWidth());
-    CPPUNIT_ASSERT_EQUAL(long(484), mpCallbackRecorder->m_aSelection[0].GetHeight());
-
+    // Search again - same result
     lcl_search("ABC");
+
     CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+    CPPUNIT_ASSERT_EQUAL(2, mpCallbackRecorder->m_nSearchResultCount);
 
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+    CPPUNIT_ASSERT_EQUAL(OString("3763, 1331, 1432, 483"),
+                         mpCallbackRecorder->m_aSearchResultSelection[0]);
+    CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(3763, 1331), Size(1433, 484)),
+                         mpCallbackRecorder->m_aSelection[0]);
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(LOKitSearchTest);
commit 203aaf2559758b2f344ab3a2e92fb7bd350c0636
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri May 29 23:52:50 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:47 2020 +0200

    vcl: add search start position support for VectorGraphicSearch
    
    By default we start at the begin of the page, but with this change
    make it possible to start at the end. This makes it possible to
    search in the backwards direction (set the start position at to
    the end and search with "previous").
    
    Change-Id: I78fb1461b86bf9eab2f91c3b9a81cbb5c6557332

diff --git a/include/vcl/VectorGraphicSearch.hxx b/include/vcl/VectorGraphicSearch.hxx
index a00c212ad61c..b67c63a844d8 100644
--- a/include/vcl/VectorGraphicSearch.hxx
+++ b/include/vcl/VectorGraphicSearch.hxx
@@ -21,6 +21,12 @@
 
 class SearchContext;
 
+enum class SearchStartPosition
+{
+    Begin,
+    End
+};
+
 class VCL_DLLPUBLIC VectorGraphicSearch final
 {
 private:
@@ -29,12 +35,14 @@ private:
     Graphic maGraphic;
     std::unique_ptr<SearchContext> mpSearchContext;
 
-    bool searchPDF(std::shared_ptr<VectorGraphicData> const& rData, OUString const& rSearchString);
+    bool searchPDF(std::shared_ptr<VectorGraphicData> const& rData, OUString const& rSearchString,
+                   SearchStartPosition eStartPosition);
 
 public:
     VectorGraphicSearch(Graphic const& rGraphic);
     ~VectorGraphicSearch();
-    bool search(OUString const& rSearchString);
+    bool search(OUString const& rSearchString,
+                SearchStartPosition eStartPosition = SearchStartPosition::Begin);
     basegfx::B2DSize pageSize();
     bool next();
     bool previous();
diff --git a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
index 7962c23f4e8f..5f65b4ba7e3d 100644
--- a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
+++ b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
@@ -93,32 +93,71 @@ void VectorGraphicSearchTest::testNextPrevious()
     Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
     aGraphic.makeAvailable();
 
-    VectorGraphicSearch aSearch(aGraphic);
-    CPPUNIT_ASSERT_EQUAL(true, aSearch.search("lazy"));
+    { // Start from the beginning of the page
+        VectorGraphicSearch aSearch(aGraphic);
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.search("lazy"));
 
-    // next - first match found
-    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
-    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+        // no previous - we are at the begin
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(0, aSearch.index()); // nothing was yet found, so it is 0
 
-    // next - second match found
-    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
-    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+        // next - first position found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
 
-    // next - not found, index unchanged
-    CPPUNIT_ASSERT_EQUAL(false, aSearch.next());
-    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+        // next - second position found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
 
-    // previous - first match
-    CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
-    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+        // next - not found, index unchanged
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
 
-    // previous - not found, index unchanged
-    CPPUNIT_ASSERT_EQUAL(false, aSearch.previous());
-    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+        // previous - first position
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
 
-    // next - second match found
-    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
-    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+        // previous - not found, index unchanged
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+        // next - second position found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+    }
+
+    { // Start from the end of the page
+        VectorGraphicSearch aSearch(aGraphic);
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.search("lazy", SearchStartPosition::End));
+
+        // no next - we are at the end
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(0, aSearch.index()); // nothing was yet found, so it is 0
+
+        // previous - second position found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+        // previous - first position found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+        // previous - not found, index unchanged
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+        // next - second position
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+        // next - not found, index unchanged
+        CPPUNIT_ASSERT_EQUAL(false, aSearch.next());
+        CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+        // previous - first match found
+        CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+        CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+    }
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(VectorGraphicSearchTest);
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index eb2199c7948d..4b2aedad1bdc 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -42,14 +42,17 @@ public:
     FPDF_PAGE mpPage;
     FPDF_TEXTPAGE mpTextPage;
     OUString maSearchString;
+    SearchStartPosition meStartPosition;
     FPDF_SCHHANDLE mpSearchHandle;
 
-    SearchContext(FPDF_DOCUMENT pPdfDocument, sal_Int32 nPageIndex, OUString const& rSearchString)
+    SearchContext(FPDF_DOCUMENT pPdfDocument, sal_Int32 nPageIndex, OUString const& rSearchString,
+                  SearchStartPosition eStartPosition)
         : mpPdfDocument(pPdfDocument)
         , mnPageIndex(nPageIndex)
         , mpPage(nullptr)
         , mpTextPage(nullptr)
         , maSearchString(rSearchString)
+        , meStartPosition(eStartPosition)
         , mpSearchHandle(nullptr)
     {
     }
@@ -91,7 +94,17 @@ public:
             return false;
 
         FPDF_WIDESTRING pString = reinterpret_cast<FPDF_WIDESTRING>(maSearchString.getStr());
-        mpSearchHandle = FPDFText_FindStart(mpTextPage, pString, 0, 0);
+
+        // Index where to start to search. -1 => at the end
+        int nStartIndex = meStartPosition == SearchStartPosition::End ? -1 : 0;
+
+        // FPDF_MATCHCASE, FPDF_MATCHWHOLEWORD, FPDF_CONSECUTIVE
+        // FPDF_MATCHCASE - If not set, it will not match case by default.
+        // FPDF_MATCHWHOLEWORD - If not set, it will not match the whole word by default.
+        // FPDF_CONSECUTIVE - If not set, it will skip past the current match to look for the next match.
+        int nSearchFlags = 0;
+
+        mpSearchHandle = FPDFText_FindStart(mpTextPage, pString, nSearchFlags, nStartIndex);
 
         return mpSearchHandle != nullptr;
     }
@@ -182,19 +195,20 @@ VectorGraphicSearch::~VectorGraphicSearch()
     FPDF_DestroyLibrary();
 }
 
-bool VectorGraphicSearch::search(OUString const& rSearchString)
+bool VectorGraphicSearch::search(OUString const& rSearchString, SearchStartPosition eStartPosition)
 {
     auto pData = maGraphic.getVectorGraphicData();
 
     if (pData && pData->getVectorGraphicDataType() == VectorGraphicDataType::Pdf)
     {
-        return searchPDF(pData, rSearchString);
+        return searchPDF(pData, rSearchString, eStartPosition);
     }
     return false;
 }
 
 bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData,
-                                    OUString const& rSearchString)
+                                    OUString const& rSearchString,
+                                    SearchStartPosition eStartPosition)
 {
     if (rSearchString.isEmpty())
         return false;
@@ -230,8 +244,8 @@ bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rD
 
     sal_Int32 nPageIndex = std::max(rData->getPageIndex(), 0);
 
-    mpSearchContext.reset(
-        new SearchContext(mpImplementation->mpPdfDocument, nPageIndex, rSearchString));
+    mpSearchContext.reset(new SearchContext(mpImplementation->mpPdfDocument, nPageIndex,
+                                            rSearchString, eStartPosition));
 
     return mpSearchContext->initialize();
 }
commit 11035706ebd238eaac37a69c60280b91c6310c41
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri May 29 23:26:51 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:46 2020 +0200

    vcl: add "previous" search to VectorGraphicSearch
    
    Previous moves backwards in the search matches.
    
    Change-Id: I88d402e0b8cb9dc4fd93e7f1ce5b08fb42aadd06

diff --git a/include/vcl/VectorGraphicSearch.hxx b/include/vcl/VectorGraphicSearch.hxx
index 5420e161448b..a00c212ad61c 100644
--- a/include/vcl/VectorGraphicSearch.hxx
+++ b/include/vcl/VectorGraphicSearch.hxx
@@ -37,6 +37,7 @@ public:
     bool search(OUString const& rSearchString);
     basegfx::B2DSize pageSize();
     bool next();
+    bool previous();
     int index();
     std::vector<basegfx::B2DRectangle> getTextRectangles();
 };
diff --git a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
index 01022a3fe225..7962c23f4e8f 100644
--- a/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
+++ b/vcl/qa/cppunit/VectorGraphicSearchTest.cxx
@@ -26,9 +26,11 @@ class VectorGraphicSearchTest : public test::BootstrapFixtureBase
     }
 
     void test();
+    void testNextPrevious();
 
     CPPUNIT_TEST_SUITE(VectorGraphicSearchTest);
     CPPUNIT_TEST(test);
+    CPPUNIT_TEST(testNextPrevious);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -81,6 +83,44 @@ void VectorGraphicSearchTest::test()
     CPPUNIT_ASSERT_DOUBLES_EQUAL(6381.04, aRectangles[3].getMaxY(), 1E-2);
 }
 
+// Test next and previous work as expected to move
+// between search matches.
+void VectorGraphicSearchTest::testNextPrevious()
+{
+    OUString aURL = getFullUrl("Pangram.pdf");
+    SvFileStream aStream(aURL, StreamMode::READ);
+    GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+    Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
+    aGraphic.makeAvailable();
+
+    VectorGraphicSearch aSearch(aGraphic);
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.search("lazy"));
+
+    // next - first match found
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+    // next - second match found
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+    // next - not found, index unchanged
+    CPPUNIT_ASSERT_EQUAL(false, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+
+    // previous - first match
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.previous());
+    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+    // previous - not found, index unchanged
+    CPPUNIT_ASSERT_EQUAL(false, aSearch.previous());
+    CPPUNIT_ASSERT_EQUAL(34, aSearch.index());
+
+    // next - second match found
+    CPPUNIT_ASSERT_EQUAL(true, aSearch.next());
+    CPPUNIT_ASSERT_EQUAL(817, aSearch.index());
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(VectorGraphicSearchTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
index 56c00efa172a..eb2199c7948d 100644
--- a/vcl/source/graphic/VectorGraphicSearch.cxx
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -103,6 +103,13 @@ public:
         return false;
     }
 
+    bool previous()
+    {
+        if (mpSearchHandle)
+            return FPDFText_FindPrev(mpSearchHandle);
+        return false;
+    }
+
     int index()
     {
         if (mpSearchHandle)
@@ -244,6 +251,13 @@ bool VectorGraphicSearch::next()
     return false;
 }
 
+bool VectorGraphicSearch::previous()
+{
+    if (mpSearchContext)
+        return mpSearchContext->previous();
+    return false;
+}
+
 int VectorGraphicSearch::index()
 {
     if (mpSearchContext)
commit 407710069092a4fa6b833a0670a25531ea5048a0
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri May 29 23:06:57 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:46 2020 +0200

    sd: fix not found case in PDF search + add PDF Search tests
    
    When searching the PDF and the search text is not found (anymore)
    in the current VectorGraphicSearch, we need to remove it and mark
    that we don't currently search in a vector graphic (PDF) anymore.
    This wasn't handled correctly and caused a crash.
    
    In addition add a LOKit test for search into a PDF document, to
    make sure the not-found case and usual searching case are working
    correctly.
    
    Change-Id: I663a6b2cf4879f11d62e440ea0c35ffcd205f81f

diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index 4474bd8e4751..33257f12d4ab 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -24,10 +24,14 @@
 #include <sfx2/viewfrm.hxx>
 #include <svl/srchitem.hxx>
 #include <svl/stritem.hxx>
+#include <vcl/scheduler.hxx>
 #include <ViewShellBase.hxx>
 #include <ViewShell.hxx>
 #include <unomodel.hxx>
 
+#include <sdpage.hxx>
+#include <svx/svdograf.hxx>
+
 #include <com/sun/star/frame/Desktop.hpp>
 
 using namespace css;
@@ -38,7 +42,7 @@ private:
     static constexpr char DATA_DIRECTORY[] = "/sd/qa/unit/tiledrendering/data/";
 
 public:
-    LOKitSearchTest() {}
+    LOKitSearchTest() = default;
 
     virtual void setUp() override;
     virtual void tearDown() override;
@@ -49,6 +53,8 @@ public:
     void testSearchAllNotifications();
     void testSearchAllFollowedBySearch();
     void testDontSearchInMasterPages();
+    void testSearchInPDFNonExisting();
+    void testSearchInPDF();
 
     CPPUNIT_TEST_SUITE(LOKitSearchTest);
     CPPUNIT_TEST(testSearch);
@@ -57,6 +63,8 @@ public:
     CPPUNIT_TEST(testSearchAllNotifications);
     CPPUNIT_TEST(testSearchAllFollowedBySearch);
     CPPUNIT_TEST(testDontSearchInMasterPages);
+    CPPUNIT_TEST(testSearchInPDFNonExisting);
+    CPPUNIT_TEST(testSearchInPDF);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -96,9 +104,11 @@ LOKitSearchTest::createDoc(const char* pName, const uno::Sequence<beans::Propert
 {
     if (mxComponent.is())
         mxComponent->dispose();
+
     mxComponent = loadFromDesktop(m_directories.getURLFromSrc(DATA_DIRECTORY)
-                                      + OUString::createFromAscii(pName),
-                                  "com.sun.star.presentation.PresentationDocument");
+                                  + OUString::createFromAscii(pName));
+
+    CPPUNIT_ASSERT(mxComponent.is());
     SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
     CPPUNIT_ASSERT(pImpressDocument);
     pImpressDocument->initializeForTiledRendering(rArguments);
@@ -109,15 +119,20 @@ namespace
 {
 void lcl_search(const OUString& rKey, bool bFindAll = false)
 {
+    Scheduler::ProcessEventsToIdle();
+    SvxSearchCmd eSearch = bFindAll ? SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND;
+
     uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({
         { "SearchItem.SearchString", uno::makeAny(rKey) },
         { "SearchItem.Backward", uno::makeAny(false) },
-        { "SearchItem.Command", uno::makeAny(static_cast<sal_uInt16>(
-                                    bFindAll ? SvxSearchCmd::FIND_ALL : SvxSearchCmd::FIND)) },
+        { "SearchItem.Command", uno::makeAny(sal_uInt16(eSearch)) },
     }));
+
     comphelper::dispatchCommand(".uno:ExecuteSearch", aPropertyValues);
+    Scheduler::ProcessEventsToIdle();
 }
-}
+
+} // end anonymous namespace
 
 void LOKitSearchTest::testSearch()
 {
@@ -228,6 +243,72 @@ void LOKitSearchTest::testDontSearchInMasterPages()
     CPPUNIT_ASSERT_EQUAL(false, mpCallbackRecorder->m_bFound);
 }
 
+void LOKitSearchTest::testSearchInPDFNonExisting()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    SdrObject* pObject = pPage->GetObj(0);
+    CPPUNIT_ASSERT(pObject);
+
+    SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+    CPPUNIT_ASSERT(pGraphicObject);
+
+    Graphic aGraphic = pGraphicObject->GetGraphic();
+    auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+    CPPUNIT_ASSERT(pVectorGraphicData);
+    CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                         pVectorGraphicData->getVectorGraphicDataType());
+
+    lcl_search("NonExisting");
+
+    CPPUNIT_ASSERT_EQUAL(false, mpCallbackRecorder->m_bFound);
+}
+
+void LOKitSearchTest::testSearchInPDF()
+{
+    SdXImpressDocument* pXImpressDocument = createDoc("PDFSearch.pdf");
+    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    mpCallbackRecorder->registerCallbacksFor(pViewShell->GetViewShellBase());
+
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+
+    SdrObject* pObject = pPage->GetObj(0);
+    CPPUNIT_ASSERT(pObject);
+
+    SdrGrafObj* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject);
+    CPPUNIT_ASSERT(pGraphicObject);
+
+    Graphic aGraphic = pGraphicObject->GetGraphic();
+    auto const& pVectorGraphicData = aGraphic.getVectorGraphicData();
+    CPPUNIT_ASSERT(pVectorGraphicData);
+    CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf,
+                         pVectorGraphicData->getVectorGraphicDataType());
+
+    lcl_search("ABC");
+
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+
+    CPPUNIT_ASSERT_EQUAL(long(3763), mpCallbackRecorder->m_aSelection[0].Left());
+    CPPUNIT_ASSERT_EQUAL(long(1331), mpCallbackRecorder->m_aSelection[0].Top());
+    CPPUNIT_ASSERT_EQUAL(long(1433), mpCallbackRecorder->m_aSelection[0].GetWidth());
+    CPPUNIT_ASSERT_EQUAL(long(484), mpCallbackRecorder->m_aSelection[0].GetHeight());
+
+    lcl_search("ABC");
+    CPPUNIT_ASSERT_EQUAL(true, mpCallbackRecorder->m_bFound);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(LOKitSearchTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/tiledrendering/data/PDFSearch.pdf b/sd/qa/unit/tiledrendering/data/PDFSearch.pdf
new file mode 100644
index 000000000000..ea8a0919a4a1
Binary files /dev/null and b/sd/qa/unit/tiledrendering/data/PDFSearch.pdf differ
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 6b143f2dd39b..50b2794973be 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -840,6 +840,11 @@ bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelecti
                         aSubSelections.push_back(aSubSelection);
                     mpView->MarkObj(mpObj, pPageView, false, false, aSubSelections);
                 }
+                else
+                {
+                    mpImpl->mbCurrentIsVectorGraphic = false;
+                    mpImpl->mpVectorGraphicSearch.reset();
+                }
             }
             else
             {
@@ -1246,6 +1251,16 @@ void SdOutliner::ProvideNextTextObject()
 
                             mpDrawDocument->GetDocSh()->SetWaitCursor( false );
                         }
+                        else
+                        {
+                            mpImpl->mbCurrentIsVectorGraphic = false;
+                            mpImpl->mpVectorGraphicSearch.reset();
+                        }
+                    }
+                    else
+                    {
+                        mpImpl->mbCurrentIsVectorGraphic = false;
+                        mpImpl->mpVectorGraphicSearch.reset();
                     }
                 }
                 else
commit 2e1d6f320b58e4dee35d836fbb4d1ad3cc56fb36
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Fri May 29 18:18:40 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Mon Jun 1 08:14:45 2020 +0200

    sd: move LOK search tests out of tiledrendering.cxx
    
    Change-Id: I76ff3e251afc877b0dcf54d772da95bb7a60e823

diff --git a/sd/CppunitTest_sd_tiledrendering.mk b/sd/CppunitTest_sd_tiledrendering.mk
index 9b643c869a84..3b555860f963 100644
--- a/sd/CppunitTest_sd_tiledrendering.mk
+++ b/sd/CppunitTest_sd_tiledrendering.mk
@@ -14,6 +14,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sd_tiledrendering))
 $(eval $(call gb_CppunitTest_use_common_precompiled_header,sd_tiledrendering))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,sd_tiledrendering, \
+    sd/qa/unit/tiledrendering/LOKitSearchTest \
     sd/qa/unit/tiledrendering/tiledrendering \
 ))
 
diff --git a/sd/qa/unit/sdmodeltestbase.hxx b/sd/qa/unit/sdmodeltestbase.hxx
index 9cdb3214f353..6469eba789fe 100644
--- a/sd/qa/unit/sdmodeltestbase.hxx
+++ b/sd/qa/unit/sdmodeltestbase.hxx
@@ -73,7 +73,7 @@ pFilterName: <node oor:Name="...">
 pTypeName: <prop oor:Name="Type">...</prop>
 nFormatType: <prop oor:name="Flags">...</prop>
 */
-FileFormat aFileFormats[] =
+static FileFormat aFileFormats[] =
 {
     { "odp",  "impress8", "impress8", "", ODP_FORMAT_TYPE },
     { "ppt",  "MS PowerPoint 97", "impress_MS_PowerPoint_97", "sdfilt", PPT_FORMAT_TYPE },
diff --git a/sd/qa/unit/tiledrendering/CallbackRecorder.hxx b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx
new file mode 100644
index 000000000000..fc5117cce6dc
--- /dev/null
+++ b/sd/qa/unit/tiledrendering/CallbackRecorder.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <boost/property_tree/json_parser.hpp>
+#include <comphelper/string.hxx>
+#include <osl/conditn.hxx>
+#include <sfx2/viewsh.hxx>
+
+namespace
+{
+std::vector<OUString> lcl_convertSeparated(const OUString& rString, sal_Unicode nSeparator)
+{
+    std::vector<OUString> aRet;
+
+    sal_Int32 nIndex = 0;
+    do
+    {
+        OUString aToken = rString.getToken(0, nSeparator, nIndex);
+        aToken = aToken.trim();
+        if (!aToken.isEmpty())
+            aRet.push_back(aToken);
+    } while (nIndex >= 0);
+
+    return aRet;
+}
+
+void lcl_convertRectangle(const OUString& rString, tools::Rectangle& rRectangle)
+{
+    uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(rString);
+    CPPUNIT_ASSERT(aSeq.getLength() == 4 || aSeq.getLength() == 5);
+    rRectangle.setX(aSeq[0].toInt32());
+    rRectangle.setY(aSeq[1].toInt32());
+    rRectangle.setWidth(aSeq[2].toInt32());
+    rRectangle.setHeight(aSeq[3].toInt32());
+}
+}
+
+struct CallbackRecorder
+{
+    CallbackRecorder()
+        : m_bFound(true)
+        , m_nPart(0)
+        , m_nSelectionBeforeSearchResult(0)
+        , m_nSelectionAfterSearchResult(0)
+    {
+    }
+
+    tools::Rectangle m_aInvalidation;
+    std::vector<::tools::Rectangle> m_aSelection;
+    bool m_bFound;
+    sal_Int32 m_nPart;
+    std::vector<OString> m_aSearchResultSelection;
+    std::vector<int> m_aSearchResultPart;
+    int m_nSelectionBeforeSearchResult;
+    int m_nSelectionAfterSearchResult;
+    /// For document size changed callback.
+    osl::Condition m_aDocumentSizeCondition;
+
+    static void callback(int nType, const char* pPayload, void* pData)
+    {
+        static_cast<CallbackRecorder*>(pData)->processCallback(nType, pPayload);
+    }
+
+    void processCallback(int nType, const char* pPayload)
+    {
+        switch (nType)
+        {
+            case LOK_CALLBACK_INVALIDATE_TILES:
+            {
+                OUString aPayload = OUString::createFromAscii(pPayload);
+                if (aPayload != "EMPTY" && m_aInvalidation.IsEmpty())
+                    lcl_convertRectangle(aPayload, m_aInvalidation);
+            }
+            break;
+            case LOK_CALLBACK_TEXT_SELECTION:
+            {
+                OUString aPayload = OUString::createFromAscii(pPayload);
+                m_aSelection.clear();
+                for (const OUString& rString : lcl_convertSeparated(aPayload, u';'))
+                {
+                    ::tools::Rectangle aRectangle;
+                    lcl_convertRectangle(rString, aRectangle);
+                    m_aSelection.push_back(aRectangle);
+                }
+                if (m_aSearchResultSelection.empty())
+                    ++m_nSelectionBeforeSearchResult;
+                else
+                    ++m_nSelectionAfterSearchResult;
+            }
+            break;
+            case LOK_CALLBACK_SEARCH_NOT_FOUND:
+            {
+                m_bFound = false;
+            }
+            break;
+            case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
+            {
+                m_aDocumentSizeCondition.set();
+            }
+            break;
+            case LOK_CALLBACK_SET_PART:
+            {
+                OUString aPayload = OUString::createFromAscii(pPayload);
+                m_nPart = aPayload.toInt32();
+            }
+            break;
+            case LOK_CALLBACK_SEARCH_RESULT_SELECTION:
+            {
+                m_aSearchResultSelection.clear();
+                m_aSearchResultPart.clear();
+                boost::property_tree::ptree aTree;
+                std::stringstream aStream(pPayload);
+                boost::property_tree::read_json(aStream, aTree);
+                for (const boost::property_tree::ptree::value_type& rValue :
+                     aTree.get_child("searchResultSelection"))
+                {
+                    m_aSearchResultSelection.emplace_back(
+                        rValue.second.get<std::string>("rectangles").c_str());
+                    m_aSearchResultPart.push_back(
+                        std::atoi(rValue.second.get<std::string>("part").c_str()));
+                }
+            }
+            break;
+        }
+    }
+
+    void registerCallbacksFor(SfxViewShell& rViewShell)
+    {
+        rViewShell.registerLibreOfficeKitViewCallback(&CallbackRecorder::callback, this);
+    }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
new file mode 100644
index 000000000000..4474bd8e4751
--- /dev/null
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "../sdmodeltestbase.hxx"
+#include "CallbackRecorder.hxx"
+
+#include <test/bootstrapfixture.hxx>
+#include <test/helper/transferable.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/dispatchcommand.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/stritem.hxx>
+#include <ViewShellBase.hxx>
+#include <ViewShell.hxx>
+#include <unomodel.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+
+using namespace css;
+
+class LOKitSearchTest : public SdModelTestBase, public XmlTestTools
+{
+private:
+    static constexpr char DATA_DIRECTORY[] = "/sd/qa/unit/tiledrendering/data/";
+
+public:
+    LOKitSearchTest() {}
+
+    virtual void setUp() override;
+    virtual void tearDown() override;
+
+    void testSearch();
+    void testSearchAll();
+    void testSearchAllSelections();
+    void testSearchAllNotifications();

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list