[Libreoffice-commits] core.git: Branch 'feature/drawinglayercore' - 48 commits - chart2/qa chart2/source compilerplugins/clang cui/inc cui/source download.lst drawinglayer/CppunitTest_drawinglayer_border.mk drawinglayer/inc drawinglayer/Library_drawinglayercore.mk drawinglayer/Library_drawinglayer.mk drawinglayer/Module_drawinglayer.mk drawinglayer/source editeng/inc editeng/qa editeng/source emfio/CppunitTest_emfio_emf_test.mk emfio/Library_emfio.mk external/libnumbertext filter/Library_pdffilter.mk filter/Library_svgfilter.mk filter/source include/basegfx include/drawinglayer include/editeng include/o3tl include/svx include/vcl lingucomponent/source o3tl/qa offapi/com officecfg/registry oox/source Repository.mk sc/CppunitTest_sc_ucalc.mk sc/Library_sc.mk sc/source sd/CppunitTest_sd_tiledrendering.mk sd/CppunitTest_sd_uimpress.mk sd/Library_sd.mk sd/qa sd/source sfx2/Library_sfx.mk sfx2/source solenv/flatpak-manifest.in svgio/CppunitTest_svgio.mk svgio/Library_svgio.mk svl/qa svl/source svx/Cppu nitTest_svx_unit.mk svx/Library_svxcore.mk svx/Library_svx.mk svx/qa svx/sdi svx/source svx/uiconfig sw/CppunitTest_sw_core_doc.mk sw/CppunitTest_sw_uwriter.mk sw/inc sw/Library_sw.mk sw/Library_swui.mk sw/qa sw/source toolkit/source vcl/inc vcl/Library_vcl.mk vcl/qa vcl/source vcl/unx xmloff/source

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Tue Jun 2 17:16:43 UTC 2020


Rebased ref, commits from common ancestor:
commit 5f83adadfa5ef4a79c687aa147b7f91f21d79ae9
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: Tue Jun 2 19:12:50 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 171900f73fa9..5308de563a08 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -840,13 +840,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 2f2f32166b749c6d721f1c470bb4a591953813aa
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: Tue Jun 2 19:12:50 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 8c88aafb2217..b64302dfb8d4 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(), sal_Int32(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 b6cb651ca396675280c21ca64eec51e9c244e205
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: Tue Jun 2 19:12:50 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 e09a9f67d887..171900f73fa9 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -840,7 +840,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;
 
@@ -1241,12 +1249,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 665ce34ee998395d373cba31bc4cd0ce7ef32d7b
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: Tue Jun 2 19:12:49 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 c30b2efe486a1e3f132b77ade71cbcb28743bec4
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: Tue Jun 2 19:12:49 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 b1d6d17acf55..8c88aafb2217 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 896513d1b2d62f00f756dc334ec84333bc4de646
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: Tue Jun 2 19:12:49 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 e8f7484320e3..b1d6d17acf55 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(), sal_Int32(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 9e219391612de66473ebbc9ea75dec78a0f804e5
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: Tue Jun 2 19:12:48 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 fc7c9257e1f8..e8f7484320e3 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 6b52ece7e3b42a98819e4db992d86fbb59094463
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: Tue Jun 2 19:12:48 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 052dc030603964b17ac3e3a2053cb9b2cdef434a
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: Tue Jun 2 19:12:48 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 8511a44f73b5..e09a9f67d887 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -1173,6 +1173,7 @@ void SdOutliner::ProvideNextTextObject()
     mbFoundObject = false;
 
     // reset the vector search
+    mpImpl->mbCurrentIsVectorGraphic = false;
     mpImpl->mpVectorGraphicSearch.reset();
 
     mpView->UnmarkAllObj (mpView->GetSdrPageView());
@@ -1208,6 +1209,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)
             {
@@ -1241,34 +1243,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
                     {
@@ -1301,6 +1299,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 46ee265df632f31757b05b596c9e06766acad097
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: Tue Jun 2 19:12: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 76e8c59404a9..fc7c9257e1f8 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 fdeff19e32cc05d1ac2d22a42f3c5397b65ab2c1
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: Tue Jun 2 19:12:47 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 694d16cd1078236f7916d9c3367ad0a2689cb8c6
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: Tue Jun 2 19:12: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 8f1104df1c78..8511a44f73b5 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -885,7 +885,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 0a1f85b91153cca5a25d7dabfa1be169db13f1f2
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: Tue Jun 2 19:12: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 03fdf1f450f582e81b17031112dd2498d168d308
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: Tue Jun 2 19:12:46 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 dd37c9fc98cf..76e8c59404a9 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(), sal_Int32(0));
 
-    mpSearchContext.reset(
-        new SearchContext(mpImplementation->mpPdfDocument, nPageIndex, rSearchString));
+    mpSearchContext.reset(new SearchContext(mpImplementation->mpPdfDocument, nPageIndex,
+                                            rSearchString, eStartPosition));
 
     return mpSearchContext->initialize();
 }
commit 2ca67f8d90e8531ebd553f490009245342ea94c2
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: Tue Jun 2 19:12: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 36eeae6d2a6c..dd37c9fc98cf 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 8136df26838aa9b7175fce12892113701ceebac5
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: Tue Jun 2 19:12: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 a5322876e9c9..8f1104df1c78 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -853,6 +853,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
             {
@@ -1259,6 +1264,16 @@ void SdOutliner::ProvideNextTextObject()
 
                             mpDrawDocument->GetDocSh()->SetWaitCursor( false );
                         }
+                        else
+                        {
+                            mpImpl->mbCurrentIsVectorGraphic = false;
+                            mpImpl->mpVectorGraphicSearch.reset();
+                        }
+                    }
+                    else
+                    {
+                        mpImpl->mbCurrentIsVectorGraphic = false;
+                        mpImpl->mpVectorGraphicSearch.reset();
                     }
                 }
                 else
commit 067bb9ed6b84111bb952e9d6d7771ad2b365d3ad
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: Tue Jun 2 19:12:46 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