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 
12 
13 #include <config_features.h>
14 
15 #if HAVE_FEATURE_PDFIUM
16 
18 #include <tools/UnitConversion.hxx>
19 
20 #include <sal/config.h>
21 
22 #include <fpdf_doc.h>
23 #include <fpdf_text.h>
24 
25 namespace
26 {
27 class SearchContext
28 {
29 private:
30  std::unique_ptr<vcl::pdf::PDFiumDocument>& mpPdfDocument;
31  std::unique_ptr<vcl::pdf::PDFiumPage> mpPage;
32  std::unique_ptr<vcl::pdf::PDFiumTextPage> mpTextPage;
33  std::unique_ptr<vcl::pdf::PDFiumSearchHandle> mpSearchHandle;
34 
35 public:
36  sal_Int32 mnPageIndex;
37  int mnCurrentIndex;
38  OUString maSearchString;
40 
41  SearchContext(std::unique_ptr<vcl::pdf::PDFiumDocument>& pPdfDocument, sal_Int32 nPageIndex)
42  : mpPdfDocument(pPdfDocument)
43  , mnPageIndex(nPageIndex)
44  , mnCurrentIndex(-1)
45  {
46  }
47 
48  ~SearchContext()
49  {
50  if (mpSearchHandle)
51  mpSearchHandle.reset();
52  if (mpTextPage)
53  mpTextPage.reset();
54  if (mpPage)
55  mpPage.reset();
56  }
57 
58  basegfx::B2DSize getPageSize()
59  {
60  basegfx::B2DSize aSize;
61  if (!mpPdfDocument)
62  return aSize;
63 
64  basegfx::B2DSize aPDFSize = mpPdfDocument->getPageSize(mnPageIndex);
65  aSize = basegfx::B2DSize(convertPointToMm100(aPDFSize.getX()),
66  convertPointToMm100(aPDFSize.getY()));
67  return aSize;
68  }
69 
70  bool initialize(OUString const& rSearchString, VectorGraphicSearchOptions const& rOptions)
71  {
72  if (!mpPdfDocument)
73  return false;
74 
75  if (rSearchString == maSearchString)
76  return true;
77 
78  if (mpSearchHandle)
79  mpSearchHandle.reset();
80 
81  if (mpTextPage)
82  mpTextPage.reset();
83 
84  if (mpPage)
85  mpPage.reset();
86 
87  maSearchString = rSearchString;
88  maOptions = rOptions;
89 
90  mpPage = mpPdfDocument->openPage(mnPageIndex);
91  if (!mpPage)
92  return false;
93 
94  mpTextPage = mpPage->getTextPage();
95  if (!mpTextPage)
96  return false;
97 
98  // Index where to start to search. -1 => at the end
99  int nStartIndex = maOptions.meStartPosition == SearchStartPosition::End ? -1 : 0;
100 
101  if (mnCurrentIndex >= 0)
102  nStartIndex = mnCurrentIndex;
103 
104  // vcl::pdf::PDFFindFlags::MatchCase, vcl::pdf::PDFFindFlags::MatchWholeWord, vcl::pdf::PDFFindFlags::Consecutive
105  // vcl::pdf::PDFFindFlags::MatchCase - If not set, it will not match case by default.
106  // vcl::pdf::PDFFindFlags::MatchWholeWord - If not set, it will not match the whole word by default.
107  // vcl::pdf::PDFFindFlags::Consecutive - If not set, it will skip past the current match to look for the next match.
108  vcl::pdf::PDFFindFlags nSearchFlags{};
109  if (maOptions.mbMatchCase)
110  nSearchFlags |= vcl::pdf::PDFFindFlags::MatchCase;
111  if (maOptions.mbMatchWholeWord)
113 
114  mpSearchHandle = mpTextPage->findStart(maSearchString, nSearchFlags, nStartIndex);
115 
116  return mpSearchHandle != nullptr;
117  }
118 
119  bool next()
120  {
121  if (mpSearchHandle && mpSearchHandle->findNext())
122  {
123  mnCurrentIndex = index();
124  return true;
125  }
126  return false;
127  }
128 
129  bool previous()
130  {
131  if (mpSearchHandle && mpSearchHandle->findPrev())
132  {
133  mnCurrentIndex = index();
134  return true;
135  }
136  return false;
137  }
138 
139  int index()
140  {
141  if (mpSearchHandle)
142  return mpSearchHandle->getSearchResultIndex();
143  return -1;
144  }
145 
146  int size()
147  {
148  if (mpSearchHandle)
149  return mpSearchHandle->getSearchCount();
150  return -1;
151  }
152 
153  std::vector<basegfx::B2DRectangle> getTextRectangles()
154  {
155  std::vector<basegfx::B2DRectangle> aRectangles;
156 
157  if (!mpTextPage || !mpSearchHandle)
158  return aRectangles;
159 
160  int nIndex = index();
161  if (nIndex < 0)
162  return aRectangles;
163 
164  int nSize = size();
165  if (nSize <= 0)
166  return aRectangles;
167 
168  double fPageHeight = getPageSize().getY();
169 
170  for (int nCount = 0; nCount < nSize; nCount++)
171  {
172  basegfx::B2DRectangle aRectangle = mpTextPage->getCharBox(nIndex + nCount, fPageHeight);
173  if (!aRectangle.isEmpty())
174  {
175  aRectangles.push_back(aRectangle);
176  }
177  }
178 
179  return aRectangles;
180  }
181 };
182 
183 } // end anonymous namespace
184 
186 {
187 public:
188  std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
189  std::unique_ptr<vcl::pdf::PDFiumDocument> mpPdfDocument;
190 
191  std::unique_ptr<SearchContext> mpSearchContext;
192 
193  Implementation()
194  : mpPDFium(vcl::pdf::PDFiumLibrary::get())
195  {
196  }
197 
198  ~Implementation() { mpSearchContext.reset(); }
199 };
200 
202  : mpImplementation(std::make_unique<VectorGraphicSearch::Implementation>())
203  , maGraphic(rGraphic)
204 {
205 }
206 
208 
209 bool VectorGraphicSearch::search(OUString const& rSearchString,
210  VectorGraphicSearchOptions const& rOptions)
211 {
212  if (!mpImplementation->mpSearchContext)
213  {
215 
216  if (pData && pData->getType() == VectorGraphicDataType::Pdf)
217  {
218  if (searchPDF(pData))
219  {
220  return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
221  }
222  }
223  return false;
224  }
225  return mpImplementation->mpSearchContext->initialize(rSearchString, rOptions);
226 }
227 
228 bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& rData)
229 {
230  mpImplementation->mpPdfDocument = mpImplementation->mpPDFium->openDocument(
231  rData->getBinaryDataContainer().getData(), rData->getBinaryDataContainer().getSize());
232 
233  if (!mpImplementation->mpPdfDocument)
234  {
235  //TODO: Handle failure to load.
236  switch (mpImplementation->mpPDFium->getLastErrorCode())
237  {
239  break;
241  break;
243  break;
245  break;
247  break;
249  break;
251  break;
252  default:
253  break;
254  }
255  return false;
256  }
257 
258  sal_Int32 nPageIndex = std::max(rData->getPageIndex(), sal_Int32(0));
259 
260  mpImplementation->mpSearchContext.reset(
261  new SearchContext(mpImplementation->mpPdfDocument, nPageIndex));
262  return true;
263 }
264 
266 {
267  basegfx::B2DSize aSize;
268  if (mpImplementation->mpSearchContext)
269  aSize = mpImplementation->mpSearchContext->getPageSize();
270  return aSize;
271 }
272 
274 {
275  if (mpImplementation->mpSearchContext)
276  return mpImplementation->mpSearchContext->next();
277  return false;
278 }
279 
281 {
282  if (mpImplementation->mpSearchContext)
283  return mpImplementation->mpSearchContext->previous();
284  return false;
285 }
286 
288 {
289  if (mpImplementation->mpSearchContext)
290  return mpImplementation->mpSearchContext->index();
291  return -1;
292 }
293 
294 std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
295 {
296  if (mpImplementation->mpSearchContext)
297  return mpImplementation->mpSearchContext->getTextRectangles();
298 
299  return std::vector<basegfx::B2DRectangle>();
300 }
301 
302 #else // !HAVE_FEATURE_PDFIUM
303 
305 {
306 };
307 
309  : maGraphic(rGraphic)
310 {
311 }
312 
314 
315 bool VectorGraphicSearch::search(OUString const& /*rSearchString*/,
316  VectorGraphicSearchOptions const& /*rOptions*/)
317 {
318  return false;
319 }
320 
321 bool VectorGraphicSearch::searchPDF(std::shared_ptr<VectorGraphicData> const& /*rData*/)
322 {
323  return false;
324 }
325 
327 
328 bool VectorGraphicSearch::next() { return false; }
329 
330 bool VectorGraphicSearch::previous() { return false; }
331 
332 int VectorGraphicSearch::index() { return -1; }
333 
334 std::vector<basegfx::B2DRectangle> VectorGraphicSearch::getTextRectangles()
335 {
336  return std::vector<basegfx::B2DRectangle>();
337 }
338 
339 #endif // HAVE_FEATURE_PDFIUM
340 
341 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
sal_Int32 nIndex
std::unique_ptr< ContentProperties > pData
double getX() const
double getY() const
std::unique_ptr< Implementation > mpImplementation
SearchStartPosition meStartPosition
B2DVector B2DSize
int nCount
bool search(OUString const &rSearchString, VectorGraphicSearchOptions const &rOptions=VectorGraphicSearchOptions())
bool isEmpty() const
FPDF_TEXTPAGE mpTextPage
FPDF_PAGE mpPage
VectorGraphicSearch(Graphic const &rGraphic)
basegfx::B2DSize pageSize()
size
std::vector< basegfx::B2DRectangle > getTextRectangles()
tuple index
constexpr auto convertPointToMm100(N n)
FPDF_DOCUMENT mpPdfDocument
bool searchPDF(std::shared_ptr< VectorGraphicData > const &rData)
FPDF_SCHHANDLE mpSearchHandle
const std::shared_ptr< VectorGraphicData > & getVectorGraphicData() const
Definition: graph.cxx:523
const Graphic maGraphic