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