1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
11 #include <vcl/filter/PDFiumLibrary.hxx>
15 #include <sal/log.hxx>
17 #include <fpdf_annot.h>
18 #include <fpdf_edit.h>
19 #include <fpdf_text.h>
20 #include <fpdf_save.h>
21 #include <fpdf_signature.h>
22 #include <fpdf_formfill.h>
23 #include <fpdf_attachment.h>
25 #include <osl/endian.h>
26 #include <vcl/bitmap.hxx>
27 #include <tools/stream.hxx>
28 #include <tools/UnitConversion.hxx>
29 #include <o3tl/string_view.hxx>
30 #include <rtl/ustrbuf.hxx>
32 #include <vcl/BitmapWriteAccess.hxx>
33 #include <vcl/bitmapex.hxx>
34 #include <vcl/dibtools.hxx>
37 using namespace com::sun::star
;
39 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Unknown
) == FPDF_PAGEOBJ_UNKNOWN
,
40 "PDFPageObjectType::Unknown value mismatch");
41 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Text
) == FPDF_PAGEOBJ_TEXT
,
42 "PDFPageObjectType::Text value mismatch");
43 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Path
) == FPDF_PAGEOBJ_PATH
,
44 "PDFPageObjectType::Path value mismatch");
45 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Image
) == FPDF_PAGEOBJ_IMAGE
,
46 "PDFPageObjectType::Image value mismatch");
47 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Shading
) == FPDF_PAGEOBJ_SHADING
,
48 "PDFPageObjectType::Shading value mismatch");
49 static_assert(static_cast<int>(vcl::pdf::PDFPageObjectType::Form
) == FPDF_PAGEOBJ_FORM
,
50 "PDFPageObjectType::Form value mismatch");
52 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Unknown
) == FPDF_SEGMENT_UNKNOWN
,
53 "PDFSegmentType::Unknown value mismatch");
54 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Lineto
) == FPDF_SEGMENT_LINETO
,
55 "PDFSegmentType::Lineto value mismatch");
56 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Bezierto
) == FPDF_SEGMENT_BEZIERTO
,
57 "PDFSegmentType::Bezierto value mismatch");
58 static_assert(static_cast<int>(vcl::pdf::PDFSegmentType::Moveto
) == FPDF_SEGMENT_MOVETO
,
59 "PDFSegmentType::Moveto value mismatch");
61 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Unknown
) == FPDFBitmap_Unknown
,
62 "PDFBitmapType::Unknown value mismatch");
63 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::Gray
) == FPDFBitmap_Gray
,
64 "PDFBitmapType::Gray value mismatch");
65 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGR
) == FPDFBitmap_BGR
,
66 "PDFBitmapType::BGR value mismatch");
67 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRx
) == FPDFBitmap_BGRx
,
68 "PDFBitmapType::BGRx value mismatch");
69 static_assert(static_cast<int>(vcl::pdf::PDFBitmapType::BGRA
) == FPDFBitmap_BGRA
,
70 "PDFBitmapType::BGRA value mismatch");
72 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Unknown
) == FPDF_OBJECT_UNKNOWN
,
73 "PDFObjectType::Unknown value mismatch");
74 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Boolean
) == FPDF_OBJECT_BOOLEAN
,
75 "PDFObjectType::Boolean value mismatch");
76 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Number
) == FPDF_OBJECT_NUMBER
,
77 "PDFObjectType::Number value mismatch");
78 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::String
) == FPDF_OBJECT_STRING
,
79 "PDFObjectType::String value mismatch");
80 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Name
) == FPDF_OBJECT_NAME
,
81 "PDFObjectType::Name value mismatch");
82 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Array
) == FPDF_OBJECT_ARRAY
,
83 "PDFObjectType::Array value mismatch");
84 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Dictionary
) == FPDF_OBJECT_DICTIONARY
,
85 "PDFObjectType::Dictionary value mismatch");
86 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Stream
) == FPDF_OBJECT_STREAM
,
87 "PDFObjectType::Stream value mismatch");
88 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Nullobj
) == FPDF_OBJECT_NULLOBJ
,
89 "PDFObjectType::Nullobj value mismatch");
90 static_assert(static_cast<int>(vcl::pdf::PDFObjectType::Reference
) == FPDF_OBJECT_REFERENCE
,
91 "PDFObjectType::Reference value mismatch");
93 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Unknown
) == FPDF_TEXTRENDERMODE_UNKNOWN
,
94 "PDFTextRenderMode::Unknown value mismatch");
95 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Fill
) == FPDF_TEXTRENDERMODE_FILL
,
96 "PDFTextRenderMode::Fill value mismatch");
97 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Stroke
) == FPDF_TEXTRENDERMODE_STROKE
,
98 "PDFTextRenderMode::Stroke value mismatch");
99 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStroke
)
100 == FPDF_TEXTRENDERMODE_FILL_STROKE
,
101 "PDFTextRenderMode::FillStroke value mismatch");
102 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Invisible
)
103 == FPDF_TEXTRENDERMODE_INVISIBLE
,
104 "PDFTextRenderMode::Invisible value mismatch");
105 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillClip
)
106 == FPDF_TEXTRENDERMODE_FILL_CLIP
,
107 "PDFTextRenderMode::FillClip value mismatch");
108 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::StrokeClip
)
109 == FPDF_TEXTRENDERMODE_STROKE_CLIP
,
110 "PDFTextRenderMode::StrokeClip value mismatch");
111 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::FillStrokeClip
)
112 == FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP
,
113 "PDFTextRenderMode::FillStrokeClip value mismatch");
114 static_assert(static_cast<int>(vcl::pdf::PDFTextRenderMode::Clip
) == FPDF_TEXTRENDERMODE_CLIP
,
115 "PDFTextRenderMode::Clip value mismatch");
117 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::None
) == FPDF_FILLMODE_NONE
,
118 "PDFFillMode::None value mismatch");
119 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Alternate
) == FPDF_FILLMODE_ALTERNATE
,
120 "PDFFillMode::Alternate value mismatch");
121 static_assert(static_cast<int>(vcl::pdf::PDFFillMode::Winding
) == FPDF_FILLMODE_WINDING
,
122 "PDFFillMode::Winding value mismatch");
124 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchCase
) == FPDF_MATCHCASE
,
125 "PDFFindFlags::MatchCase value mismatch");
126 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::MatchWholeWord
) == FPDF_MATCHWHOLEWORD
,
127 "PDFFindFlags::MatchWholeWord value mismatch");
128 static_assert(static_cast<int>(vcl::pdf::PDFFindFlags::Consecutive
) == FPDF_CONSECUTIVE
,
129 "PDFFindFlags::Consecutive value mismatch");
131 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Success
) == FPDF_ERR_SUCCESS
,
132 "PDFErrorType::Success value mismatch");
133 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Unknown
) == FPDF_ERR_UNKNOWN
,
134 "PDFErrorType::Unknown value mismatch");
135 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::File
) == FPDF_ERR_FILE
,
136 "PDFErrorType::File value mismatch");
137 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Format
) == FPDF_ERR_FORMAT
,
138 "PDFErrorType::Format value mismatch");
139 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Password
) == FPDF_ERR_PASSWORD
,
140 "PDFErrorType::Password value mismatch");
141 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Security
) == FPDF_ERR_SECURITY
,
142 "PDFErrorType::Security value mismatch");
143 static_assert(static_cast<int>(vcl::pdf::PDFErrorType::Page
) == FPDF_ERR_PAGE
,
144 "PDFErrorType::Page value mismatch");
146 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::Unknown
) == FPDF_FORMFIELD_UNKNOWN
,
147 "PDFFormFieldType::Unknown value mismatch");
148 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::PushButton
) == FPDF_FORMFIELD_PUSHBUTTON
,
149 "PDFFormFieldType::PushButton value mismatch");
150 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::CheckBox
) == FPDF_FORMFIELD_CHECKBOX
,
151 "PDFFormFieldType::CheckBox value mismatch");
152 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::RadioButton
)
153 == FPDF_FORMFIELD_RADIOBUTTON
,
154 "PDFFormFieldType::RadioButton value mismatch");
155 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::ComboBox
) == FPDF_FORMFIELD_COMBOBOX
,
156 "PDFFormFieldType::ComboBox value mismatch");
157 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::ListBox
) == FPDF_FORMFIELD_LISTBOX
,
158 "PDFFormFieldType::ListBox value mismatch");
159 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::TextField
) == FPDF_FORMFIELD_TEXTFIELD
,
160 "PDFFormFieldType::TextField value mismatch");
161 static_assert(static_cast<int>(vcl::pdf::PDFFormFieldType::Signature
) == FPDF_FORMFIELD_SIGNATURE
,
162 "PDFFormFieldType::Signature value mismatch");
164 static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::KeyStroke
)
165 == FPDF_ANNOT_AACTION_KEY_STROKE
,
166 "PDFAnnotAActionType::KeyStroke) value mismatch");
167 static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Format
) == FPDF_ANNOT_AACTION_FORMAT
,
168 "PDFAnnotAActionType::Format) value mismatch");
169 static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Validate
)
170 == FPDF_ANNOT_AACTION_VALIDATE
,
171 "PDFAnnotAActionType::Validate) value mismatch");
172 static_assert(static_cast<int>(vcl::pdf::PDFAnnotAActionType::Calculate
)
173 == FPDF_ANNOT_AACTION_CALCULATE
,
174 "PDFAnnotAActionType::Calculate) value mismatch");
176 static_assert(int(vcl::pdf::PDFAnnotationSubType::Unknown
) == FPDF_ANNOT_UNKNOWN
);
177 static_assert(int(vcl::pdf::PDFAnnotationSubType::Text
) == FPDF_ANNOT_TEXT
);
178 static_assert(int(vcl::pdf::PDFAnnotationSubType::Link
) == FPDF_ANNOT_LINK
);
179 static_assert(int(vcl::pdf::PDFAnnotationSubType::FreeText
) == FPDF_ANNOT_FREETEXT
);
180 static_assert(int(vcl::pdf::PDFAnnotationSubType::Line
) == FPDF_ANNOT_LINE
);
181 static_assert(int(vcl::pdf::PDFAnnotationSubType::Square
) == FPDF_ANNOT_SQUARE
);
182 static_assert(int(vcl::pdf::PDFAnnotationSubType::Circle
) == FPDF_ANNOT_CIRCLE
);
183 static_assert(int(vcl::pdf::PDFAnnotationSubType::Polygon
) == FPDF_ANNOT_POLYGON
);
184 static_assert(int(vcl::pdf::PDFAnnotationSubType::Polyline
) == FPDF_ANNOT_POLYLINE
);
185 static_assert(int(vcl::pdf::PDFAnnotationSubType::Highlight
) == FPDF_ANNOT_HIGHLIGHT
);
186 static_assert(int(vcl::pdf::PDFAnnotationSubType::Underline
) == FPDF_ANNOT_UNDERLINE
);
187 static_assert(int(vcl::pdf::PDFAnnotationSubType::Squiggly
) == FPDF_ANNOT_SQUIGGLY
);
188 static_assert(int(vcl::pdf::PDFAnnotationSubType::Strikeout
) == FPDF_ANNOT_STRIKEOUT
);
189 static_assert(int(vcl::pdf::PDFAnnotationSubType::Stamp
) == FPDF_ANNOT_STAMP
);
190 static_assert(int(vcl::pdf::PDFAnnotationSubType::Caret
) == FPDF_ANNOT_CARET
);
191 static_assert(int(vcl::pdf::PDFAnnotationSubType::Ink
) == FPDF_ANNOT_INK
);
192 static_assert(int(vcl::pdf::PDFAnnotationSubType::Popup
) == FPDF_ANNOT_POPUP
);
193 static_assert(int(vcl::pdf::PDFAnnotationSubType::FileAttachment
) == FPDF_ANNOT_FILEATTACHMENT
);
194 static_assert(int(vcl::pdf::PDFAnnotationSubType::Sound
) == FPDF_ANNOT_SOUND
);
195 static_assert(int(vcl::pdf::PDFAnnotationSubType::Movie
) == FPDF_ANNOT_MOVIE
);
196 static_assert(int(vcl::pdf::PDFAnnotationSubType::Widget
) == FPDF_ANNOT_WIDGET
);
197 static_assert(int(vcl::pdf::PDFAnnotationSubType::Screen
) == FPDF_ANNOT_SCREEN
);
198 static_assert(int(vcl::pdf::PDFAnnotationSubType::Printermark
) == FPDF_ANNOT_PRINTERMARK
);
199 static_assert(int(vcl::pdf::PDFAnnotationSubType::Trapnet
) == FPDF_ANNOT_TRAPNET
);
200 static_assert(int(vcl::pdf::PDFAnnotationSubType::Watermark
) == FPDF_ANNOT_WATERMARK
);
201 static_assert(int(vcl::pdf::PDFAnnotationSubType::Threed
) == FPDF_ANNOT_THREED
);
202 static_assert(int(vcl::pdf::PDFAnnotationSubType::Richmedia
) == FPDF_ANNOT_RICHMEDIA
);
203 static_assert(int(vcl::pdf::PDFAnnotationSubType::XFAWidget
) == FPDF_ANNOT_XFAWIDGET
);
204 static_assert(int(vcl::pdf::PDFAnnotationSubType::Redact
) == FPDF_ANNOT_REDACT
);
208 /// Callback class to be used with FPDF_SaveWithVersion().
209 struct CompatibleWriter
: public FPDF_FILEWRITE
211 CompatibleWriter(SvMemoryStream
& rStream
)
216 SvMemoryStream
& m_rStream
;
219 int CompatibleWriterCallback(FPDF_FILEWRITE
* pFileWrite
, const void* pData
, unsigned long nSize
)
221 auto pImpl
= static_cast<CompatibleWriter
*>(pFileWrite
);
222 pImpl
->m_rStream
.WriteBytes(pData
, nSize
);
226 OUString
getUnicodeString(std::function
<int(FPDF_WCHAR
*, unsigned long)> aPDFiumFunctionCall
)
228 OUString sReturnText
;
230 int nBytes
= aPDFiumFunctionCall(nullptr, 0);
233 assert(nBytes
% 2 == 0);
236 std::vector
<sal_Unicode
> pText(nBytes
, 0);
238 int nActualBytes
= aPDFiumFunctionCall(reinterpret_cast<FPDF_WCHAR
*>(pText
.data()), nBytes
* 2);
239 assert(nActualBytes
% 2 == 0);
241 if (nActualBytes
> 1)
244 for (int i
= 0; i
!= nActualBytes
; ++i
)
246 pText
[i
] = OSL_SWAPWORD(pText
[i
]);
249 sReturnText
= OUString(pText
.data());
260 class PDFiumBitmapImpl final
: public PDFiumBitmap
263 FPDF_BITMAP mpBitmap
;
265 PDFiumBitmapImpl(const PDFiumBitmapImpl
&) = delete;
266 PDFiumBitmapImpl
& operator=(const PDFiumBitmapImpl
&) = delete;
269 PDFiumBitmapImpl(FPDF_BITMAP pBitmap
);
270 ~PDFiumBitmapImpl() override
;
271 FPDF_BITMAP
getPointer() { return mpBitmap
; }
273 void fillRect(int left
, int top
, int width
, int height
, sal_uInt32 nColor
) override
;
274 void renderPageBitmap(PDFiumDocument
* pDoc
, PDFiumPage
* pPage
, int nStartX
, int nStartY
,
275 int nSizeX
, int nSizeY
) override
;
276 ConstScanline
getBuffer() override
;
277 int getStride() override
;
278 int getWidth() override
;
279 int getHeight() override
;
280 PDFBitmapType
getFormat() override
;
281 BitmapEx
createBitmapFromBuffer() override
;
284 class PDFiumPathSegmentImpl final
: public PDFiumPathSegment
287 FPDF_PATHSEGMENT mpPathSegment
;
289 PDFiumPathSegmentImpl(const PDFiumPathSegmentImpl
&) = delete;
290 PDFiumPathSegmentImpl
& operator=(const PDFiumPathSegmentImpl
&) = delete;
293 PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment
);
295 basegfx::B2DPoint
getPoint() const override
;
296 bool isClosed() const override
;
297 PDFSegmentType
getType() const override
;
300 class PDFiumAnnotationImpl final
: public PDFiumAnnotation
303 FPDF_ANNOTATION mpAnnotation
;
305 PDFiumAnnotationImpl(const PDFiumAnnotationImpl
&) = delete;
306 PDFiumAnnotationImpl
& operator=(const PDFiumAnnotationImpl
&) = delete;
309 PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation
);
310 ~PDFiumAnnotationImpl();
311 FPDF_ANNOTATION
getPointer() { return mpAnnotation
; }
313 PDFAnnotationSubType
getSubType() override
;
314 basegfx::B2DRectangle
getRectangle() override
;
315 bool hasKey(OString
const& rKey
) override
;
316 PDFObjectType
getValueType(OString
const& rKey
) override
;
317 OUString
getString(OString
const& rKey
) override
;
318 std::unique_ptr
<PDFiumAnnotation
> getLinked(OString
const& rKey
) override
;
319 int getObjectCount() override
;
320 std::unique_ptr
<PDFiumPageObject
> getObject(int nIndex
) override
;
321 std::vector
<std::vector
<basegfx::B2DPoint
>> getInkStrokes() override
;
322 std::vector
<basegfx::B2DPoint
> getVertices() override
;
323 Color
getColor() override
;
324 Color
getInteriorColor() override
;
325 float getBorderWidth() override
;
326 basegfx::B2DSize
getBorderCornerRadius() override
;
327 size_t getAttachmentPointsCount() override
;
328 std::vector
<basegfx::B2DPoint
> getAttachmentPoints(size_t nIndex
) override
;
329 std::vector
<basegfx::B2DPoint
> getLineGeometry() override
;
330 PDFFormFieldType
getFormFieldType(PDFiumDocument
* pDoc
) override
;
331 float getFontSize(PDFiumDocument
* pDoc
) override
;
332 Color
getFontColor(PDFiumDocument
* pDoc
) override
;
333 OUString
getFormFieldAlternateName(PDFiumDocument
* pDoc
) override
;
334 int getFormFieldFlags(PDFiumDocument
* pDoc
) override
;
335 OUString
getFormAdditionalActionJavaScript(PDFiumDocument
* pDoc
,
336 PDFAnnotAActionType eEvent
) override
;
337 OUString
getFormFieldValue(PDFiumDocument
* pDoc
) override
;
338 int getOptionCount(PDFiumDocument
* pDoc
) override
;
341 class PDFiumPageObjectImpl final
: public PDFiumPageObject
344 FPDF_PAGEOBJECT mpPageObject
;
346 PDFiumPageObjectImpl(const PDFiumPageObjectImpl
&) = delete;
347 PDFiumPageObjectImpl
& operator=(const PDFiumPageObjectImpl
&) = delete;
350 PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject
);
352 PDFPageObjectType
getType() override
;
353 OUString
getText(std::unique_ptr
<PDFiumTextPage
> const& pTextPage
) override
;
355 int getFormObjectCount() override
;
356 std::unique_ptr
<PDFiumPageObject
> getFormObject(int nIndex
) override
;
358 basegfx::B2DHomMatrix
getMatrix() override
;
359 basegfx::B2DRectangle
getBounds() override
;
360 double getFontSize() override
;
361 OUString
getFontName() override
;
362 PDFTextRenderMode
getTextRenderMode() override
;
363 Color
getFillColor() override
;
364 Color
getStrokeColor() override
;
365 double getStrokeWidth() override
;
367 int getPathSegmentCount() override
;
368 std::unique_ptr
<PDFiumPathSegment
> getPathSegment(int index
) override
;
369 Size
getImageSize(PDFiumPage
& rPage
) override
;
370 std::unique_ptr
<PDFiumBitmap
> getImageBitmap() override
;
371 bool getDrawMode(PDFFillMode
& eFillMode
, bool& bStroke
) override
;
374 class PDFiumSearchHandleImpl final
: public PDFiumSearchHandle
377 FPDF_SCHHANDLE mpSearchHandle
;
379 PDFiumSearchHandleImpl(const PDFiumSearchHandleImpl
&) = delete;
380 PDFiumSearchHandleImpl
& operator=(const PDFiumSearchHandleImpl
&) = delete;
383 PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle
);
384 ~PDFiumSearchHandleImpl();
386 bool findNext() override
;
387 bool findPrev() override
;
388 int getSearchResultIndex() override
;
389 int getSearchCount() override
;
392 class PDFiumTextPageImpl final
: public PDFiumTextPage
395 FPDF_TEXTPAGE mpTextPage
;
397 PDFiumTextPageImpl(const PDFiumTextPageImpl
&) = delete;
398 PDFiumTextPageImpl
& operator=(const PDFiumTextPageImpl
&) = delete;
401 PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage
);
402 ~PDFiumTextPageImpl();
404 FPDF_TEXTPAGE
getPointer() { return mpTextPage
; }
406 int countChars() override
;
407 unsigned int getUnicode(int index
) override
;
408 std::unique_ptr
<PDFiumSearchHandle
> findStart(const OUString
& rFindWhat
, PDFFindFlags nFlags
,
409 sal_Int32 nStartIndex
) override
;
411 /// Returned rect is no longer upside down and is in mm100.
412 basegfx::B2DRectangle
getCharBox(int nIndex
, double fPageHeight
) override
;
415 class PDFiumSignatureImpl final
: public PDFiumSignature
418 FPDF_SIGNATURE mpSignature
;
419 PDFiumSignatureImpl(const PDFiumSignatureImpl
&) = delete;
420 PDFiumSignatureImpl
& operator=(const PDFiumSignatureImpl
&) = delete;
423 PDFiumSignatureImpl(FPDF_SIGNATURE pSignature
);
425 std::vector
<int> getByteRange() override
;
426 int getDocMDPPermission() override
;
427 std::vector
<unsigned char> getContents() override
;
428 OString
getSubFilter() override
;
429 OUString
getReason() override
;
430 css::util::DateTime
getTime() override
;
433 class PDFiumPageImpl final
: public PDFiumPage
439 PDFiumPageImpl(const PDFiumPageImpl
&) = delete;
440 PDFiumPageImpl
& operator=(const PDFiumPageImpl
&) = delete;
443 PDFiumPageImpl(FPDF_PAGE pPage
)
448 ~PDFiumPageImpl() override
451 FPDF_ClosePage(mpPage
);
454 FPDF_PAGE
getPointer() { return mpPage
; }
456 int getObjectCount() override
;
457 std::unique_ptr
<PDFiumPageObject
> getObject(int nIndex
) override
;
459 int getAnnotationCount() override
;
460 int getAnnotationIndex(std::unique_ptr
<PDFiumAnnotation
> const& rAnnotation
) override
;
462 std::unique_ptr
<PDFiumAnnotation
> getAnnotation(int nIndex
) override
;
464 std::unique_ptr
<PDFiumTextPage
> getTextPage() override
;
466 BitmapChecksum
getChecksum(int nMDPPerm
) override
;
468 double getWidth() override
;
469 double getHeight() override
;
471 bool hasTransparency() override
;
473 bool hasLinks() override
;
475 void onAfterLoadPage(PDFiumDocument
* pDoc
) override
;
478 /// Wrapper around FPDF_FORMHANDLE.
479 class PDFiumFormHandle final
482 FPDF_FORMHANDLE mpHandle
;
484 PDFiumFormHandle(const PDFiumFormHandle
&) = delete;
485 PDFiumFormHandle
& operator=(const PDFiumFormHandle
&) = delete;
488 PDFiumFormHandle(FPDF_FORMHANDLE pHandle
);
490 FPDF_FORMHANDLE
getPointer();
493 class PDFiumAttachmentImpl final
: public PDFiumAttachment
496 FPDF_ATTACHMENT mpAttachment
;
497 PDFiumAttachmentImpl(const PDFiumSignatureImpl
&) = delete;
498 PDFiumAttachmentImpl
& operator=(const PDFiumSignatureImpl
&) = delete;
501 PDFiumAttachmentImpl(FPDF_ATTACHMENT pAttachment
)
502 : mpAttachment(pAttachment
)
506 OUString
getName() override
;
507 bool getFile(std::vector
<unsigned char>& rOutBuffer
) override
;
510 class PDFiumDocumentImpl
: public PDFiumDocument
513 FPDF_DOCUMENT mpPdfDocument
;
514 FPDF_FORMFILLINFO m_aFormCallbacks
;
515 std::unique_ptr
<PDFiumFormHandle
> m_pFormHandle
;
518 PDFiumDocumentImpl(const PDFiumDocumentImpl
&) = delete;
519 PDFiumDocumentImpl
& operator=(const PDFiumDocumentImpl
&) = delete;
522 PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument
);
523 ~PDFiumDocumentImpl() override
;
524 FPDF_FORMHANDLE
getFormHandlePointer();
526 // Page size in points
527 basegfx::B2DSize
getPageSize(int nIndex
) override
;
528 int getPageCount() override
;
529 int getSignatureCount() override
;
530 int getAttachmentCount() override
;
531 int getFileVersion() override
;
532 bool saveWithVersion(SvMemoryStream
& rStream
, int nFileVersion
) override
;
534 std::unique_ptr
<PDFiumPage
> openPage(int nIndex
) override
;
535 std::unique_ptr
<PDFiumSignature
> getSignature(int nIndex
) override
;
536 std::unique_ptr
<PDFiumAttachment
> getAttachment(int nIndex
) override
;
537 std::vector
<unsigned int> getTrailerEnds() override
;
538 OUString
getBookmarks() override
;
541 class PDFiumImpl
: public PDFium
544 PDFiumImpl(const PDFiumImpl
&) = delete;
545 PDFiumImpl
& operator=(const PDFiumImpl
&) = delete;
547 OUString maLastError
;
548 void setLastError(OUString
const& rErrorString
);
552 ~PDFiumImpl() override
;
554 const OUString
& getLastError() const override
{ return maLastError
; }
556 std::unique_ptr
<PDFiumDocument
> openDocument(const void* pData
, int nSize
,
557 const OString
& rPassword
) override
;
558 PDFErrorType
getLastErrorCode() override
;
559 /// @brief creates bitmap, can reduce size if needed, check nWidth and nHeight
560 std::unique_ptr
<PDFiumBitmap
> createBitmap(int& nWidth
, int& nHeight
, int nAlpha
) override
;
564 PDFiumImpl::PDFiumImpl()
566 FPDF_LIBRARY_CONFIG aConfig
;
568 aConfig
.m_pUserFontPaths
= nullptr;
569 aConfig
.m_pIsolate
= nullptr;
570 aConfig
.m_v8EmbedderSlot
= 0;
571 FPDF_InitLibraryWithConfig(&aConfig
);
574 PDFiumImpl::~PDFiumImpl() { FPDF_DestroyLibrary(); }
576 void PDFiumImpl::setLastError(OUString
const& rErrorString
)
578 if (!rErrorString
.isEmpty())
580 // Report what error was set (useful in test failures)
581 SAL_WARN("vcl.filter", "PDFiumImpl Error: '" << rErrorString
<< "' Error number: "
582 << sal_Int32(getLastErrorCode()));
584 maLastError
= rErrorString
;
587 std::unique_ptr
<PDFiumDocument
> PDFiumImpl::openDocument(const void* pData
, int nSize
,
588 const OString
& rPassword
)
590 setLastError(u
""_ustr
);
591 std::unique_ptr
<PDFiumDocument
> pPDFiumDocument
;
593 FPDF_BYTESTRING pPassword
= nullptr;
594 if (!rPassword
.isEmpty())
596 pPassword
= rPassword
.getStr();
598 FPDF_DOCUMENT pDocument
= FPDF_LoadMemDocument(pData
, nSize
, pPassword
);
602 switch (FPDF_GetLastError())
604 case FPDF_ERR_SUCCESS
:
605 setLastError(u
"Success"_ustr
);
607 case FPDF_ERR_UNKNOWN
:
608 setLastError(u
"Unknown error"_ustr
);
611 setLastError(u
"File not found"_ustr
);
613 case FPDF_ERR_FORMAT
:
614 setLastError(u
"Input is not a PDF format"_ustr
);
616 case FPDF_ERR_PASSWORD
:
617 setLastError(u
"Incorrect password or password is required"_ustr
);
619 case FPDF_ERR_SECURITY
:
620 setLastError(u
"Security error"_ustr
);
623 setLastError(u
"Content error"_ustr
);
626 setLastError(u
"Unknown error number"_ustr
);
632 pPDFiumDocument
= std::make_unique
<PDFiumDocumentImpl
>(pDocument
);
635 return pPDFiumDocument
;
638 PDFErrorType
PDFiumImpl::getLastErrorCode()
640 return static_cast<PDFErrorType
>(FPDF_GetLastError());
643 std::unique_ptr
<PDFiumBitmap
> PDFiumImpl::createBitmap(int& nWidth
, int& nHeight
, int nAlpha
)
645 std::unique_ptr
<PDFiumBitmap
> pPDFiumBitmap
;
647 FPDF_BITMAP pPdfBitmap
= FPDFBitmap_Create(nWidth
, nHeight
, nAlpha
);
650 int nOriginal
= nHeight
;
651 // PDFium cannot create big bitmaps, max 2^14 x 2^14 x 4 bytes per pixel
657 nWidth
= 16384.0 / nOriginal
* nWidth
;
660 if (nWidth
* nHeight
> 16384 * 16384)
663 nHeight
= 16384.0 / nOriginal
* nHeight
;
666 pPdfBitmap
= FPDFBitmap_Create(nWidth
, nHeight
, nAlpha
);
671 setLastError(u
"Failed to create bitmap"_ustr
);
675 pPDFiumBitmap
= std::make_unique
<PDFiumBitmapImpl
>(pPdfBitmap
);
677 return pPDFiumBitmap
;
680 PDFiumSignatureImpl::PDFiumSignatureImpl(FPDF_SIGNATURE pSignature
)
681 : mpSignature(pSignature
)
685 std::vector
<int> PDFiumSignatureImpl::getByteRange()
687 int nByteRangeLen
= FPDFSignatureObj_GetByteRange(mpSignature
, nullptr, 0);
688 std::vector
<int> aByteRange(nByteRangeLen
);
689 if (nByteRangeLen
<= 0)
694 FPDFSignatureObj_GetByteRange(mpSignature
, aByteRange
.data(), aByteRange
.size());
698 int PDFiumSignatureImpl::getDocMDPPermission()
700 return FPDFSignatureObj_GetDocMDPPermission(mpSignature
);
703 std::vector
<unsigned char> PDFiumSignatureImpl::getContents()
705 int nContentsLen
= FPDFSignatureObj_GetContents(mpSignature
, nullptr, 0);
706 std::vector
<unsigned char> aContents(nContentsLen
);
707 if (aContents
.empty())
712 FPDFSignatureObj_GetContents(mpSignature
, aContents
.data(), aContents
.size());
716 OString
PDFiumSignatureImpl::getSubFilter()
718 int nSubFilterLen
= FPDFSignatureObj_GetSubFilter(mpSignature
, nullptr, 0);
719 std::vector
<char> aSubFilterBuf(nSubFilterLen
);
720 FPDFSignatureObj_GetSubFilter(mpSignature
, aSubFilterBuf
.data(), aSubFilterBuf
.size());
721 // Buffer is NUL-terminated.
722 OString
aSubFilter(aSubFilterBuf
.data(), aSubFilterBuf
.size() - 1);
726 OUString
PDFiumSignatureImpl::getReason()
728 int nReasonLen
= FPDFSignatureObj_GetReason(mpSignature
, nullptr, 0);
732 std::vector
<char16_t
> aReasonBuf(nReasonLen
);
733 FPDFSignatureObj_GetReason(mpSignature
, aReasonBuf
.data(), aReasonBuf
.size());
734 aRet
= OUString(aReasonBuf
.data(), aReasonBuf
.size() - 1);
740 util::DateTime
PDFiumSignatureImpl::getTime()
743 int nTimeLen
= FPDFSignatureObj_GetTime(mpSignature
, nullptr, 0);
749 // Example: "D:20161027100104".
750 std::vector
<char> aTimeBuf(nTimeLen
);
751 FPDFSignatureObj_GetTime(mpSignature
, aTimeBuf
.data(), aTimeBuf
.size());
752 OString
aM(aTimeBuf
.data(), aTimeBuf
.size() - 1);
753 if (aM
.startsWith("D:") && aM
.getLength() >= 16)
755 aRet
.Year
= o3tl::toInt32(aM
.subView(2, 4));
756 aRet
.Month
= o3tl::toInt32(aM
.subView(6, 2));
757 aRet
.Day
= o3tl::toInt32(aM
.subView(8, 2));
758 aRet
.Hours
= o3tl::toInt32(aM
.subView(10, 2));
759 aRet
.Minutes
= o3tl::toInt32(aM
.subView(12, 2));
760 aRet
.Seconds
= o3tl::toInt32(aM
.subView(14, 2));
765 OUString
PDFiumAttachmentImpl::getName()
767 return getUnicodeString([this](FPDF_WCHAR
* buffer
, unsigned long length
) {
768 return FPDFAttachment_GetName(mpAttachment
, buffer
, length
);
772 bool PDFiumAttachmentImpl::getFile(std::vector
<unsigned char>& rOutBuffer
)
776 unsigned long nLength
{};
777 if (!FPDFAttachment_GetFile(mpAttachment
, nullptr, 0, &nLength
))
780 rOutBuffer
.resize(nLength
);
781 unsigned long nActualLength
{};
782 if (!FPDFAttachment_GetFile(mpAttachment
, rOutBuffer
.data(), nLength
, &nActualLength
))
784 rOutBuffer
.resize(nActualLength
);
788 PDFiumDocumentImpl::PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument
)
789 : mpPdfDocument(pPdfDocument
)
792 m_aFormCallbacks
.version
= 1;
793 m_pFormHandle
= std::make_unique
<PDFiumFormHandle
>(
794 FPDFDOC_InitFormFillEnvironment(pPdfDocument
, &m_aFormCallbacks
));
797 PDFiumDocumentImpl::~PDFiumDocumentImpl()
799 m_pFormHandle
.reset();
801 FPDF_CloseDocument(mpPdfDocument
);
804 FPDF_FORMHANDLE
PDFiumDocumentImpl::getFormHandlePointer() { return m_pFormHandle
->getPointer(); }
806 std::unique_ptr
<PDFiumPage
> PDFiumDocumentImpl::openPage(int nIndex
)
808 std::unique_ptr
<PDFiumPage
> pPDFiumPage
;
809 FPDF_PAGE pPage
= FPDF_LoadPage(mpPdfDocument
, nIndex
);
812 pPDFiumPage
= std::make_unique
<PDFiumPageImpl
>(pPage
);
817 std::unique_ptr
<PDFiumSignature
> PDFiumDocumentImpl::getSignature(int nIndex
)
819 std::unique_ptr
<PDFiumSignature
> pPDFiumSignature
;
820 FPDF_SIGNATURE pSignature
= FPDF_GetSignatureObject(mpPdfDocument
, nIndex
);
823 pPDFiumSignature
= std::make_unique
<PDFiumSignatureImpl
>(pSignature
);
825 return pPDFiumSignature
;
828 std::unique_ptr
<PDFiumAttachment
> PDFiumDocumentImpl::getAttachment(int nIndex
)
830 std::unique_ptr
<PDFiumAttachment
> pPDFiumAttachment
;
831 FPDF_ATTACHMENT pAttachment
= FPDFDoc_GetAttachment(mpPdfDocument
, nIndex
);
834 pPDFiumAttachment
= std::make_unique
<PDFiumAttachmentImpl
>(pAttachment
);
836 return pPDFiumAttachment
;
839 std::vector
<unsigned int> PDFiumDocumentImpl::getTrailerEnds()
841 int nNumTrailers
= FPDF_GetTrailerEnds(mpPdfDocument
, nullptr, 0);
842 std::vector
<unsigned int> aTrailerEnds(nNumTrailers
);
843 FPDF_GetTrailerEnds(mpPdfDocument
, aTrailerEnds
.data(), aTrailerEnds
.size());
847 static void lcl_getBookmarks(int nLevel
, OUStringBuffer
& rBuf
, FPDF_DOCUMENT pDoc
,
848 FPDF_BOOKMARK pBookmark
)
850 // no first child or too much levels
851 if (!pBookmark
|| nLevel
> 10)
855 int nBytes
= FPDFBookmark_GetTitle(pBookmark
, nullptr, 0);
856 assert(nBytes
% 2 == 0);
859 std::unique_ptr
<sal_Unicode
[]> pText(new sal_Unicode
[nBytes
]);
861 int nActualBytes
= FPDFBookmark_GetTitle(pBookmark
, pText
.get(), nBytes
* 2);
862 assert(nActualBytes
% 2 == 0);
864 if (nActualBytes
> 1)
866 #if defined OSL_BIGENDIAN
867 // The data returned by FPDFTextObj_GetText is documented to always be UTF-16LE:
868 for (int i
= 0; i
!= nActualBytes
; ++i
)
870 pText
[i
] = OSL_SWAPWORD(pText
[i
]);
873 // insert nLevel spaces before the title
874 rBuf
.append(OUString(" ").subView(0, nLevel
));
875 aString
= OUString(pText
.get());
878 rBuf
.append(aString
);
882 lcl_getBookmarks(nLevel
+ 1, rBuf
, pDoc
, FPDFBookmark_GetFirstChild(pDoc
, pBookmark
));
885 while (nullptr != (pBookmark
= FPDFBookmark_GetNextSibling(pDoc
, pBookmark
)))
886 lcl_getBookmarks(nLevel
, rBuf
, pDoc
, pBookmark
);
889 OUString
PDFiumDocumentImpl::getBookmarks()
892 FPDF_BOOKMARK pBookmark
= FPDFBookmark_GetFirstChild(mpPdfDocument
, nullptr);
893 lcl_getBookmarks(0, aBuf
, mpPdfDocument
, pBookmark
);
894 return aBuf
.makeStringAndClear();
897 basegfx::B2DSize
PDFiumDocumentImpl::getPageSize(int nIndex
)
899 basegfx::B2DSize aSize
;
901 if (FPDF_GetPageSizeByIndexF(mpPdfDocument
, nIndex
, &aPDFSize
))
903 aSize
= basegfx::B2DSize(aPDFSize
.width
, aPDFSize
.height
);
908 int PDFiumDocumentImpl::getPageCount() { return FPDF_GetPageCount(mpPdfDocument
); }
910 int PDFiumDocumentImpl::getSignatureCount() { return FPDF_GetSignatureCount(mpPdfDocument
); }
912 int PDFiumDocumentImpl::getAttachmentCount() { return FPDFDoc_GetAttachmentCount(mpPdfDocument
); }
914 int PDFiumDocumentImpl::getFileVersion()
916 int nFileVersion
= 0;
917 FPDF_GetFileVersion(mpPdfDocument
, &nFileVersion
);
921 bool PDFiumDocumentImpl::saveWithVersion(SvMemoryStream
& rStream
, int nFileVersion
)
923 CompatibleWriter
aWriter(rStream
);
925 aWriter
.WriteBlock
= &CompatibleWriterCallback
;
926 if (!FPDF_SaveWithVersion(mpPdfDocument
, &aWriter
, 0, nFileVersion
))
934 int PDFiumPageImpl::getObjectCount() { return FPDFPage_CountObjects(mpPage
); }
936 std::unique_ptr
<PDFiumPageObject
> PDFiumPageImpl::getObject(int nIndex
)
938 std::unique_ptr
<PDFiumPageObject
> pPDFiumPageObject
;
939 FPDF_PAGEOBJECT pPageObject
= FPDFPage_GetObject(mpPage
, nIndex
);
942 pPDFiumPageObject
= std::make_unique
<PDFiumPageObjectImpl
>(pPageObject
);
944 return pPDFiumPageObject
;
947 int PDFiumPageImpl::getAnnotationCount() { return FPDFPage_GetAnnotCount(mpPage
); }
949 int PDFiumPageImpl::getAnnotationIndex(std::unique_ptr
<PDFiumAnnotation
> const& rAnnotation
)
951 auto pAnnotation
= static_cast<PDFiumAnnotationImpl
*>(rAnnotation
.get());
952 return FPDFPage_GetAnnotIndex(mpPage
, pAnnotation
->getPointer());
955 std::unique_ptr
<PDFiumAnnotation
> PDFiumPageImpl::getAnnotation(int nIndex
)
957 std::unique_ptr
<PDFiumAnnotation
> pPDFiumAnnotation
;
958 FPDF_ANNOTATION pAnnotation
= FPDFPage_GetAnnot(mpPage
, nIndex
);
961 pPDFiumAnnotation
= std::make_unique
<PDFiumAnnotationImpl
>(pAnnotation
);
963 return pPDFiumAnnotation
;
966 std::unique_ptr
<PDFiumTextPage
> PDFiumPageImpl::getTextPage()
968 std::unique_ptr
<PDFiumTextPage
> pPDFiumTextPage
;
969 FPDF_TEXTPAGE pTextPage
= FPDFText_LoadPage(mpPage
);
972 pPDFiumTextPage
= std::make_unique
<PDFiumTextPageImpl
>(pTextPage
);
974 return pPDFiumTextPage
;
977 bool PDFiumPageImpl::hasLinks()
979 // This could be a full iterator, but at the moment we just determine if the list is empty or
982 FPDF_LINK pLinkAnnot
= nullptr;
983 return FPDFLink_Enumerate(mpPage
, &nStartPos
, &pLinkAnnot
);
986 void PDFiumPageImpl::onAfterLoadPage(PDFiumDocument
* pDoc
)
988 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
989 FORM_OnAfterLoadPage(mpPage
, pDocImpl
->getFormHandlePointer());
992 PDFiumPageObjectImpl::PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject
)
993 : mpPageObject(pPageObject
)
997 OUString
PDFiumPageObjectImpl::getText(std::unique_ptr
<PDFiumTextPage
> const& rTextPage
)
999 auto pTextPage
= static_cast<PDFiumTextPageImpl
*>(rTextPage
.get());
1000 return getUnicodeString([this, pTextPage
](FPDF_WCHAR
* buffer
, unsigned long length
) {
1001 return FPDFTextObj_GetText(mpPageObject
, pTextPage
->getPointer(), buffer
, length
);
1005 PDFPageObjectType
PDFiumPageObjectImpl::getType()
1007 return static_cast<PDFPageObjectType
>(FPDFPageObj_GetType(mpPageObject
));
1010 int PDFiumPageObjectImpl::getFormObjectCount() { return FPDFFormObj_CountObjects(mpPageObject
); }
1012 std::unique_ptr
<PDFiumPageObject
> PDFiumPageObjectImpl::getFormObject(int nIndex
)
1014 std::unique_ptr
<PDFiumPageObject
> pPDFiumFormObject
;
1015 FPDF_PAGEOBJECT pFormObject
= FPDFFormObj_GetObject(mpPageObject
, nIndex
);
1018 pPDFiumFormObject
= std::make_unique
<PDFiumPageObjectImpl
>(pFormObject
);
1020 return pPDFiumFormObject
;
1023 basegfx::B2DHomMatrix
PDFiumPageObjectImpl::getMatrix()
1025 basegfx::B2DHomMatrix aB2DMatrix
;
1027 if (FPDFPageObj_GetMatrix(mpPageObject
, &matrix
))
1028 aB2DMatrix
= basegfx::B2DHomMatrix::abcdef(matrix
.a
, matrix
.b
, matrix
.c
, matrix
.d
, matrix
.e
,
1033 basegfx::B2DRectangle
PDFiumPageObjectImpl::getBounds()
1035 basegfx::B2DRectangle aB2DRectangle
;
1041 if (FPDFPageObj_GetBounds(mpPageObject
, &left
, &bottom
, &right
, &top
))
1043 aB2DRectangle
= basegfx::B2DRectangle(left
, top
, right
, bottom
);
1045 return aB2DRectangle
;
1048 double PDFiumPageObjectImpl::getFontSize()
1051 FPDFTextObj_GetFontSize(mpPageObject
, &nSize
);
1055 OUString
PDFiumPageObjectImpl::getFontName()
1057 OUString sFamilyName
;
1058 const int nFamilyName
= 80 + 1;
1059 std::unique_ptr
<char[]> pFamilyName(new char[nFamilyName
]); // + terminating null
1060 FPDF_FONT pFontObject
= FPDFTextObj_GetFont(mpPageObject
);
1061 int nFamilyNameChars
= FPDFFont_GetFamilyName(pFontObject
, pFamilyName
.get(), nFamilyName
);
1062 if (nFamilyName
>= nFamilyNameChars
)
1064 sFamilyName
= OUString::createFromAscii(pFamilyName
.get());
1069 PDFTextRenderMode
PDFiumPageObjectImpl::getTextRenderMode()
1071 return static_cast<PDFTextRenderMode
>(FPDFTextObj_GetTextRenderMode(mpPageObject
));
1074 Color
PDFiumPageObjectImpl::getFillColor()
1076 Color aColor
= COL_TRANSPARENT
;
1077 unsigned int nR
, nG
, nB
, nA
;
1078 if (FPDFPageObj_GetFillColor(mpPageObject
, &nR
, &nG
, &nB
, &nA
))
1080 aColor
= Color(ColorAlpha
, nA
, nR
, nG
, nB
);
1085 Color
PDFiumPageObjectImpl::getStrokeColor()
1087 Color aColor
= COL_TRANSPARENT
;
1088 unsigned int nR
, nG
, nB
, nA
;
1089 if (FPDFPageObj_GetStrokeColor(mpPageObject
, &nR
, &nG
, &nB
, &nA
))
1091 aColor
= Color(ColorAlpha
, nA
, nR
, nG
, nB
);
1096 double PDFiumPageObjectImpl::getStrokeWidth()
1099 FPDFPageObj_GetStrokeWidth(mpPageObject
, &fWidth
);
1103 int PDFiumPageObjectImpl::getPathSegmentCount() { return FPDFPath_CountSegments(mpPageObject
); }
1105 std::unique_ptr
<PDFiumPathSegment
> PDFiumPageObjectImpl::getPathSegment(int index
)
1107 std::unique_ptr
<PDFiumPathSegment
> pPDFiumPathSegment
;
1108 FPDF_PATHSEGMENT pPathSegment
= FPDFPath_GetPathSegment(mpPageObject
, index
);
1111 pPDFiumPathSegment
= std::make_unique
<PDFiumPathSegmentImpl
>(pPathSegment
);
1113 return pPDFiumPathSegment
;
1116 Size
PDFiumPageObjectImpl::getImageSize(PDFiumPage
& rPage
)
1118 FPDF_IMAGEOBJ_METADATA aMeta
;
1119 auto& rPageImpl
= static_cast<PDFiumPageImpl
&>(rPage
);
1120 FPDFImageObj_GetImageMetadata(mpPageObject
, rPageImpl
.getPointer(), &aMeta
);
1121 return Size(aMeta
.width
, aMeta
.height
);
1124 std::unique_ptr
<PDFiumBitmap
> PDFiumPageObjectImpl::getImageBitmap()
1126 std::unique_ptr
<PDFiumBitmap
> pPDFiumBitmap
;
1127 FPDF_BITMAP pBitmap
= FPDFImageObj_GetBitmap(mpPageObject
);
1130 pPDFiumBitmap
= std::make_unique
<PDFiumBitmapImpl
>(pBitmap
);
1132 return pPDFiumBitmap
;
1135 bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode
& rFillMode
, bool& rStroke
)
1137 auto nFillMode
= static_cast<int>(rFillMode
);
1138 auto bStroke
= static_cast<FPDF_BOOL
>(rStroke
);
1139 bool bRet
= FPDFPath_GetDrawMode(mpPageObject
, &nFillMode
, &bStroke
);
1140 rFillMode
= static_cast<PDFFillMode
>(nFillMode
);
1141 rStroke
= static_cast<bool>(bStroke
);
1145 BitmapChecksum
PDFiumPageImpl::getChecksum(int nMDPPerm
)
1147 int nPageWidth
= getWidth();
1148 int nPageHeight
= getHeight();
1149 std::unique_ptr
<PDFiumBitmap
> pPdfBitmap
1150 = PDFiumLibrary::get()->createBitmap(nPageWidth
, nPageHeight
, /*nAlpha=*/1);
1154 PDFiumBitmapImpl
* pBitmapImpl
= static_cast<PDFiumBitmapImpl
*>(pPdfBitmap
.get());
1159 // Annotations/commenting should affect the checksum, signature verification wants this.
1160 nFlags
= FPDF_ANNOT
;
1162 FPDF_RenderPageBitmap(pBitmapImpl
->getPointer(), mpPage
, /*start_x=*/0, /*start_y=*/0,
1163 nPageWidth
, nPageHeight
,
1164 /*rotate=*/0, nFlags
);
1165 Bitmap
aBitmap(Size(nPageWidth
, nPageHeight
), vcl::PixelFormat::N24_BPP
);
1167 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
1168 const auto pPdfBuffer
1169 = static_cast<ConstScanline
>(FPDFBitmap_GetBuffer(pBitmapImpl
->getPointer()));
1170 const int nStride
= FPDFBitmap_GetStride(pBitmapImpl
->getPointer());
1171 for (int nRow
= 0; nRow
< nPageHeight
; ++nRow
)
1173 ConstScanline pPdfLine
= pPdfBuffer
+ (nStride
* nRow
);
1174 pWriteAccess
->CopyScanline(nRow
, pPdfLine
, ScanlineFormat::N32BitTcBgra
, nStride
);
1177 return aBitmap
.GetChecksum();
1180 double PDFiumPageImpl::getWidth() { return FPDF_GetPageWidth(mpPage
); }
1182 double PDFiumPageImpl::getHeight() { return FPDF_GetPageHeight(mpPage
); }
1184 bool PDFiumPageImpl::hasTransparency() { return FPDFPage_HasTransparency(mpPage
); }
1186 PDFiumPathSegmentImpl::PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment
)
1187 : mpPathSegment(pPathSegment
)
1191 basegfx::B2DPoint
PDFiumPathSegmentImpl::getPoint() const
1193 basegfx::B2DPoint aPoint
;
1195 if (FPDFPathSegment_GetPoint(mpPathSegment
, &fx
, &fy
))
1196 aPoint
= basegfx::B2DPoint(fx
, fy
);
1200 bool PDFiumPathSegmentImpl::isClosed() const { return FPDFPathSegment_GetClose(mpPathSegment
); }
1202 PDFSegmentType
PDFiumPathSegmentImpl::getType() const
1204 return static_cast<PDFSegmentType
>(FPDFPathSegment_GetType(mpPathSegment
));
1207 PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle
)
1212 PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle
); }
1214 FPDF_FORMHANDLE
PDFiumFormHandle::getPointer() { return mpHandle
; }
1216 PDFiumBitmapImpl::PDFiumBitmapImpl(FPDF_BITMAP pBitmap
)
1221 PDFiumBitmapImpl::~PDFiumBitmapImpl()
1225 FPDFBitmap_Destroy(mpBitmap
);
1229 void PDFiumBitmapImpl::fillRect(int left
, int top
, int width
, int height
, sal_uInt32 nColor
)
1231 FPDFBitmap_FillRect(mpBitmap
, left
, top
, width
, height
, nColor
);
1234 void PDFiumBitmapImpl::renderPageBitmap(PDFiumDocument
* pDoc
, PDFiumPage
* pPage
, int nStartX
,
1235 int nStartY
, int nSizeX
, int nSizeY
)
1237 auto pPageImpl
= static_cast<PDFiumPageImpl
*>(pPage
);
1238 FPDF_RenderPageBitmap(mpBitmap
, pPageImpl
->getPointer(), nStartX
, nStartY
, nSizeX
, nSizeY
,
1239 /*rotate=*/0, /*flags=*/0);
1241 // Render widget annotations for FormFields.
1242 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1243 FPDF_FFLDraw(pDocImpl
->getFormHandlePointer(), mpBitmap
, pPageImpl
->getPointer(), nStartX
,
1244 nStartY
, nSizeX
, nSizeY
, /*rotate=*/0, /*flags=*/0);
1247 ConstScanline
PDFiumBitmapImpl::getBuffer()
1249 return static_cast<ConstScanline
>(FPDFBitmap_GetBuffer(mpBitmap
));
1252 int PDFiumBitmapImpl::getStride() { return FPDFBitmap_GetStride(mpBitmap
); }
1254 int PDFiumBitmapImpl::getWidth() { return FPDFBitmap_GetWidth(mpBitmap
); }
1256 int PDFiumBitmapImpl::getHeight() { return FPDFBitmap_GetHeight(mpBitmap
); }
1258 PDFBitmapType
PDFiumBitmapImpl::getFormat()
1260 return static_cast<PDFBitmapType
>(FPDFBitmap_GetFormat(mpBitmap
));
1263 BitmapEx
PDFiumBitmapImpl::createBitmapFromBuffer()
1267 const vcl::pdf::PDFBitmapType eFormat
= getFormat();
1268 if (eFormat
== vcl::pdf::PDFBitmapType::Unknown
)
1271 const int nWidth
= getWidth();
1272 const int nHeight
= getHeight();
1273 const int nStride
= getStride();
1277 case vcl::pdf::PDFBitmapType::BGR
:
1279 aBitmapEx
= BitmapEx(Size(nWidth
, nHeight
), vcl::PixelFormat::N24_BPP
);
1280 ReadRawDIB(aBitmapEx
, getBuffer(), ScanlineFormat::N24BitTcBgr
, nHeight
, nStride
);
1284 case vcl::pdf::PDFBitmapType::BGRx
:
1286 aBitmapEx
= BitmapEx(Size(nWidth
, nHeight
), vcl::PixelFormat::N24_BPP
);
1287 ReadRawDIB(aBitmapEx
, getBuffer(), ScanlineFormat::N32BitTcRgba
, nHeight
, nStride
);
1291 case vcl::pdf::PDFBitmapType::BGRA
:
1293 Bitmap
aBitmap(Size(nWidth
, nHeight
), vcl::PixelFormat::N24_BPP
);
1294 AlphaMask
aMask(Size(nWidth
, nHeight
));
1296 BitmapScopedWriteAccess
pWriteAccess(aBitmap
);
1297 BitmapScopedWriteAccess
pMaskAccess(aMask
);
1298 ConstScanline pBuffer
= getBuffer();
1299 std::vector
<sal_uInt8
> aScanlineAlpha(nWidth
);
1300 for (int nRow
= 0; nRow
< nHeight
; ++nRow
)
1302 ConstScanline pLine
= pBuffer
+ (nStride
* nRow
);
1303 pWriteAccess
->CopyScanline(nRow
, pLine
, ScanlineFormat::N32BitTcBgra
, nStride
);
1304 for (int nCol
= 0; nCol
< nWidth
; ++nCol
)
1306 aScanlineAlpha
[nCol
] = pLine
[3];
1309 pMaskAccess
->CopyScanline(nRow
, aScanlineAlpha
.data(), ScanlineFormat::N8BitPal
,
1313 aBitmapEx
= BitmapEx(aBitmap
, aMask
);
1324 PDFiumAnnotationImpl::PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation
)
1325 : mpAnnotation(pAnnotation
)
1329 PDFiumAnnotationImpl::~PDFiumAnnotationImpl()
1332 FPDFPage_CloseAnnot(mpAnnotation
);
1335 PDFAnnotationSubType
PDFiumAnnotationImpl::getSubType()
1337 return PDFAnnotationSubType(FPDFAnnot_GetSubtype(mpAnnotation
));
1340 basegfx::B2DRectangle
PDFiumAnnotationImpl::getRectangle()
1342 basegfx::B2DRectangle aB2DRectangle
;
1344 if (FPDFAnnot_GetRect(mpAnnotation
, &aRect
))
1346 aB2DRectangle
= basegfx::B2DRectangle(aRect
.left
, aRect
.top
, aRect
.right
, aRect
.bottom
);
1348 return aB2DRectangle
;
1351 Color
PDFiumAnnotationImpl::getColor()
1353 unsigned int nR
, nG
, nB
, nA
;
1354 if (FPDFAnnot_GetColor(mpAnnotation
, FPDFANNOT_COLORTYPE_Color
, &nR
, &nG
, &nB
, &nA
))
1356 return Color(ColorAlpha
, nA
, nR
, nG
, nB
);
1358 // FPDFAnnot_GetColor can return false if there is an appearance stream
1359 // So we search for a color with getStrokeColor
1360 for (int i
= 0; i
< getObjectCount(); ++i
)
1362 if (getObject(i
)->getType() == PDFPageObjectType::Path
)
1363 return getObject(i
)->getStrokeColor();
1365 return COL_TRANSPARENT
;
1368 Color
PDFiumAnnotationImpl::getInteriorColor()
1370 unsigned int nR
, nG
, nB
, nA
;
1371 if (FPDFAnnot_GetColor(mpAnnotation
, FPDFANNOT_COLORTYPE_InteriorColor
, &nR
, &nG
, &nB
, &nA
))
1373 return Color(ColorAlpha
, nA
, nR
, nG
, nB
);
1375 // FPDFAnnot_GetColor can return false if there is an appearance stream
1376 // So we search for a color with getFillColor
1377 for (int i
= 0; i
< getObjectCount(); ++i
)
1379 if (getObject(i
)->getType() == PDFPageObjectType::Path
)
1380 return getObject(i
)->getFillColor();
1382 return COL_TRANSPARENT
;
1385 size_t PDFiumAnnotationImpl::getAttachmentPointsCount()
1387 return FPDFAnnot_CountAttachmentPoints(mpAnnotation
);
1390 std::vector
<basegfx::B2DPoint
> PDFiumAnnotationImpl::getAttachmentPoints(size_t nIndex
)
1392 std::vector
<basegfx::B2DPoint
> aQuads
;
1394 FS_QUADPOINTSF aQuadpoints
;
1395 if (FPDFAnnot_GetAttachmentPoints(mpAnnotation
, nIndex
, &aQuadpoints
))
1397 aQuads
.emplace_back(aQuadpoints
.x1
, aQuadpoints
.y1
);
1398 aQuads
.emplace_back(aQuadpoints
.x2
, aQuadpoints
.y2
);
1399 aQuads
.emplace_back(aQuadpoints
.x3
, aQuadpoints
.y3
);
1400 aQuads
.emplace_back(aQuadpoints
.x4
, aQuadpoints
.y4
);
1405 std::vector
<basegfx::B2DPoint
> PDFiumAnnotationImpl::getLineGeometry()
1407 std::vector
<basegfx::B2DPoint
> aLine
;
1410 if (FPDFAnnot_GetLine(mpAnnotation
, &aStart
, &aEnd
))
1412 aLine
.emplace_back(aStart
.x
, aStart
.y
);
1413 aLine
.emplace_back(aEnd
.x
, aEnd
.y
);
1418 PDFFormFieldType
PDFiumAnnotationImpl::getFormFieldType(PDFiumDocument
* pDoc
)
1420 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1421 return PDFFormFieldType(
1422 FPDFAnnot_GetFormFieldType(pDocImpl
->getFormHandlePointer(), mpAnnotation
));
1425 int PDFiumAnnotationImpl::getFormFieldFlags(PDFiumDocument
* pDoc
)
1427 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1428 return FPDFAnnot_GetFormFieldFlags(pDocImpl
->getFormHandlePointer(), mpAnnotation
);
1431 float PDFiumAnnotationImpl::getFontSize(PDFiumDocument
* pDoc
)
1433 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1435 if (!FPDFAnnot_GetFontSize(pDocImpl
->getFormHandlePointer(), mpAnnotation
, &fRet
))
1443 Color
PDFiumAnnotationImpl::getFontColor(PDFiumDocument
* pDoc
)
1445 auto pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1446 unsigned int nR
, nG
, nB
;
1447 if (!FPDFAnnot_GetFontColor(pDocImpl
->getFormHandlePointer(), mpAnnotation
, &nR
, &nG
, &nB
))
1452 return Color(nR
, nG
, nB
);
1455 OUString
PDFiumAnnotationImpl::getFormFieldAlternateName(PDFiumDocument
* pDoc
)
1457 auto* pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1458 return getUnicodeString([this, pDocImpl
](FPDF_WCHAR
* buffer
, unsigned long length
) {
1459 return FPDFAnnot_GetFormFieldAlternateName(pDocImpl
->getFormHandlePointer(), mpAnnotation
,
1464 OUString
PDFiumAnnotationImpl::getFormFieldValue(PDFiumDocument
* pDoc
)
1466 auto* pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1467 return getUnicodeString([this, pDocImpl
](FPDF_WCHAR
* buffer
, unsigned long length
) {
1468 return FPDFAnnot_GetFormFieldValue(pDocImpl
->getFormHandlePointer(), mpAnnotation
, buffer
,
1472 int PDFiumAnnotationImpl::getOptionCount(PDFiumDocument
* pDoc
)
1474 auto* pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1475 return FPDFAnnot_GetOptionCount(pDocImpl
->getFormHandlePointer(), mpAnnotation
);
1478 OUString
PDFiumAnnotationImpl::getFormAdditionalActionJavaScript(PDFiumDocument
* pDoc
,
1479 PDFAnnotAActionType eEvent
)
1481 auto* pDocImpl
= static_cast<PDFiumDocumentImpl
*>(pDoc
);
1482 return getUnicodeString([this, pDocImpl
, eEvent
](FPDF_WCHAR
* buffer
, unsigned long length
) {
1483 return FPDFAnnot_GetFormAdditionalActionJavaScript(pDocImpl
->getFormHandlePointer(),
1484 mpAnnotation
, static_cast<int>(eEvent
),
1491 bool getBorderProperties(FPDF_ANNOTATION mpAnnotation
, float& rHorizontalCornerRadius
,
1492 float& rVerticalCornerRadius
, float& rBorderWidth
)
1494 float fHoriRadius
= 0.0f
;
1495 float fVertRadius
= 0.0f
;
1496 float fWidth
= 0.0f
;
1498 if (!FPDFAnnot_GetBorder(mpAnnotation
, &fHoriRadius
, &fVertRadius
, &fWidth
))
1501 rHorizontalCornerRadius
= fHoriRadius
;
1502 rVerticalCornerRadius
= fVertRadius
;
1503 rBorderWidth
= fWidth
;
1508 float PDFiumAnnotationImpl::getBorderWidth()
1510 float fHorizontalCornerRadius
;
1511 float fVerticalCornerRadius
;
1514 if (!getBorderProperties(mpAnnotation
, fHorizontalCornerRadius
, fVerticalCornerRadius
,
1517 return fBorderWidth
;
1520 basegfx::B2DSize
PDFiumAnnotationImpl::getBorderCornerRadius()
1522 float fHorizontalCornerRadius
;
1523 float fVerticalCornerRadius
;
1526 if (!getBorderProperties(mpAnnotation
, fHorizontalCornerRadius
, fVerticalCornerRadius
,
1528 return basegfx::B2DSize(0.0, 0.0);
1529 return basegfx::B2DSize(fHorizontalCornerRadius
, fVerticalCornerRadius
);
1532 bool PDFiumAnnotationImpl::hasKey(OString
const& rKey
)
1534 return FPDFAnnot_HasKey(mpAnnotation
, rKey
.getStr());
1537 PDFObjectType
PDFiumAnnotationImpl::getValueType(OString
const& rKey
)
1539 return static_cast<PDFObjectType
>(FPDFAnnot_GetValueType(mpAnnotation
, rKey
.getStr()));
1542 OUString
PDFiumAnnotationImpl::getString(OString
const& rKey
)
1544 return getUnicodeString([this, rKey
](FPDF_WCHAR
* buffer
, unsigned long length
) {
1545 return FPDFAnnot_GetStringValue(mpAnnotation
, rKey
.getStr(), buffer
, length
);
1549 std::vector
<std::vector
<basegfx::B2DPoint
>> PDFiumAnnotationImpl::getInkStrokes()
1551 std::vector
<std::vector
<basegfx::B2DPoint
>> aB2DPointList
;
1552 int nInkStrokes
= FPDFAnnot_GetInkListCount(mpAnnotation
);
1553 for (int i
= 0; i
< nInkStrokes
; i
++)
1555 std::vector
<basegfx::B2DPoint
> aB2DPoints
;
1556 int nPoints
= FPDFAnnot_GetInkListPath(mpAnnotation
, i
, nullptr, 0);
1559 std::vector
<FS_POINTF
> aPoints(nPoints
);
1560 if (FPDFAnnot_GetInkListPath(mpAnnotation
, i
, aPoints
.data(), aPoints
.size()))
1562 for (auto const& rPoint
: aPoints
)
1564 aB2DPoints
.emplace_back(rPoint
.x
, rPoint
.y
);
1566 aB2DPointList
.push_back(aB2DPoints
);
1570 return aB2DPointList
;
1573 std::vector
<basegfx::B2DPoint
> PDFiumAnnotationImpl::getVertices()
1575 std::vector
<basegfx::B2DPoint
> aB2DPoints
;
1576 int nPoints
= FPDFAnnot_GetVertices(mpAnnotation
, nullptr, 0);
1579 std::vector
<FS_POINTF
> aPoints(nPoints
);
1580 if (FPDFAnnot_GetVertices(mpAnnotation
, aPoints
.data(), aPoints
.size()))
1582 for (auto const& rPoint
: aPoints
)
1583 aB2DPoints
.emplace_back(rPoint
.x
, rPoint
.y
);
1589 std::unique_ptr
<PDFiumAnnotation
> PDFiumAnnotationImpl::getLinked(OString
const& rKey
)
1591 std::unique_ptr
<PDFiumAnnotation
> pPDFiumAnnotation
;
1592 FPDF_ANNOTATION pAnnotation
= FPDFAnnot_GetLinkedAnnot(mpAnnotation
, rKey
.getStr());
1595 pPDFiumAnnotation
= std::make_unique
<PDFiumAnnotationImpl
>(pAnnotation
);
1597 return pPDFiumAnnotation
;
1600 int PDFiumAnnotationImpl::getObjectCount() { return FPDFAnnot_GetObjectCount(mpAnnotation
); }
1602 std::unique_ptr
<PDFiumPageObject
> PDFiumAnnotationImpl::getObject(int nIndex
)
1604 std::unique_ptr
<PDFiumPageObject
> pPDFiumPageObject
;
1605 FPDF_PAGEOBJECT pPageObject
= FPDFAnnot_GetObject(mpAnnotation
, nIndex
);
1608 pPDFiumPageObject
= std::make_unique
<PDFiumPageObjectImpl
>(pPageObject
);
1610 return pPDFiumPageObject
;
1613 PDFiumTextPageImpl::PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage
)
1614 : mpTextPage(pTextPage
)
1618 PDFiumTextPageImpl::~PDFiumTextPageImpl()
1621 FPDFText_ClosePage(mpTextPage
);
1624 int PDFiumTextPageImpl::countChars() { return FPDFText_CountChars(mpTextPage
); }
1626 basegfx::B2DRectangle
PDFiumTextPageImpl::getCharBox(int nIndex
, double fPageHeight
)
1630 double bottom
= 0.0;
1633 if (FPDFText_GetCharBox(mpTextPage
, nIndex
, &left
, &right
, &bottom
, &top
))
1635 left
= convertPointToMm100(left
);
1636 right
= convertPointToMm100(right
);
1637 top
= fPageHeight
- convertPointToMm100(top
);
1638 bottom
= fPageHeight
- convertPointToMm100(bottom
);
1640 return basegfx::B2DRectangle(left
, bottom
, right
, top
);
1643 return basegfx::B2DRectangle();
1646 unsigned int PDFiumTextPageImpl::getUnicode(int index
)
1648 return FPDFText_GetUnicode(mpTextPage
, index
);
1651 std::unique_ptr
<PDFiumSearchHandle
>
1652 PDFiumTextPageImpl::findStart(const OUString
& rFindWhat
, PDFFindFlags nFlags
, sal_Int32 nStartIndex
)
1654 FPDF_WIDESTRING pFindWhat
= reinterpret_cast<FPDF_WIDESTRING
>(rFindWhat
.getStr());
1655 return std::make_unique
<vcl::pdf::PDFiumSearchHandleImpl
>(
1656 FPDFText_FindStart(mpTextPage
, pFindWhat
, static_cast<sal_uInt32
>(nFlags
), nStartIndex
));
1659 PDFiumSearchHandleImpl::PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle
)
1660 : mpSearchHandle(pSearchHandle
)
1664 PDFiumSearchHandleImpl::~PDFiumSearchHandleImpl()
1667 FPDFText_FindClose(mpSearchHandle
);
1670 bool PDFiumSearchHandleImpl::findNext() { return FPDFText_FindNext(mpSearchHandle
); }
1672 bool PDFiumSearchHandleImpl::findPrev() { return FPDFText_FindPrev(mpSearchHandle
); }
1674 int PDFiumSearchHandleImpl::getSearchResultIndex()
1676 return FPDFText_GetSchResultIndex(mpSearchHandle
);
1679 int PDFiumSearchHandleImpl::getSearchCount() { return FPDFText_GetSchCount(mpSearchHandle
); }
1681 std::shared_ptr
<PDFium
>& PDFiumLibrary::get()
1683 static std::shared_ptr
<PDFium
> pInstance
= std::make_shared
<PDFiumImpl
>();
1689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */