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 <vcl/filter/PDFiumLibrary.hxx>
12 
13 #include <cassert>
14 
15 #include <fpdf_doc.h>
16 #include <fpdf_annot.h>
17 #include <fpdf_edit.h>
18 #include <fpdf_text.h>
19 #include <fpdf_save.h>
20 #include <fpdf_signature.h>
21 #include <fpdf_formfill.h>
22 
23 #include <osl/endian.h>
24 #include <vcl/bitmap.hxx>
25 #include <tools/stream.hxx>
26 #include <tools/UnitConversion.hxx>
27 
28 #include <bitmap/BitmapWriteAccess.hxx>
29 
30 using namespace com::sun::star;
31 
32 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Unknown) == FPDF_PAGEOBJ_UNKNOWN,
33               "PDFPageObjectType::Unknown value mismatch");
34 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Text) == FPDF_PAGEOBJ_TEXT,
35               "PDFPageObjectType::Text value mismatch");
36 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Path) == FPDF_PAGEOBJ_PATH,
37               "PDFPageObjectType::Path value mismatch");
38 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Image) == FPDF_PAGEOBJ_IMAGE,
39               "PDFPageObjectType::Image value mismatch");
40 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Shading) == FPDF_PAGEOBJ_SHADING,
41               "PDFPageObjectType::Shading value mismatch");
42 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Form) == FPDF_PAGEOBJ_FORM,
43               "PDFPageObjectType::Form value mismatch");
44 
45 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Unknown) == FPDF_SEGMENT_UNKNOWN,
46               "PDFSegmentType::Unknown value mismatch");
47 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Lineto) == FPDF_SEGMENT_LINETO,
48               "PDFSegmentType::Lineto value mismatch");
49 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Bezierto) == FPDF_SEGMENT_BEZIERTO,
50               "PDFSegmentType::Bezierto value mismatch");
51 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Moveto) == FPDF_SEGMENT_MOVETO,
52               "PDFSegmentType::Moveto value mismatch");
53 
54 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Unknown) == FPDFBitmap_Unknown,
55               "PDFBitmapType::Unknown value mismatch");
56 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Gray) == FPDFBitmap_Gray,
57               "PDFBitmapType::Gray value mismatch");
58 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGR) == FPDFBitmap_BGR,
59               "PDFBitmapType::BGR value mismatch");
60 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRx) == FPDFBitmap_BGRx,
61               "PDFBitmapType::BGRx value mismatch");
62 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRA) == FPDFBitmap_BGRA,
63               "PDFBitmapType::BGRA value mismatch");
64 
65 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Unknown) == FPDF_OBJECT_UNKNOWN,
66               "PDFObjectType::Unknown value mismatch");
67 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Boolean) == FPDF_OBJECT_BOOLEAN,
68               "PDFObjectType::Boolean value mismatch");
69 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Number) == FPDF_OBJECT_NUMBER,
70               "PDFObjectType::Number value mismatch");
71 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::String) == FPDF_OBJECT_STRING,
72               "PDFObjectType::String value mismatch");
73 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Name) == FPDF_OBJECT_NAME,
74               "PDFObjectType::Name value mismatch");
75 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Array) == FPDF_OBJECT_ARRAY,
76               "PDFObjectType::Array value mismatch");
77 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Dictionary) == FPDF_OBJECT_DICTIONARY,
78               "PDFObjectType::Dictionary value mismatch");
79 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Stream) == FPDF_OBJECT_STREAM,
80               "PDFObjectType::Stream value mismatch");
81 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Nullobj) == FPDF_OBJECT_NULLOBJ,
82               "PDFObjectType::Nullobj value mismatch");
83 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Reference) == FPDF_OBJECT_REFERENCE,
84               "PDFObjectType::Reference value mismatch");
85 
86 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Unknown) == FPDF_TEXTRENDERMODE_UNKNOWN,
87               "PDFTextRenderMode::Unknown value mismatch");
88 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Fill) == FPDF_TEXTRENDERMODE_FILL,
89               "PDFTextRenderMode::Fill value mismatch");
90 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Stroke) == FPDF_TEXTRENDERMODE_STROKE,
91               "PDFTextRenderMode::Stroke value mismatch");
92 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStroke)
93                   == FPDF_TEXTRENDERMODE_FILL_STROKE,
94               "PDFTextRenderMode::FillStroke value mismatch");
95 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Invisible)
96                   == FPDF_TEXTRENDERMODE_INVISIBLE,
97               "PDFTextRenderMode::Invisible value mismatch");
98 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillClip)
99                   == FPDF_TEXTRENDERMODE_FILL_CLIP,
100               "PDFTextRenderMode::FillClip value mismatch");
101 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::StrokeClip)
102                   == FPDF_TEXTRENDERMODE_STROKE_CLIP,
103               "PDFTextRenderMode::StrokeClip value mismatch");
104 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStrokeClip)
105                   == FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP,
106               "PDFTextRenderMode::FillStrokeClip value mismatch");
107 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Clip) == FPDF_TEXTRENDERMODE_CLIP,
108               "PDFTextRenderMode::Clip value mismatch");
109 
110 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::None) == FPDF_FILLMODE_NONE,
111               "PDFFillMode::None value mismatch");
112 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Alternate) == FPDF_FILLMODE_ALTERNATE,
113               "PDFFillMode::Alternate value mismatch");
114 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Winding) == FPDF_FILLMODE_WINDING,
115               "PDFFillMode::Winding value mismatch");
116 
117 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchCase) == FPDF_MATCHCASE,
118               "PDFFindFlags::MatchCase value mismatch");
119 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchWholeWord) == FPDF_MATCHWHOLEWORD,
120               "PDFFindFlags::MatchWholeWord value mismatch");
121 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::Consecutive) == FPDF_CONSECUTIVE,
122               "PDFFindFlags::Consecutive value mismatch");
123 
124 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Success) == FPDF_ERR_SUCCESS,
125               "PDFErrorType::Success value mismatch");
126 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Unknown) == FPDF_ERR_UNKNOWN,
127               "PDFErrorType::Unknown value mismatch");
128 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::File) == FPDF_ERR_FILE,
129               "PDFErrorType::File value mismatch");
130 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Format) == FPDF_ERR_FORMAT,
131               "PDFErrorType::Format value mismatch");
132 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Password) == FPDF_ERR_PASSWORD,
133               "PDFErrorType::Password value mismatch");
134 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Security) == FPDF_ERR_SECURITY,
135               "PDFErrorType::Security value mismatch");
136 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Page) == FPDF_ERR_PAGE,
137               "PDFErrorType::Page value mismatch");
138 
139 namespace
140 {
141 /// Callback class to be used with FPDF_SaveWithVersion().
142 struct CompatibleWriter : public FPDF_FILEWRITE
143 {
CompatibleWriter__anonb13af9050111::CompatibleWriter144     CompatibleWriter(SvMemoryStream& rStream)
145         : m_rStream(rStream)
146     {
147     }
148 
149     SvMemoryStream& m_rStream;
150 };
151 
CompatibleWriterCallback(FPDF_FILEWRITE * pFileWrite,const void * pData,unsigned long nSize)152 int CompatibleWriterCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsigned long nSize)
153 {
154     auto pImpl = static_cast<CompatibleWriter*>(pFileWrite);
155     pImpl->m_rStream.WriteBytes(pData, nSize);
156     return 1;
157 }
158 }
159 
160 namespace vcl::pdf
161 {
162 namespace
163 {
164 class PDFiumBitmapImpl final : public PDFiumBitmap
165 {
166 private:
167     FPDF_BITMAP mpBitmap;
168 
169     PDFiumBitmapImpl(const PDFiumBitmapImpl&) = delete;
170     PDFiumBitmapImpl& operator=(const PDFiumBitmapImpl&) = delete;
171 
172 public:
173     PDFiumBitmapImpl(FPDF_BITMAP pBitmap);
174     ~PDFiumBitmapImpl() override;
getPointer()175     FPDF_BITMAP getPointer() { return mpBitmap; }
176 
177     void fillRect(int left, int top, int width, int height, sal_uInt32 nColor) override;
178     void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY,
179                           int nSizeX, int nSizeY) override;
180     ConstScanline getBuffer() override;
181     int getStride() override;
182     int getWidth() override;
183     int getHeight() override;
184     PDFBitmapType getFormat() override;
185 };
186 
187 class PDFiumPathSegmentImpl final : public PDFiumPathSegment
188 {
189 private:
190     FPDF_PATHSEGMENT mpPathSegment;
191 
192     PDFiumPathSegmentImpl(const PDFiumPathSegmentImpl&) = delete;
193     PDFiumPathSegmentImpl& operator=(const PDFiumPathSegmentImpl&) = delete;
194 
195 public:
196     PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment);
197 
198     basegfx::B2DPoint getPoint() const override;
199     bool isClosed() const override;
200     PDFSegmentType getType() const override;
201 };
202 
203 class PDFiumAnnotationImpl final : public PDFiumAnnotation
204 {
205 private:
206     FPDF_ANNOTATION mpAnnotation;
207 
208     PDFiumAnnotationImpl(const PDFiumAnnotationImpl&) = delete;
209     PDFiumAnnotationImpl& operator=(const PDFiumAnnotationImpl&) = delete;
210 
211 public:
212     PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation);
213     ~PDFiumAnnotationImpl();
getPointer()214     FPDF_ANNOTATION getPointer() { return mpAnnotation; }
215 
216     PDFAnnotationSubType getSubType() override;
217     basegfx::B2DRectangle getRectangle() override;
218     bool hasKey(OString const& rKey) override;
219     PDFObjectType getValueType(OString const& rKey) override;
220     OUString getString(OString const& rKey) override;
221     std::unique_ptr<PDFiumAnnotation> getLinked(OString const& rKey) override;
222     int getObjectCount() override;
223     std::unique_ptr<PDFiumPageObject> getObject(int nIndex) override;
224     std::vector<std::vector<basegfx::B2DPoint>> getInkStrokes() override;
225     std::vector<basegfx::B2DPoint> getVertices() override;
226     Color getColor() override;
227     Color getInteriorColor() override;
228     float getBorderWidth() override;
229     basegfx::B2DSize getBorderCornerRadius() override;
230     size_t getAttachmentPointsCount() override;
231     std::vector<basegfx::B2DPoint> getAttachmentPoints(size_t nIndex) override;
232     std::vector<basegfx::B2DPoint> getLineGeometry() override;
233 };
234 
235 class PDFiumPageObjectImpl final : public PDFiumPageObject
236 {
237 private:
238     FPDF_PAGEOBJECT mpPageObject;
239 
240     PDFiumPageObjectImpl(const PDFiumPageObjectImpl&) = delete;
241     PDFiumPageObjectImpl& operator=(const PDFiumPageObjectImpl&) = delete;
242 
243 public:
244     PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject);
245 
246     PDFPageObjectType getType() override;
247     OUString getText(std::unique_ptr<PDFiumTextPage> const& pTextPage) override;
248 
249     int getFormObjectCount() override;
250     std::unique_ptr<PDFiumPageObject> getFormObject(int nIndex) override;
251 
252     basegfx::B2DHomMatrix getMatrix() override;
253     basegfx::B2DRectangle getBounds() override;
254     double getFontSize() override;
255     OUString getFontName() override;
256     PDFTextRenderMode getTextRenderMode() override;
257     Color getFillColor() override;
258     Color getStrokeColor() override;
259     double getStrokeWidth() override;
260     // Path
261     int getPathSegmentCount() override;
262     std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) override;
263     Size getImageSize(PDFiumPage& rPage) override;
264     std::unique_ptr<PDFiumBitmap> getImageBitmap() override;
265     bool getDrawMode(PDFFillMode& eFillMode, bool& bStroke) override;
266 };
267 
268 class PDFiumSearchHandleImpl final : public PDFiumSearchHandle
269 {
270 private:
271     FPDF_SCHHANDLE mpSearchHandle;
272 
273     PDFiumSearchHandleImpl(const PDFiumSearchHandleImpl&) = delete;
274     PDFiumSearchHandleImpl& operator=(const PDFiumSearchHandleImpl&) = delete;
275 
276 public:
277     PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle);
278     ~PDFiumSearchHandleImpl();
279 
280     bool findNext() override;
281     bool findPrev() override;
282     int getSearchResultIndex() override;
283     int getSearchCount() override;
284 };
285 
286 class PDFiumTextPageImpl final : public PDFiumTextPage
287 {
288 private:
289     FPDF_TEXTPAGE mpTextPage;
290 
291     PDFiumTextPageImpl(const PDFiumTextPageImpl&) = delete;
292     PDFiumTextPageImpl& operator=(const PDFiumTextPageImpl&) = delete;
293 
294 public:
295     PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage);
296     ~PDFiumTextPageImpl();
297 
getPointer()298     FPDF_TEXTPAGE getPointer() { return mpTextPage; }
299 
300     int countChars() override;
301     unsigned int getUnicode(int index) override;
302     std::unique_ptr<PDFiumSearchHandle> findStart(const OUString& rFindWhat, PDFFindFlags nFlags,
303                                                   sal_Int32 nStartIndex) override;
304 
305     /// Returned rect is no longer upside down and is in mm100.
306     basegfx::B2DRectangle getCharBox(int nIndex, double fPageHeight) override;
307 };
308 
309 class PDFiumSignatureImpl final : public PDFiumSignature
310 {
311 private:
312     FPDF_SIGNATURE mpSignature;
313     PDFiumSignatureImpl(const PDFiumSignatureImpl&) = delete;
314     PDFiumSignatureImpl& operator=(const PDFiumSignatureImpl&) = delete;
315 
316 public:
317     PDFiumSignatureImpl(FPDF_SIGNATURE pSignature);
318 
319     std::vector<int> getByteRange() override;
320     int getDocMDPPermission() override;
321     std::vector<unsigned char> getContents() override;
322     OString getSubFilter() override;
323     OUString getReason() override;
324     css::util::DateTime getTime() override;
325 };
326 
327 class PDFiumPageImpl final : public PDFiumPage
328 {
329 private:
330     FPDF_PAGE mpPage;
331 
332 private:
333     PDFiumPageImpl(const PDFiumPageImpl&) = delete;
334     PDFiumPageImpl& operator=(const PDFiumPageImpl&) = delete;
335 
336 public:
PDFiumPageImpl(FPDF_PAGE pPage)337     PDFiumPageImpl(FPDF_PAGE pPage)
338         : mpPage(pPage)
339     {
340     }
341 
~PDFiumPageImpl()342     ~PDFiumPageImpl() override
343     {
344         if (mpPage)
345             FPDF_ClosePage(mpPage);
346     }
347 
getPointer()348     FPDF_PAGE getPointer() { return mpPage; }
349 
350     int getObjectCount() override;
351     std::unique_ptr<PDFiumPageObject> getObject(int nIndex) override;
352 
353     int getAnnotationCount() override;
354     int getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation) override;
355 
356     std::unique_ptr<PDFiumAnnotation> getAnnotation(int nIndex) override;
357 
358     std::unique_ptr<PDFiumTextPage> getTextPage() override;
359 
360     BitmapChecksum getChecksum(int nMDPPerm) override;
361 
362     double getWidth() override;
363     double getHeight() override;
364 
365     bool hasTransparency() override;
366 
367     bool hasLinks() override;
368 };
369 
370 /// Wrapper around FPDF_FORMHANDLE.
371 class PDFiumFormHandle final
372 {
373 private:
374     FPDF_FORMHANDLE mpHandle;
375 
376     PDFiumFormHandle(const PDFiumFormHandle&) = delete;
377     PDFiumFormHandle& operator=(const PDFiumFormHandle&) = delete;
378 
379 public:
380     PDFiumFormHandle(FPDF_FORMHANDLE pHandle);
381     ~PDFiumFormHandle();
382     FPDF_FORMHANDLE getPointer();
383 };
384 
385 class PDFiumDocumentImpl : public PDFiumDocument
386 {
387 private:
388     FPDF_DOCUMENT mpPdfDocument;
389     FPDF_FORMFILLINFO m_aFormCallbacks;
390     std::unique_ptr<PDFiumFormHandle> m_pFormHandle;
391 
392 private:
393     PDFiumDocumentImpl(const PDFiumDocumentImpl&) = delete;
394     PDFiumDocumentImpl& operator=(const PDFiumDocumentImpl&) = delete;
395 
396 public:
397     PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument);
398     ~PDFiumDocumentImpl() override;
399     FPDF_FORMHANDLE getFormHandlePointer();
400 
401     // Page size in points
402     basegfx::B2DSize getPageSize(int nIndex) override;
403     int getPageCount() override;
404     int getSignatureCount() override;
405     int getFileVersion() override;
406     bool saveWithVersion(SvMemoryStream& rStream, int nFileVersion) override;
407 
408     std::unique_ptr<PDFiumPage> openPage(int nIndex) override;
409     std::unique_ptr<PDFiumSignature> getSignature(int nIndex) override;
410     std::vector<unsigned int> getTrailerEnds() override;
411 };
412 
413 class PDFiumImpl : public PDFium
414 {
415 private:
416     PDFiumImpl(const PDFiumImpl&) = delete;
417     PDFiumImpl& operator=(const PDFiumImpl&) = delete;
418 
419     OUString maLastError;
420 
421 public:
422     PDFiumImpl();
423     ~PDFiumImpl() override;
424 
getLastError() const425     const OUString& getLastError() const override { return maLastError; }
426 
427     std::unique_ptr<PDFiumDocument> openDocument(const void* pData, int nSize) override;
428     PDFErrorType getLastErrorCode() override;
429     std::unique_ptr<PDFiumBitmap> createBitmap(int nWidth, int nHeight, int nAlpha) override;
430 };
431 }
432 
PDFiumImpl()433 PDFiumImpl::PDFiumImpl()
434 {
435     FPDF_LIBRARY_CONFIG aConfig;
436     aConfig.version = 2;
437     aConfig.m_pUserFontPaths = nullptr;
438     aConfig.m_pIsolate = nullptr;
439     aConfig.m_v8EmbedderSlot = 0;
440     FPDF_InitLibraryWithConfig(&aConfig);
441 }
442 
~PDFiumImpl()443 PDFiumImpl::~PDFiumImpl() { FPDF_DestroyLibrary(); }
444 
openDocument(const void * pData,int nSize)445 std::unique_ptr<PDFiumDocument> PDFiumImpl::openDocument(const void* pData, int nSize)
446 {
447     maLastError = OUString();
448     std::unique_ptr<PDFiumDocument> pPDFiumDocument;
449 
450     FPDF_DOCUMENT pDocument = FPDF_LoadMemDocument(pData, nSize, /*password=*/nullptr);
451 
452     if (!pDocument)
453     {
454         switch (FPDF_GetLastError())
455         {
456             case FPDF_ERR_SUCCESS:
457                 maLastError = "Success";
458                 break;
459             case FPDF_ERR_UNKNOWN:
460                 maLastError = "Unknown error";
461                 break;
462             case FPDF_ERR_FILE:
463                 maLastError = "File not found";
464                 break;
465             case FPDF_ERR_FORMAT:
466                 maLastError = "Input is not a PDF format";
467                 break;
468             case FPDF_ERR_PASSWORD:
469                 maLastError = "Incorrect password or password is required";
470                 break;
471             case FPDF_ERR_SECURITY:
472                 maLastError = "Security error";
473                 break;
474             case FPDF_ERR_PAGE:
475                 maLastError = "Content error";
476                 break;
477             default:
478                 break;
479         }
480     }
481     else
482     {
483         pPDFiumDocument = std::make_unique<PDFiumDocumentImpl>(pDocument);
484     }
485 
486     return pPDFiumDocument;
487 }
488 
getLastErrorCode()489 PDFErrorType PDFiumImpl::getLastErrorCode()
490 {
491     return static_cast<PDFErrorType>(FPDF_GetLastError());
492 }
493 
createBitmap(int nWidth,int nHeight,int nAlpha)494 std::unique_ptr<PDFiumBitmap> PDFiumImpl::createBitmap(int nWidth, int nHeight, int nAlpha)
495 {
496     std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
497     FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha);
498     if (!pPdfBitmap)
499     {
500         maLastError = "Failed to create bitmap";
501     }
502     else
503     {
504         pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pPdfBitmap);
505     }
506     return pPDFiumBitmap;
507 }
508 
PDFiumSignatureImpl(FPDF_SIGNATURE pSignature)509 PDFiumSignatureImpl::PDFiumSignatureImpl(FPDF_SIGNATURE pSignature)
510     : mpSignature(pSignature)
511 {
512 }
513 
getByteRange()514 std::vector<int> PDFiumSignatureImpl::getByteRange()
515 {
516     int nByteRangeLen = FPDFSignatureObj_GetByteRange(mpSignature, nullptr, 0);
517     std::vector<int> aByteRange(nByteRangeLen);
518     if (nByteRangeLen <= 0)
519     {
520         return aByteRange;
521     }
522 
523     FPDFSignatureObj_GetByteRange(mpSignature, aByteRange.data(), aByteRange.size());
524     return aByteRange;
525 }
526 
getDocMDPPermission()527 int PDFiumSignatureImpl::getDocMDPPermission()
528 {
529     return FPDFSignatureObj_GetDocMDPPermission(mpSignature);
530 }
531 
getContents()532 std::vector<unsigned char> PDFiumSignatureImpl::getContents()
533 {
534     int nContentsLen = FPDFSignatureObj_GetContents(mpSignature, nullptr, 0);
535     std::vector<unsigned char> aContents(nContentsLen);
536     if (aContents.empty())
537     {
538         return aContents;
539     }
540 
541     FPDFSignatureObj_GetContents(mpSignature, aContents.data(), aContents.size());
542     return aContents;
543 }
544 
getSubFilter()545 OString PDFiumSignatureImpl::getSubFilter()
546 {
547     int nSubFilterLen = FPDFSignatureObj_GetSubFilter(mpSignature, nullptr, 0);
548     std::vector<char> aSubFilterBuf(nSubFilterLen);
549     FPDFSignatureObj_GetSubFilter(mpSignature, aSubFilterBuf.data(), aSubFilterBuf.size());
550     // Buffer is NUL-terminated.
551     OString aSubFilter(aSubFilterBuf.data(), aSubFilterBuf.size() - 1);
552     return aSubFilter;
553 }
554 
getReason()555 OUString PDFiumSignatureImpl::getReason()
556 {
557     int nReasonLen = FPDFSignatureObj_GetReason(mpSignature, nullptr, 0);
558     OUString aRet;
559     if (nReasonLen > 0)
560     {
561         std::vector<char16_t> aReasonBuf(nReasonLen);
562         FPDFSignatureObj_GetReason(mpSignature, aReasonBuf.data(), aReasonBuf.size());
563         aRet = OUString(aReasonBuf.data(), aReasonBuf.size() - 1);
564     }
565 
566     return aRet;
567 }
568 
getTime()569 util::DateTime PDFiumSignatureImpl::getTime()
570 {
571     util::DateTime aRet;
572     int nTimeLen = FPDFSignatureObj_GetTime(mpSignature, nullptr, 0);
573     if (nTimeLen <= 0)
574     {
575         return aRet;
576     }
577 
578     // Example: "D:20161027100104".
579     std::vector<char> aTimeBuf(nTimeLen);
580     FPDFSignatureObj_GetTime(mpSignature, aTimeBuf.data(), aTimeBuf.size());
581     OString aM(aTimeBuf.data(), aTimeBuf.size() - 1);
582     if (aM.startsWith("D:") && aM.getLength() >= 16)
583     {
584         aRet.Year = aM.copy(2, 4).toInt32();
585         aRet.Month = aM.copy(6, 2).toInt32();
586         aRet.Day = aM.copy(8, 2).toInt32();
587         aRet.Hours = aM.copy(10, 2).toInt32();
588         aRet.Minutes = aM.copy(12, 2).toInt32();
589         aRet.Seconds = aM.copy(14, 2).toInt32();
590     }
591     return aRet;
592 }
593 
PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument)594 PDFiumDocumentImpl::PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument)
595     : mpPdfDocument(pPdfDocument)
596     , m_aFormCallbacks()
597 {
598     m_aFormCallbacks.version = 1;
599     m_pFormHandle = std::make_unique<PDFiumFormHandle>(
600         FPDFDOC_InitFormFillEnvironment(pPdfDocument, &m_aFormCallbacks));
601 }
602 
~PDFiumDocumentImpl()603 PDFiumDocumentImpl::~PDFiumDocumentImpl()
604 {
605     m_pFormHandle.reset();
606     if (mpPdfDocument)
607         FPDF_CloseDocument(mpPdfDocument);
608 }
609 
getFormHandlePointer()610 FPDF_FORMHANDLE PDFiumDocumentImpl::getFormHandlePointer() { return m_pFormHandle->getPointer(); }
611 
openPage(int nIndex)612 std::unique_ptr<PDFiumPage> PDFiumDocumentImpl::openPage(int nIndex)
613 {
614     std::unique_ptr<PDFiumPage> pPDFiumPage;
615     FPDF_PAGE pPage = FPDF_LoadPage(mpPdfDocument, nIndex);
616     if (pPage)
617     {
618         pPDFiumPage = std::make_unique<PDFiumPageImpl>(pPage);
619     }
620     return pPDFiumPage;
621 }
622 
getSignature(int nIndex)623 std::unique_ptr<PDFiumSignature> PDFiumDocumentImpl::getSignature(int nIndex)
624 {
625     std::unique_ptr<PDFiumSignature> pPDFiumSignature;
626     FPDF_SIGNATURE pSignature = FPDF_GetSignatureObject(mpPdfDocument, nIndex);
627     if (pSignature)
628     {
629         pPDFiumSignature = std::make_unique<PDFiumSignatureImpl>(pSignature);
630     }
631     return pPDFiumSignature;
632 }
633 
getTrailerEnds()634 std::vector<unsigned int> PDFiumDocumentImpl::getTrailerEnds()
635 {
636     int nNumTrailers = FPDF_GetTrailerEnds(mpPdfDocument, nullptr, 0);
637     std::vector<unsigned int> aTrailerEnds(nNumTrailers);
638     FPDF_GetTrailerEnds(mpPdfDocument, aTrailerEnds.data(), aTrailerEnds.size());
639     return aTrailerEnds;
640 }
641 
getPageSize(int nIndex)642 basegfx::B2DSize PDFiumDocumentImpl::getPageSize(int nIndex)
643 {
644     basegfx::B2DSize aSize;
645     FS_SIZEF aPDFSize;
646     if (FPDF_GetPageSizeByIndexF(mpPdfDocument, nIndex, &aPDFSize))
647     {
648         aSize = basegfx::B2DSize(aPDFSize.width, aPDFSize.height);
649     }
650     return aSize;
651 }
652 
getPageCount()653 int PDFiumDocumentImpl::getPageCount() { return FPDF_GetPageCount(mpPdfDocument); }
654 
getSignatureCount()655 int PDFiumDocumentImpl::getSignatureCount() { return FPDF_GetSignatureCount(mpPdfDocument); }
656 
getFileVersion()657 int PDFiumDocumentImpl::getFileVersion()
658 {
659     int nFileVersion = 0;
660     FPDF_GetFileVersion(mpPdfDocument, &nFileVersion);
661     return nFileVersion;
662 }
663 
saveWithVersion(SvMemoryStream & rStream,int nFileVersion)664 bool PDFiumDocumentImpl::saveWithVersion(SvMemoryStream& rStream, int nFileVersion)
665 {
666     CompatibleWriter aWriter(rStream);
667     aWriter.version = 1;
668     aWriter.WriteBlock = &CompatibleWriterCallback;
669     if (!FPDF_SaveWithVersion(mpPdfDocument, &aWriter, 0, nFileVersion))
670     {
671         return false;
672     }
673 
674     return true;
675 }
676 
getObjectCount()677 int PDFiumPageImpl::getObjectCount() { return FPDFPage_CountObjects(mpPage); }
678 
getObject(int nIndex)679 std::unique_ptr<PDFiumPageObject> PDFiumPageImpl::getObject(int nIndex)
680 {
681     std::unique_ptr<PDFiumPageObject> pPDFiumPageObject;
682     FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(mpPage, nIndex);
683     if (pPageObject)
684     {
685         pPDFiumPageObject = std::make_unique<PDFiumPageObjectImpl>(pPageObject);
686     }
687     return pPDFiumPageObject;
688 }
689 
getAnnotationCount()690 int PDFiumPageImpl::getAnnotationCount() { return FPDFPage_GetAnnotCount(mpPage); }
691 
getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const & rAnnotation)692 int PDFiumPageImpl::getAnnotationIndex(std::unique_ptr<PDFiumAnnotation> const& rAnnotation)
693 {
694     auto pAnnotation = static_cast<PDFiumAnnotationImpl*>(rAnnotation.get());
695     return FPDFPage_GetAnnotIndex(mpPage, pAnnotation->getPointer());
696 }
697 
getAnnotation(int nIndex)698 std::unique_ptr<PDFiumAnnotation> PDFiumPageImpl::getAnnotation(int nIndex)
699 {
700     std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
701     FPDF_ANNOTATION pAnnotation = FPDFPage_GetAnnot(mpPage, nIndex);
702     if (pAnnotation)
703     {
704         pPDFiumAnnotation = std::make_unique<PDFiumAnnotationImpl>(pAnnotation);
705     }
706     return pPDFiumAnnotation;
707 }
708 
getTextPage()709 std::unique_ptr<PDFiumTextPage> PDFiumPageImpl::getTextPage()
710 {
711     std::unique_ptr<PDFiumTextPage> pPDFiumTextPage;
712     FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(mpPage);
713     if (pTextPage)
714     {
715         pPDFiumTextPage = std::make_unique<PDFiumTextPageImpl>(pTextPage);
716     }
717     return pPDFiumTextPage;
718 }
719 
hasLinks()720 bool PDFiumPageImpl::hasLinks()
721 {
722     // This could be a full iterator, but at the moment we just determine if the list is empty or
723     // not.
724     int nStartPos = 0;
725     FPDF_LINK pLinkAnnot = nullptr;
726     return FPDFLink_Enumerate(mpPage, &nStartPos, &pLinkAnnot);
727 }
728 
PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject)729 PDFiumPageObjectImpl::PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject)
730     : mpPageObject(pPageObject)
731 {
732 }
733 
getText(std::unique_ptr<PDFiumTextPage> const & rTextPage)734 OUString PDFiumPageObjectImpl::getText(std::unique_ptr<PDFiumTextPage> const& rTextPage)
735 {
736     OUString sReturnText;
737 
738     auto pTextPage = static_cast<PDFiumTextPageImpl*>(rTextPage.get());
739     int nBytes = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(), nullptr, 0);
740     assert(nBytes % 2 == 0);
741     nBytes /= 2;
742 
743     std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nBytes]);
744 
745     int nActualBytes
746         = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(), pText.get(), nBytes * 2);
747     assert(nActualBytes % 2 == 0);
748     nActualBytes /= 2;
749     if (nActualBytes > 1)
750     {
751 #if defined OSL_BIGENDIAN
752         // The data returned by FPDFTextObj_GetText is documented to always be UTF-16LE:
753         for (int i = 0; i != nActualBytes; ++i)
754         {
755             pText[i] = OSL_SWAPWORD(pText[i]);
756         }
757 #endif
758         sReturnText = OUString(pText.get());
759     }
760 
761     return sReturnText;
762 }
763 
getType()764 PDFPageObjectType PDFiumPageObjectImpl::getType()
765 {
766     return static_cast<PDFPageObjectType>(FPDFPageObj_GetType(mpPageObject));
767 }
768 
getFormObjectCount()769 int PDFiumPageObjectImpl::getFormObjectCount() { return FPDFFormObj_CountObjects(mpPageObject); }
770 
getFormObject(int nIndex)771 std::unique_ptr<PDFiumPageObject> PDFiumPageObjectImpl::getFormObject(int nIndex)
772 {
773     std::unique_ptr<PDFiumPageObject> pPDFiumFormObject;
774     FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(mpPageObject, nIndex);
775     if (pFormObject)
776     {
777         pPDFiumFormObject = std::make_unique<PDFiumPageObjectImpl>(pFormObject);
778     }
779     return pPDFiumFormObject;
780 }
781 
getMatrix()782 basegfx::B2DHomMatrix PDFiumPageObjectImpl::getMatrix()
783 {
784     basegfx::B2DHomMatrix aB2DMatrix;
785     FS_MATRIX matrix;
786     if (FPDFFormObj_GetMatrix(mpPageObject, &matrix))
787         aB2DMatrix = basegfx::B2DHomMatrix::abcdef(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e,
788                                                    matrix.f);
789     return aB2DMatrix;
790 }
791 
getBounds()792 basegfx::B2DRectangle PDFiumPageObjectImpl::getBounds()
793 {
794     basegfx::B2DRectangle aB2DRectangle;
795 
796     float left = 0;
797     float bottom = 0;
798     float right = 0;
799     float top = 0;
800     if (FPDFPageObj_GetBounds(mpPageObject, &left, &bottom, &right, &top))
801     {
802         aB2DRectangle = basegfx::B2DRectangle(left, top, right, bottom);
803     }
804     return aB2DRectangle;
805 }
806 
getFontSize()807 double PDFiumPageObjectImpl::getFontSize() { return FPDFTextObj_GetFontSize(mpPageObject); }
808 
getFontName()809 OUString PDFiumPageObjectImpl::getFontName()
810 {
811     OUString sFontName;
812     const int nFontName = 80 + 1;
813     std::unique_ptr<char[]> pFontName(new char[nFontName]); // + terminating null
814     int nFontNameChars = FPDFTextObj_GetFontName(mpPageObject, pFontName.get(), nFontName);
815     if (nFontName >= nFontNameChars)
816     {
817         sFontName = OUString::createFromAscii(pFontName.get());
818     }
819     return sFontName;
820 }
821 
getTextRenderMode()822 PDFTextRenderMode PDFiumPageObjectImpl::getTextRenderMode()
823 {
824     return static_cast<PDFTextRenderMode>(FPDFTextObj_GetTextRenderMode(mpPageObject));
825 }
826 
getFillColor()827 Color PDFiumPageObjectImpl::getFillColor()
828 {
829     Color aColor = COL_TRANSPARENT;
830     unsigned int nR, nG, nB, nA;
831     if (FPDFPageObj_GetFillColor(mpPageObject, &nR, &nG, &nB, &nA))
832     {
833         aColor = Color(ColorAlpha, nA, nR, nG, nB);
834     }
835     return aColor;
836 }
837 
getStrokeColor()838 Color PDFiumPageObjectImpl::getStrokeColor()
839 {
840     Color aColor = COL_TRANSPARENT;
841     unsigned int nR, nG, nB, nA;
842     if (FPDFPageObj_GetStrokeColor(mpPageObject, &nR, &nG, &nB, &nA))
843     {
844         aColor = Color(ColorAlpha, nA, nR, nG, nB);
845     }
846     return aColor;
847 }
848 
getStrokeWidth()849 double PDFiumPageObjectImpl::getStrokeWidth()
850 {
851     float fWidth = 1;
852     FPDFPageObj_GetStrokeWidth(mpPageObject, &fWidth);
853     return fWidth;
854 }
855 
getPathSegmentCount()856 int PDFiumPageObjectImpl::getPathSegmentCount() { return FPDFPath_CountSegments(mpPageObject); }
857 
getPathSegment(int index)858 std::unique_ptr<PDFiumPathSegment> PDFiumPageObjectImpl::getPathSegment(int index)
859 {
860     std::unique_ptr<PDFiumPathSegment> pPDFiumPathSegment;
861     FPDF_PATHSEGMENT pPathSegment = FPDFPath_GetPathSegment(mpPageObject, index);
862     if (pPathSegment)
863     {
864         pPDFiumPathSegment = std::make_unique<PDFiumPathSegmentImpl>(pPathSegment);
865     }
866     return pPDFiumPathSegment;
867 }
868 
getImageSize(PDFiumPage & rPage)869 Size PDFiumPageObjectImpl::getImageSize(PDFiumPage& rPage)
870 {
871     FPDF_IMAGEOBJ_METADATA aMeta;
872     auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage);
873     FPDFImageObj_GetImageMetadata(mpPageObject, rPageImpl.getPointer(), &aMeta);
874     return Size(aMeta.width, aMeta.height);
875 }
876 
getImageBitmap()877 std::unique_ptr<PDFiumBitmap> PDFiumPageObjectImpl::getImageBitmap()
878 {
879     std::unique_ptr<PDFiumBitmap> pPDFiumBitmap;
880     FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(mpPageObject);
881     if (pBitmap)
882     {
883         pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap);
884     }
885     return pPDFiumBitmap;
886 }
887 
getDrawMode(PDFFillMode & rFillMode,bool & rStroke)888 bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& rFillMode, bool& rStroke)
889 {
890     auto nFillMode = static_cast<int>(rFillMode);
891     auto bStroke = static_cast<FPDF_BOOL>(rStroke);
892     bool bRet = FPDFPath_GetDrawMode(mpPageObject, &nFillMode, &bStroke);
893     rFillMode = static_cast<PDFFillMode>(nFillMode);
894     rStroke = static_cast<bool>(bStroke);
895     return bRet;
896 }
897 
getChecksum(int nMDPPerm)898 BitmapChecksum PDFiumPageImpl::getChecksum(int nMDPPerm)
899 {
900     size_t nPageWidth = getWidth();
901     size_t nPageHeight = getHeight();
902     auto pPdfBitmap = std::make_unique<PDFiumBitmapImpl>(
903         FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1));
904     if (!pPdfBitmap)
905     {
906         return 0;
907     }
908 
909     int nFlags = 0;
910     if (nMDPPerm != 3)
911     {
912         // Annotations/commenting should affect the checksum, signature verification wants this.
913         nFlags = FPDF_ANNOT;
914     }
915     FPDF_RenderPageBitmap(pPdfBitmap->getPointer(), mpPage, /*start_x=*/0, /*start_y=*/0,
916                           nPageWidth, nPageHeight,
917                           /*rotate=*/0, nFlags);
918     Bitmap aBitmap(Size(nPageWidth, nPageHeight), vcl::PixelFormat::N24_BPP);
919     {
920         BitmapScopedWriteAccess pWriteAccess(aBitmap);
921         const auto pPdfBuffer
922             = static_cast<ConstScanline>(FPDFBitmap_GetBuffer(pPdfBitmap->getPointer()));
923         const int nStride = FPDFBitmap_GetStride(pPdfBitmap->getPointer());
924         for (size_t nRow = 0; nRow < nPageHeight; ++nRow)
925         {
926             ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow);
927             pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride);
928         }
929     }
930     return aBitmap.GetChecksum();
931 }
932 
getWidth()933 double PDFiumPageImpl::getWidth() { return FPDF_GetPageWidth(mpPage); }
934 
getHeight()935 double PDFiumPageImpl::getHeight() { return FPDF_GetPageHeight(mpPage); }
936 
hasTransparency()937 bool PDFiumPageImpl::hasTransparency() { return FPDFPage_HasTransparency(mpPage); }
938 
PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment)939 PDFiumPathSegmentImpl::PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment)
940     : mpPathSegment(pPathSegment)
941 {
942 }
943 
getPoint() const944 basegfx::B2DPoint PDFiumPathSegmentImpl::getPoint() const
945 {
946     basegfx::B2DPoint aPoint;
947     float fx, fy;
948     if (FPDFPathSegment_GetPoint(mpPathSegment, &fx, &fy))
949         aPoint = basegfx::B2DPoint(fx, fy);
950     return aPoint;
951 }
952 
isClosed() const953 bool PDFiumPathSegmentImpl::isClosed() const { return FPDFPathSegment_GetClose(mpPathSegment); }
954 
getType() const955 PDFSegmentType PDFiumPathSegmentImpl::getType() const
956 {
957     return static_cast<PDFSegmentType>(FPDFPathSegment_GetType(mpPathSegment));
958 }
959 
PDFiumFormHandle(FPDF_FORMHANDLE pHandle)960 PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle)
961     : mpHandle(pHandle)
962 {
963 }
964 
~PDFiumFormHandle()965 PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle); }
966 
getPointer()967 FPDF_FORMHANDLE PDFiumFormHandle::getPointer() { return mpHandle; }
968 
PDFiumBitmapImpl(FPDF_BITMAP pBitmap)969 PDFiumBitmapImpl::PDFiumBitmapImpl(FPDF_BITMAP pBitmap)
970     : mpBitmap(pBitmap)
971 {
972 }
973 
~PDFiumBitmapImpl()974 PDFiumBitmapImpl::~PDFiumBitmapImpl()
975 {
976     if (mpBitmap)
977     {
978         FPDFBitmap_Destroy(mpBitmap);
979     }
980 }
981 
fillRect(int left,int top,int width,int height,sal_uInt32 nColor)982 void PDFiumBitmapImpl::fillRect(int left, int top, int width, int height, sal_uInt32 nColor)
983 {
984     FPDFBitmap_FillRect(mpBitmap, left, top, width, height, nColor);
985 }
986 
renderPageBitmap(PDFiumDocument * pDoc,PDFiumPage * pPage,int nStartX,int nStartY,int nSizeX,int nSizeY)987 void PDFiumBitmapImpl::renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX,
988                                         int nStartY, int nSizeX, int nSizeY)
989 {
990     auto pPageImpl = static_cast<PDFiumPageImpl*>(pPage);
991     FPDF_RenderPageBitmap(mpBitmap, pPageImpl->getPointer(), nStartX, nStartY, nSizeX, nSizeY,
992                           /*rotate=*/0, /*flags=*/0);
993 
994     // Render widget annotations for FormFields.
995     auto pDocImpl = static_cast<PDFiumDocumentImpl*>(pDoc);
996     FPDF_FFLDraw(pDocImpl->getFormHandlePointer(), mpBitmap, pPageImpl->getPointer(), nStartX,
997                  nStartY, nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0);
998 }
999 
getBuffer()1000 ConstScanline PDFiumBitmapImpl::getBuffer()
1001 {
1002     return static_cast<ConstScanline>(FPDFBitmap_GetBuffer(mpBitmap));
1003 }
1004 
getStride()1005 int PDFiumBitmapImpl::getStride() { return FPDFBitmap_GetStride(mpBitmap); }
1006 
getWidth()1007 int PDFiumBitmapImpl::getWidth() { return FPDFBitmap_GetWidth(mpBitmap); }
1008 
getHeight()1009 int PDFiumBitmapImpl::getHeight() { return FPDFBitmap_GetHeight(mpBitmap); }
1010 
getFormat()1011 PDFBitmapType PDFiumBitmapImpl::getFormat()
1012 {
1013     return static_cast<PDFBitmapType>(FPDFBitmap_GetFormat(mpBitmap));
1014 }
1015 
PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation)1016 PDFiumAnnotationImpl::PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation)
1017     : mpAnnotation(pAnnotation)
1018 {
1019 }
1020 
~PDFiumAnnotationImpl()1021 PDFiumAnnotationImpl::~PDFiumAnnotationImpl()
1022 {
1023     if (mpAnnotation)
1024         FPDFPage_CloseAnnot(mpAnnotation);
1025 }
1026 
getSubType()1027 PDFAnnotationSubType PDFiumAnnotationImpl::getSubType()
1028 {
1029     return PDFAnnotationSubType(FPDFAnnot_GetSubtype(mpAnnotation));
1030 }
1031 
getRectangle()1032 basegfx::B2DRectangle PDFiumAnnotationImpl::getRectangle()
1033 {
1034     basegfx::B2DRectangle aB2DRectangle;
1035     FS_RECTF aRect;
1036     if (FPDFAnnot_GetRect(mpAnnotation, &aRect))
1037     {
1038         aB2DRectangle = basegfx::B2DRectangle(aRect.left, aRect.top, aRect.right, aRect.bottom);
1039     }
1040     return aB2DRectangle;
1041 }
1042 
getColor()1043 Color PDFiumAnnotationImpl::getColor()
1044 {
1045     Color aColor = COL_TRANSPARENT;
1046     unsigned int nR, nG, nB, nA;
1047     if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_Color, &nR, &nG, &nB, &nA))
1048     {
1049         aColor = Color(ColorAlpha, nA, nR, nG, nB);
1050     }
1051     return aColor;
1052 }
1053 
getInteriorColor()1054 Color PDFiumAnnotationImpl::getInteriorColor()
1055 {
1056     Color aColor = COL_TRANSPARENT;
1057     unsigned int nR, nG, nB, nA;
1058     if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_InteriorColor, &nR, &nG, &nB, &nA))
1059     {
1060         aColor = Color(ColorAlpha, nA, nR, nG, nB);
1061     }
1062     return aColor;
1063 }
1064 
getAttachmentPointsCount()1065 size_t PDFiumAnnotationImpl::getAttachmentPointsCount()
1066 {
1067     return FPDFAnnot_CountAttachmentPoints(mpAnnotation);
1068 }
1069 
getAttachmentPoints(size_t nIndex)1070 std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getAttachmentPoints(size_t nIndex)
1071 {
1072     std::vector<basegfx::B2DPoint> aQuads;
1073 
1074     FS_QUADPOINTSF aQuadpoints;
1075     if (FPDFAnnot_GetAttachmentPoints(mpAnnotation, nIndex, &aQuadpoints))
1076     {
1077         aQuads.emplace_back(aQuadpoints.x1, aQuadpoints.y1);
1078         aQuads.emplace_back(aQuadpoints.x2, aQuadpoints.y2);
1079         aQuads.emplace_back(aQuadpoints.x3, aQuadpoints.y3);
1080         aQuads.emplace_back(aQuadpoints.x4, aQuadpoints.y4);
1081     }
1082     return aQuads;
1083 }
1084 
getLineGeometry()1085 std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getLineGeometry()
1086 {
1087     std::vector<basegfx::B2DPoint> aLine;
1088     FS_POINTF aStart;
1089     FS_POINTF aEnd;
1090     if (FPDFAnnot_GetLine(mpAnnotation, &aStart, &aEnd))
1091     {
1092         aLine.emplace_back(aStart.x, aStart.y);
1093         aLine.emplace_back(aEnd.x, aEnd.y);
1094     }
1095     return aLine;
1096 }
1097 
1098 namespace
1099 {
getBorderProperties(FPDF_ANNOTATION mpAnnotation,float & rHorizontalCornerRadius,float & rVerticalCornerRadius,float & rBorderWidth)1100 bool getBorderProperties(FPDF_ANNOTATION mpAnnotation, float& rHorizontalCornerRadius,
1101                          float& rVerticalCornerRadius, float& rBorderWidth)
1102 {
1103     float fHoriRadius = 0.0f;
1104     float fVertRadius = 0.0f;
1105     float fWidth = 0.0f;
1106 
1107     if (!FPDFAnnot_GetBorder(mpAnnotation, &fHoriRadius, &fVertRadius, &fWidth))
1108         return false;
1109 
1110     rHorizontalCornerRadius = fHoriRadius;
1111     rVerticalCornerRadius = fVertRadius;
1112     rBorderWidth = fWidth;
1113     return true;
1114 }
1115 }
1116 
getBorderWidth()1117 float PDFiumAnnotationImpl::getBorderWidth()
1118 {
1119     float fHorizontalCornerRadius;
1120     float fVerticalCornerRadius;
1121     float fBorderWidth;
1122 
1123     if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius,
1124                              fBorderWidth))
1125         return 0.0f;
1126     return fBorderWidth;
1127 }
1128 
getBorderCornerRadius()1129 basegfx::B2DSize PDFiumAnnotationImpl::getBorderCornerRadius()
1130 {
1131     float fHorizontalCornerRadius;
1132     float fVerticalCornerRadius;
1133     float fBorderWidth;
1134 
1135     if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius,
1136                              fBorderWidth))
1137         return basegfx::B2DSize(0.0, 0.0);
1138     return basegfx::B2DSize(fHorizontalCornerRadius, fVerticalCornerRadius);
1139 }
1140 
hasKey(OString const & rKey)1141 bool PDFiumAnnotationImpl::hasKey(OString const& rKey)
1142 {
1143     return FPDFAnnot_HasKey(mpAnnotation, rKey.getStr());
1144 }
1145 
getValueType(OString const & rKey)1146 PDFObjectType PDFiumAnnotationImpl::getValueType(OString const& rKey)
1147 {
1148     return static_cast<PDFObjectType>(FPDFAnnot_GetValueType(mpAnnotation, rKey.getStr()));
1149 }
1150 
getString(OString const & rKey)1151 OUString PDFiumAnnotationImpl::getString(OString const& rKey)
1152 {
1153     OUString rString;
1154     unsigned long nSize = FPDFAnnot_GetStringValue(mpAnnotation, rKey.getStr(), nullptr, 0);
1155     assert(nSize % 2 == 0);
1156     nSize /= 2;
1157     if (nSize > 1)
1158     {
1159         std::unique_ptr<sal_Unicode[]> pText(new sal_Unicode[nSize]);
1160         unsigned long nStringSize = FPDFAnnot_GetStringValue(
1161             mpAnnotation, rKey.getStr(), reinterpret_cast<FPDF_WCHAR*>(pText.get()), nSize * 2);
1162         assert(nStringSize % 2 == 0);
1163         nStringSize /= 2;
1164         if (nStringSize > 0)
1165         {
1166 #if defined OSL_BIGENDIAN
1167             // The data returned by FPDFAnnot_GetStringValue is documented to always be UTF-16LE:
1168             for (unsigned long i = 0; i != nStringSize; ++i)
1169             {
1170                 pText[i] = OSL_SWAPWORD(pText[i]);
1171             }
1172 #endif
1173             rString = OUString(pText.get());
1174         }
1175     }
1176     return rString;
1177 }
1178 
getInkStrokes()1179 std::vector<std::vector<basegfx::B2DPoint>> PDFiumAnnotationImpl::getInkStrokes()
1180 {
1181     std::vector<std::vector<basegfx::B2DPoint>> aB2DPointList;
1182     int nInkStrokes = FPDFAnnot_GetInkListCount(mpAnnotation);
1183     for (int i = 0; i < nInkStrokes; i++)
1184     {
1185         std::vector<basegfx::B2DPoint> aB2DPoints;
1186         int nPoints = FPDFAnnot_GetInkListPath(mpAnnotation, i, nullptr, 0);
1187         if (nPoints)
1188         {
1189             std::vector<FS_POINTF> aPoints(nPoints);
1190             if (FPDFAnnot_GetInkListPath(mpAnnotation, i, aPoints.data(), aPoints.size()))
1191             {
1192                 for (auto const& rPoint : aPoints)
1193                 {
1194                     aB2DPoints.emplace_back(rPoint.x, rPoint.y);
1195                 }
1196                 aB2DPointList.push_back(aB2DPoints);
1197             }
1198         }
1199     }
1200     return aB2DPointList;
1201 }
1202 
getVertices()1203 std::vector<basegfx::B2DPoint> PDFiumAnnotationImpl::getVertices()
1204 {
1205     std::vector<basegfx::B2DPoint> aB2DPoints;
1206     int nPoints = FPDFAnnot_GetVertices(mpAnnotation, nullptr, 0);
1207     if (nPoints)
1208     {
1209         std::vector<FS_POINTF> aPoints(nPoints);
1210         if (FPDFAnnot_GetVertices(mpAnnotation, aPoints.data(), aPoints.size()))
1211         {
1212             for (auto const& rPoint : aPoints)
1213                 aB2DPoints.emplace_back(rPoint.x, rPoint.y);
1214         }
1215     }
1216     return aB2DPoints;
1217 }
1218 
getLinked(OString const & rKey)1219 std::unique_ptr<PDFiumAnnotation> PDFiumAnnotationImpl::getLinked(OString const& rKey)
1220 {
1221     std::unique_ptr<PDFiumAnnotation> pPDFiumAnnotation;
1222     FPDF_ANNOTATION pAnnotation = FPDFAnnot_GetLinkedAnnot(mpAnnotation, rKey.getStr());
1223     if (pAnnotation)
1224     {
1225         pPDFiumAnnotation = std::make_unique<PDFiumAnnotationImpl>(pAnnotation);
1226     }
1227     return pPDFiumAnnotation;
1228 }
1229 
getObjectCount()1230 int PDFiumAnnotationImpl::getObjectCount() { return FPDFAnnot_GetObjectCount(mpAnnotation); }
1231 
getObject(int nIndex)1232 std::unique_ptr<PDFiumPageObject> PDFiumAnnotationImpl::getObject(int nIndex)
1233 {
1234     std::unique_ptr<PDFiumPageObject> pPDFiumPageObject;
1235     FPDF_PAGEOBJECT pPageObject = FPDFAnnot_GetObject(mpAnnotation, nIndex);
1236     if (pPageObject)
1237     {
1238         pPDFiumPageObject = std::make_unique<PDFiumPageObjectImpl>(pPageObject);
1239     }
1240     return pPDFiumPageObject;
1241 }
1242 
PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage)1243 PDFiumTextPageImpl::PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage)
1244     : mpTextPage(pTextPage)
1245 {
1246 }
1247 
~PDFiumTextPageImpl()1248 PDFiumTextPageImpl::~PDFiumTextPageImpl()
1249 {
1250     if (mpTextPage)
1251         FPDFText_ClosePage(mpTextPage);
1252 }
1253 
countChars()1254 int PDFiumTextPageImpl::countChars() { return FPDFText_CountChars(mpTextPage); }
1255 
getCharBox(int nIndex,double fPageHeight)1256 basegfx::B2DRectangle PDFiumTextPageImpl::getCharBox(int nIndex, double fPageHeight)
1257 {
1258     double left = 0.0;
1259     double right = 0.0;
1260     double bottom = 0.0;
1261     double top = 0.0;
1262 
1263     if (FPDFText_GetCharBox(mpTextPage, nIndex, &left, &right, &bottom, &top))
1264     {
1265         left = convertPointToMm100(left);
1266         right = convertPointToMm100(right);
1267         top = fPageHeight - convertPointToMm100(top);
1268         bottom = fPageHeight - convertPointToMm100(bottom);
1269 
1270         return basegfx::B2DRectangle(left, bottom, right, top);
1271     }
1272 
1273     return basegfx::B2DRectangle();
1274 }
1275 
getUnicode(int index)1276 unsigned int PDFiumTextPageImpl::getUnicode(int index)
1277 {
1278     return FPDFText_GetUnicode(mpTextPage, index);
1279 }
1280 
1281 std::unique_ptr<PDFiumSearchHandle>
findStart(const OUString & rFindWhat,PDFFindFlags nFlags,sal_Int32 nStartIndex)1282 PDFiumTextPageImpl::findStart(const OUString& rFindWhat, PDFFindFlags nFlags, sal_Int32 nStartIndex)
1283 {
1284     FPDF_WIDESTRING pFindWhat = reinterpret_cast<FPDF_WIDESTRING>(rFindWhat.getStr());
1285     return std::make_unique<vcl::pdf::PDFiumSearchHandleImpl>(
1286         FPDFText_FindStart(mpTextPage, pFindWhat, static_cast<sal_uInt32>(nFlags), nStartIndex));
1287 }
1288 
PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle)1289 PDFiumSearchHandleImpl::PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle)
1290     : mpSearchHandle(pSearchHandle)
1291 {
1292 }
1293 
~PDFiumSearchHandleImpl()1294 PDFiumSearchHandleImpl::~PDFiumSearchHandleImpl()
1295 {
1296     if (mpSearchHandle)
1297         FPDFText_FindClose(mpSearchHandle);
1298 }
1299 
findNext()1300 bool PDFiumSearchHandleImpl::findNext() { return FPDFText_FindNext(mpSearchHandle); }
1301 
findPrev()1302 bool PDFiumSearchHandleImpl::findPrev() { return FPDFText_FindPrev(mpSearchHandle); }
1303 
getSearchResultIndex()1304 int PDFiumSearchHandleImpl::getSearchResultIndex()
1305 {
1306     return FPDFText_GetSchResultIndex(mpSearchHandle);
1307 }
1308 
getSearchCount()1309 int PDFiumSearchHandleImpl::getSearchCount() { return FPDFText_GetSchCount(mpSearchHandle); }
1310 
get()1311 std::shared_ptr<PDFium>& PDFiumLibrary::get()
1312 {
1313     static std::shared_ptr<PDFium> pInstance = std::make_shared<PDFiumImpl>();
1314     return pInstance;
1315 }
1316 
1317 } // end vcl::pdf
1318 
1319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1320