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