LibreOffice Module vcl (master) 1
VectorGraphicSearch.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <utility>
13
16
17#include <sal/config.h>
18
19namespace
20{
21class SearchContext
22{
23private:
24 std::unique_ptr<vcl::pdf::PDFiumDocument>& mpPdfDocument;
25 std::unique_ptr<vcl::pdf::PDFiumPage> mpPage;
26 std::unique_ptr<vcl::pdf::PDFiumTextPage> mpTextPage;
27 std::unique_ptr<vcl::pdf::PDFiumSearchHandle> mpSearchHandle;
28
29public:
30 sal_Int32 mnPageIndex;
31 int mnCurrentIndex;
32 OUString maSearchString;
34
35 SearchContext(std::unique_ptr<vcl::pdf::PDFiumDocument>& pPdfDocument, sal_Int32 nPageIndex)
36 : mpPdfDocument(pPdfDocument)
37 , mnPageIndex(nPageIndex)
38 , mnCurrentIndex(-1)
39 {
40 }
41
42 ~SearchContext()
43 {
45 mpSearchHandle.reset();
46 if (mpTextPage)
47 mpTextPage.reset();
48 if (mpPage)
49 mpPage.reset();
50 }
51
52 basegfx::B2DSize getPageSize()
53 {
54 basegfx::B2DSize aSize;
55 if (!mpPdfDocument)
56 return aSize;
57
58 basegfx::B2DSize aPDFSize = mpPdfDocument->getPageSize(mnPageIndex);
59 aSize = basegfx::B2DSize(convertPointToMm100(aPDFSize.getX()),
60 convertPointToMm100(aPDFSize.getY()));
61 return aSize;
62 }
63
64 bool initialize(OUString const& rSearchString, VectorGraphicSearchOptions const& rOptions)
65 {
66 if (!mpPdfDocument)
67 return false;
68
69 if (rSearchString == maSearchString)
70 return true;
71
73 mpSearchHandle.reset();
74
75 if (mpTextPage)
76 mpTextPage.reset();
77
78 if (mpPage)
79 mpPage.reset();
80
81 maSearchString = rSearchString;
82 maOptions = rOptions;
83
84 mpPage = mpPdfDocument->openPage(mnPageIndex);
85 if (!mpPage)
86 return false;
87
88 mpTextPage = mpPage->getTextPage();
89 if (!mpTextPage)
90 return false;
91
92 // Index where to start to search. -1 => at the end
93 int nStartIndex = maOptions.meStartPosition == SearchStartPosition::End ? -1 : 0;
94
95 if (mnCurrentIndex >= 0)
96 nStartIndex = mnCurrentIndex;
97
98 // vcl::pdf::PDFFindFlags::MatchCase, vcl::pdf::PDFFindFlags::MatchWholeWord, vcl::pdf::PDFFindFlags::Consecutive
99 // vcl::pdf::PDFFindFlags::MatchCase - If not set, it will not match case by default.
100 // vcl::pdf::PDFFindFlags::MatchWholeWord - If not set, it will not match the whole word by default.
101 // vcl::pdf::PDFFindFlags::Consecutive - If not set, it will skip past the current match to look for the next match.
102 vcl::pdf::PDFFindFlags nSearchFlags{};
103 if (maOptions.mbMatchCase)
104 nSearchFlags |= vcl::pdf::PDFFindFlags::MatchCase;
105 if (maOptions.mbMatchWholeWord)
107
108 mpSearchHandle = mpTextPage->findStart(maSearchString, nSearchFlags, nStartIndex);
109
110 return mpSearchHandle != nullptr;
111 }
112
113 bool next()
114 {
115 if (mpSearchHandle && mpSearchHandle->findNext())
116 {
117 mnCurrentIndex = index();
118 return true;
119 }
120 return false;
121 }
122
123 bool previous()
124 {
125 if (mpSearchHandle && mpSearchHandle->findPrev())
126 {
127 mnCurrentIndex = index();
128 return true;
129 }
130 return false;
131 }
132
133 int index()
134 {
135 if (mpSearchHandle)
136 return mpSearchHandle->getSearchResultIndex();
137 return -1;
138 }
139
140 int size()
141 {
142 if (mpSearchHandle)
143 return mpSearchHandle->getSearchCount();
144 return -1;
145 }
146
147 std::vector<basegfx::B2DRectangle> getTextRectangles()
148 {
149 std::vector<basegfx::B2DRectangle> aRectangles;
150
151 if (!mpTextPage || !mpSearchHandle)
152 return aRectangles;
153
154 int nIndex = index();
155 if (nIndex < 0)
156 return aRectangles;
157
158 int nSize = size();
159 if (nSize <= 0)
160 return aRectangles;
161
162 double fPageHeight = getPageSize().getY();
163
164 for (int nCount = 0; nCount < nSize; nCount++)
165 {
166 basegfx::B2DRectangle aRectangle = mpTextPage->getCharBox(nIndex + nCount, fPageHeight);
167 if (!aRectangle.isEmpty())
168 {
169 aRectangles.push_back(aRectangle);
170 }
171 }
172
173 return aRectangles;
174 }
175};
176
177} // end anonymous namespace
178
180{
181public:
182 std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
183 std::unique_ptr<vcl::pdf::PDFiumDocument> mpPdfDocument;
184
185 std::unique_ptr<SearchContext> mpSearchContext;
186
188 : mpPDFium(vcl::pdf::PDFiumLibrary::get())
189 {
190 }
191
193};
194
196 : mpImplementation(std::make_unique<VectorGraphicSearch::Implementation>())
197 , maGraphic(std::move(aGraphic))
198{
199}
200
202
203bool VectorGraphicSearch::search(OUString const& rSearchString,
204 VectorGraphicSearchOptions const& rOptions)
205{
206 if (!mpImplementation->mpPDFium)
207 {
208 return false;
209 }
210
211 if (!mpImplementation->mpSearchContext)
212 {
214
215 if (pData && pData->getType() == VectorGraphicDataType::Pdf)
216 {
217 if (searchPDF(pData))
218 {
219 return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
220 }
221 }
222 return false;
223 }
224 return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
225}
226
227bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData)
228{
229 if (!mpImplementation->mpPDFium)
230 {
231 return false;
232 }
233
234 mpImplementation->mpPdfDocument = mpImplementation->mpPDFium->openDocument(
235 rData->getBinaryDataContainer().getData(), rData->getBinaryDataContainer().getSize(),
236 OString());
237
238 if (!mpImplementation->mpPdfDocument)
239 {
240 //TODO: Handle failure to load.
241 switch (mpImplementation->mpPDFium->getLastErrorCode())
242 {
244 break;
246 break;
248 break;
250 break;
252 break;
254 break;
256 break;
257 default:
258 break;
259 }
260 return false;
261 }
262
263 sal_Int32 nPageIndex = std::max(rData->getPageIndex(), sal_Int32(0));
264
265 mpImplementation->mpSearchContext.reset(
266 new SearchContext(mpImplementation->mpPdfDocument, nPageIndex));
267 return true;
268}
269
271{
272 basegfx::B2DSize aSize;
273 if (mpImplementation->mpSearchContext)
274 aSize = mpImplementation->mpSearchContext->getPageSize();
275 return aSize;
276}
277
279{
280 if (mpImplementation->mpSearchContext)
281 return mpImplementation->mpSearchContext->next();
282 return false;
283}
284
286{
287 if (mpImplementation->mpSearchContext)
288 return mpImplementation->mpSearchContext->previous();
289 return false;
290}
291
293{
294 if (mpImplementation->mpSearchContext)
295 return mpImplementation->mpSearchContext->index();
296 return -1;
297}
298
299std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
300{
301 if (mpImplementation->mpSearchContext)
302 return mpImplementation->mpSearchContext->getTextRectangles();
303
304 return std::vector<basegfx::B2DRectangle>();
305}
306
307/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
FPDF_DOCUMENT mpPdfDocument
FPDF_TEXTPAGE mpTextPage
FPDF_SCHHANDLE mpSearchHandle
FPDF_PAGE mpPage
constexpr auto convertPointToMm100(N n)
const std::shared_ptr< VectorGraphicData > & getVectorGraphicData() const
Definition: graph.cxx:524
std::shared_ptr< vcl::pdf::PDFium > mpPDFium
std::unique_ptr< vcl::pdf::PDFiumDocument > mpPdfDocument
std::unique_ptr< SearchContext > mpSearchContext
std::vector< basegfx::B2DRectangle > getTextRectangles()
basegfx::B2DSize pageSize()
std::unique_ptr< Implementation > mpImplementation
bool search(OUString const &rSearchString, VectorGraphicSearchOptions const &rOptions=VectorGraphicSearchOptions())
bool searchPDF(std::shared_ptr< VectorGraphicData > const &rData)
VectorGraphicSearch(Graphic aGraphic)
bool isEmpty() const
TYPE getX() const
TYPE getY() const
int nCount
const Graphic maGraphic
sal_Int32 nIndex
std::unique_ptr< sal_Int32[]> pData
const ContentProperties & rData
B2DVector B2DSize
size
index
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
SearchStartPosition meStartPosition