summaryrefslogtreecommitdiffstats
path: root/vcl/source/graphic/VectorGraphicSearch.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/graphic/VectorGraphicSearch.cxx')
-rw-r--r--vcl/source/graphic/VectorGraphicSearch.cxx306
1 files changed, 306 insertions, 0 deletions
diff --git a/vcl/source/graphic/VectorGraphicSearch.cxx b/vcl/source/graphic/VectorGraphicSearch.cxx
new file mode 100644
index 000000000..63dae6e52
--- /dev/null
+++ b/vcl/source/graphic/VectorGraphicSearch.cxx
@@ -0,0 +1,306 @@
+/* -*- 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 <vcl/VectorGraphicSearch.hxx>
+
+#include <vcl/filter/PDFiumLibrary.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <sal/config.h>
+
+namespace
+{
+class SearchContext
+{
+private:
+ std::unique_ptr<vcl::pdf::PDFiumDocument>& mpPdfDocument;
+ std::unique_ptr<vcl::pdf::PDFiumPage> mpPage;
+ std::unique_ptr<vcl::pdf::PDFiumTextPage> mpTextPage;
+ std::unique_ptr<vcl::pdf::PDFiumSearchHandle> mpSearchHandle;
+
+public:
+ sal_Int32 mnPageIndex;
+ int mnCurrentIndex;
+ OUString maSearchString;
+ VectorGraphicSearchOptions maOptions;
+
+ SearchContext(std::unique_ptr<vcl::pdf::PDFiumDocument>& pPdfDocument, sal_Int32 nPageIndex)
+ : mpPdfDocument(pPdfDocument)
+ , mnPageIndex(nPageIndex)
+ , mnCurrentIndex(-1)
+ {
+ }
+
+ ~SearchContext()
+ {
+ if (mpSearchHandle)
+ mpSearchHandle.reset();
+ if (mpTextPage)
+ mpTextPage.reset();
+ if (mpPage)
+ mpPage.reset();
+ }
+
+ basegfx::B2DSize getPageSize()
+ {
+ basegfx::B2DSize aSize;
+ if (!mpPdfDocument)
+ return aSize;
+
+ basegfx::B2DSize aPDFSize = mpPdfDocument->getPageSize(mnPageIndex);
+ aSize = basegfx::B2DSize(convertPointToMm100(aPDFSize.getX()),
+ convertPointToMm100(aPDFSize.getY()));
+ return aSize;
+ }
+
+ bool initialize(OUString const& rSearchString, VectorGraphicSearchOptions const& rOptions)
+ {
+ if (!mpPdfDocument)
+ return false;
+
+ if (rSearchString == maSearchString)
+ return true;
+
+ if (mpSearchHandle)
+ mpSearchHandle.reset();
+
+ if (mpTextPage)
+ mpTextPage.reset();
+
+ if (mpPage)
+ mpPage.reset();
+
+ maSearchString = rSearchString;
+ maOptions = rOptions;
+
+ mpPage = mpPdfDocument->openPage(mnPageIndex);
+ if (!mpPage)
+ return false;
+
+ mpTextPage = mpPage->getTextPage();
+ if (!mpTextPage)
+ return false;
+
+ // Index where to start to search. -1 => at the end
+ int nStartIndex = maOptions.meStartPosition == SearchStartPosition::End ? -1 : 0;
+
+ if (mnCurrentIndex >= 0)
+ nStartIndex = mnCurrentIndex;
+
+ // vcl::pdf::PDFFindFlags::MatchCase, vcl::pdf::PDFFindFlags::MatchWholeWord, vcl::pdf::PDFFindFlags::Consecutive
+ // vcl::pdf::PDFFindFlags::MatchCase - If not set, it will not match case by default.
+ // vcl::pdf::PDFFindFlags::MatchWholeWord - If not set, it will not match the whole word by default.
+ // vcl::pdf::PDFFindFlags::Consecutive - If not set, it will skip past the current match to look for the next match.
+ vcl::pdf::PDFFindFlags nSearchFlags{};
+ if (maOptions.mbMatchCase)
+ nSearchFlags |= vcl::pdf::PDFFindFlags::MatchCase;
+ if (maOptions.mbMatchWholeWord)
+ nSearchFlags |= vcl::pdf::PDFFindFlags::MatchWholeWord;
+
+ mpSearchHandle = mpTextPage->findStart(maSearchString, nSearchFlags, nStartIndex);
+
+ return mpSearchHandle != nullptr;
+ }
+
+ bool next()
+ {
+ if (mpSearchHandle && mpSearchHandle->findNext())
+ {
+ mnCurrentIndex = index();
+ return true;
+ }
+ return false;
+ }
+
+ bool previous()
+ {
+ if (mpSearchHandle && mpSearchHandle->findPrev())
+ {
+ mnCurrentIndex = index();
+ return true;
+ }
+ return false;
+ }
+
+ int index()
+ {
+ if (mpSearchHandle)
+ return mpSearchHandle->getSearchResultIndex();
+ return -1;
+ }
+
+ int size()
+ {
+ if (mpSearchHandle)
+ return mpSearchHandle->getSearchCount();
+ return -1;
+ }
+
+ std::vector<basegfx::B2DRectangle> getTextRectangles()
+ {
+ std::vector<basegfx::B2DRectangle> aRectangles;
+
+ if (!mpTextPage || !mpSearchHandle)
+ return aRectangles;
+
+ int nIndex = index();
+ if (nIndex < 0)
+ return aRectangles;
+
+ int nSize = size();
+ if (nSize <= 0)
+ return aRectangles;
+
+ double fPageHeight = getPageSize().getY();
+
+ for (int nCount = 0; nCount < nSize; nCount++)
+ {
+ basegfx::B2DRectangle aRectangle = mpTextPage->getCharBox(nIndex + nCount, fPageHeight);
+ if (!aRectangle.isEmpty())
+ {
+ aRectangles.push_back(aRectangle);
+ }
+ }
+
+ return aRectangles;
+ }
+};
+
+} // end anonymous namespace
+
+class VectorGraphicSearch::Implementation
+{
+public:
+ std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
+ std::unique_ptr<vcl::pdf::PDFiumDocument> mpPdfDocument;
+
+ std::unique_ptr<SearchContext> mpSearchContext;
+
+ Implementation()
+ : mpPDFium(vcl::pdf::PDFiumLibrary::get())
+ {
+ }
+
+ ~Implementation() { mpSearchContext.reset(); }
+};
+
+VectorGraphicSearch::VectorGraphicSearch(Graphic const& rGraphic)
+ : mpImplementation(std::make_unique<VectorGraphicSearch::Implementation>())
+ , maGraphic(rGraphic)
+{
+}
+
+VectorGraphicSearch::~VectorGraphicSearch() { mpImplementation.reset(); }
+
+bool VectorGraphicSearch::search(OUString const& rSearchString,
+ VectorGraphicSearchOptions const& rOptions)
+{
+ if (!mpImplementation->mpPDFium)
+ {
+ return false;
+ }
+
+ if (!mpImplementation->mpSearchContext)
+ {
+ auto pData = maGraphic.getVectorGraphicData();
+
+ if (pData && pData->getType() == VectorGraphicDataType::Pdf)
+ {
+ if (searchPDF(pData))
+ {
+ return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
+ }
+ }
+ return false;
+ }
+ return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
+}
+
+bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData)
+{
+ if (!mpImplementation->mpPDFium)
+ {
+ return false;
+ }
+
+ mpImplementation->mpPdfDocument = mpImplementation->mpPDFium->openDocument(
+ rData->getBinaryDataContainer().getData(), rData->getBinaryDataContainer().getSize(),
+ OString());
+
+ if (!mpImplementation->mpPdfDocument)
+ {
+ //TODO: Handle failure to load.
+ switch (mpImplementation->mpPDFium->getLastErrorCode())
+ {
+ case vcl::pdf::PDFErrorType::Success:
+ break;
+ case vcl::pdf::PDFErrorType::Unknown:
+ break;
+ case vcl::pdf::PDFErrorType::File:
+ break;
+ case vcl::pdf::PDFErrorType::Format:
+ break;
+ case vcl::pdf::PDFErrorType::Password:
+ break;
+ case vcl::pdf::PDFErrorType::Security:
+ break;
+ case vcl::pdf::PDFErrorType::Page:
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ sal_Int32 nPageIndex = std::max(rData->getPageIndex(), sal_Int32(0));
+
+ mpImplementation->mpSearchContext.reset(
+ new SearchContext(mpImplementation->mpPdfDocument, nPageIndex));
+ return true;
+}
+
+basegfx::B2DSize VectorGraphicSearch::pageSize()
+{
+ basegfx::B2DSize aSize;
+ if (mpImplementation->mpSearchContext)
+ aSize = mpImplementation->mpSearchContext->getPageSize();
+ return aSize;
+}
+
+bool VectorGraphicSearch::next()
+{
+ if (mpImplementation->mpSearchContext)
+ return mpImplementation->mpSearchContext->next();
+ return false;
+}
+
+bool VectorGraphicSearch::previous()
+{
+ if (mpImplementation->mpSearchContext)
+ return mpImplementation->mpSearchContext->previous();
+ return false;
+}
+
+int VectorGraphicSearch::index()
+{
+ if (mpImplementation->mpSearchContext)
+ return mpImplementation->mpSearchContext->index();
+ return -1;
+}
+
+std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
+{
+ if (mpImplementation->mpSearchContext)
+ return mpImplementation->mpSearchContext->getTextRectangles();
+
+ return std::vector<basegfx::B2DRectangle>();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */