/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; static_assert(static_cast(vcl::pdf::PDFPageObjectType::Unknown) == FPDF_PAGEOBJ_UNKNOWN, "PDFPageObjectType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFPageObjectType::Text) == FPDF_PAGEOBJ_TEXT, "PDFPageObjectType::Text value mismatch"); static_assert(static_cast(vcl::pdf::PDFPageObjectType::Path) == FPDF_PAGEOBJ_PATH, "PDFPageObjectType::Path value mismatch"); static_assert(static_cast(vcl::pdf::PDFPageObjectType::Image) == FPDF_PAGEOBJ_IMAGE, "PDFPageObjectType::Image value mismatch"); static_assert(static_cast(vcl::pdf::PDFPageObjectType::Shading) == FPDF_PAGEOBJ_SHADING, "PDFPageObjectType::Shading value mismatch"); static_assert(static_cast(vcl::pdf::PDFPageObjectType::Form) == FPDF_PAGEOBJ_FORM, "PDFPageObjectType::Form value mismatch"); static_assert(static_cast(vcl::pdf::PDFSegmentType::Unknown) == FPDF_SEGMENT_UNKNOWN, "PDFSegmentType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFSegmentType::Lineto) == FPDF_SEGMENT_LINETO, "PDFSegmentType::Lineto value mismatch"); static_assert(static_cast(vcl::pdf::PDFSegmentType::Bezierto) == FPDF_SEGMENT_BEZIERTO, "PDFSegmentType::Bezierto value mismatch"); static_assert(static_cast(vcl::pdf::PDFSegmentType::Moveto) == FPDF_SEGMENT_MOVETO, "PDFSegmentType::Moveto value mismatch"); static_assert(static_cast(vcl::pdf::PDFBitmapType::Unknown) == FPDFBitmap_Unknown, "PDFBitmapType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFBitmapType::Gray) == FPDFBitmap_Gray, "PDFBitmapType::Gray value mismatch"); static_assert(static_cast(vcl::pdf::PDFBitmapType::BGR) == FPDFBitmap_BGR, "PDFBitmapType::BGR value mismatch"); static_assert(static_cast(vcl::pdf::PDFBitmapType::BGRx) == FPDFBitmap_BGRx, "PDFBitmapType::BGRx value mismatch"); static_assert(static_cast(vcl::pdf::PDFBitmapType::BGRA) == FPDFBitmap_BGRA, "PDFBitmapType::BGRA value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Unknown) == FPDF_OBJECT_UNKNOWN, "PDFObjectType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Boolean) == FPDF_OBJECT_BOOLEAN, "PDFObjectType::Boolean value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Number) == FPDF_OBJECT_NUMBER, "PDFObjectType::Number value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::String) == FPDF_OBJECT_STRING, "PDFObjectType::String value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Name) == FPDF_OBJECT_NAME, "PDFObjectType::Name value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Array) == FPDF_OBJECT_ARRAY, "PDFObjectType::Array value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Dictionary) == FPDF_OBJECT_DICTIONARY, "PDFObjectType::Dictionary value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Stream) == FPDF_OBJECT_STREAM, "PDFObjectType::Stream value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Nullobj) == FPDF_OBJECT_NULLOBJ, "PDFObjectType::Nullobj value mismatch"); static_assert(static_cast(vcl::pdf::PDFObjectType::Reference) == FPDF_OBJECT_REFERENCE, "PDFObjectType::Reference value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::Unknown) == FPDF_TEXTRENDERMODE_UNKNOWN, "PDFTextRenderMode::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::Fill) == FPDF_TEXTRENDERMODE_FILL, "PDFTextRenderMode::Fill value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::Stroke) == FPDF_TEXTRENDERMODE_STROKE, "PDFTextRenderMode::Stroke value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::FillStroke) == FPDF_TEXTRENDERMODE_FILL_STROKE, "PDFTextRenderMode::FillStroke value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::Invisible) == FPDF_TEXTRENDERMODE_INVISIBLE, "PDFTextRenderMode::Invisible value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::FillClip) == FPDF_TEXTRENDERMODE_FILL_CLIP, "PDFTextRenderMode::FillClip value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::StrokeClip) == FPDF_TEXTRENDERMODE_STROKE_CLIP, "PDFTextRenderMode::StrokeClip value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::FillStrokeClip) == FPDF_TEXTRENDERMODE_FILL_STROKE_CLIP, "PDFTextRenderMode::FillStrokeClip value mismatch"); static_assert(static_cast(vcl::pdf::PDFTextRenderMode::Clip) == FPDF_TEXTRENDERMODE_CLIP, "PDFTextRenderMode::Clip value mismatch"); static_assert(static_cast(vcl::pdf::PDFFillMode::None) == FPDF_FILLMODE_NONE, "PDFFillMode::None value mismatch"); static_assert(static_cast(vcl::pdf::PDFFillMode::Alternate) == FPDF_FILLMODE_ALTERNATE, "PDFFillMode::Alternate value mismatch"); static_assert(static_cast(vcl::pdf::PDFFillMode::Winding) == FPDF_FILLMODE_WINDING, "PDFFillMode::Winding value mismatch"); static_assert(static_cast(vcl::pdf::PDFFindFlags::MatchCase) == FPDF_MATCHCASE, "PDFFindFlags::MatchCase value mismatch"); static_assert(static_cast(vcl::pdf::PDFFindFlags::MatchWholeWord) == FPDF_MATCHWHOLEWORD, "PDFFindFlags::MatchWholeWord value mismatch"); static_assert(static_cast(vcl::pdf::PDFFindFlags::Consecutive) == FPDF_CONSECUTIVE, "PDFFindFlags::Consecutive value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Success) == FPDF_ERR_SUCCESS, "PDFErrorType::Success value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Unknown) == FPDF_ERR_UNKNOWN, "PDFErrorType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::File) == FPDF_ERR_FILE, "PDFErrorType::File value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Format) == FPDF_ERR_FORMAT, "PDFErrorType::Format value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Password) == FPDF_ERR_PASSWORD, "PDFErrorType::Password value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Security) == FPDF_ERR_SECURITY, "PDFErrorType::Security value mismatch"); static_assert(static_cast(vcl::pdf::PDFErrorType::Page) == FPDF_ERR_PAGE, "PDFErrorType::Page value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::Unknown) == FPDF_FORMFIELD_UNKNOWN, "PDFFormFieldType::Unknown value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::PushButton) == FPDF_FORMFIELD_PUSHBUTTON, "PDFFormFieldType::PushButton value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::CheckBox) == FPDF_FORMFIELD_CHECKBOX, "PDFFormFieldType::CheckBox value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::RadioButton) == FPDF_FORMFIELD_RADIOBUTTON, "PDFFormFieldType::RadioButton value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::ComboBox) == FPDF_FORMFIELD_COMBOBOX, "PDFFormFieldType::ComboBox value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::ListBox) == FPDF_FORMFIELD_LISTBOX, "PDFFormFieldType::ListBox value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::TextField) == FPDF_FORMFIELD_TEXTFIELD, "PDFFormFieldType::TextField value mismatch"); static_assert(static_cast(vcl::pdf::PDFFormFieldType::Signature) == FPDF_FORMFIELD_SIGNATURE, "PDFFormFieldType::Signature value mismatch"); static_assert(static_cast(vcl::pdf::PDFAnnotAActionType::KeyStroke) == FPDF_ANNOT_AACTION_KEY_STROKE, "PDFAnnotAActionType::KeyStroke) value mismatch"); static_assert(static_cast(vcl::pdf::PDFAnnotAActionType::Format) == FPDF_ANNOT_AACTION_FORMAT, "PDFAnnotAActionType::Format) value mismatch"); static_assert(static_cast(vcl::pdf::PDFAnnotAActionType::Validate) == FPDF_ANNOT_AACTION_VALIDATE, "PDFAnnotAActionType::Validate) value mismatch"); static_assert(static_cast(vcl::pdf::PDFAnnotAActionType::Calculate) == FPDF_ANNOT_AACTION_CALCULATE, "PDFAnnotAActionType::Calculate) value mismatch"); namespace { /// Callback class to be used with FPDF_SaveWithVersion(). struct CompatibleWriter : public FPDF_FILEWRITE { CompatibleWriter(SvMemoryStream& rStream) : m_rStream(rStream) { } SvMemoryStream& m_rStream; }; int CompatibleWriterCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsigned long nSize) { auto pImpl = static_cast(pFileWrite); pImpl->m_rStream.WriteBytes(pData, nSize); return 1; } } namespace vcl::pdf { namespace { class PDFiumBitmapImpl final : public PDFiumBitmap { private: FPDF_BITMAP mpBitmap; PDFiumBitmapImpl(const PDFiumBitmapImpl&) = delete; PDFiumBitmapImpl& operator=(const PDFiumBitmapImpl&) = delete; public: PDFiumBitmapImpl(FPDF_BITMAP pBitmap); ~PDFiumBitmapImpl() override; FPDF_BITMAP getPointer() { return mpBitmap; } void fillRect(int left, int top, int width, int height, sal_uInt32 nColor) override; void renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX, int nSizeY) override; ConstScanline getBuffer() override; int getStride() override; int getWidth() override; int getHeight() override; PDFBitmapType getFormat() override; }; class PDFiumPathSegmentImpl final : public PDFiumPathSegment { private: FPDF_PATHSEGMENT mpPathSegment; PDFiumPathSegmentImpl(const PDFiumPathSegmentImpl&) = delete; PDFiumPathSegmentImpl& operator=(const PDFiumPathSegmentImpl&) = delete; public: PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment); basegfx::B2DPoint getPoint() const override; bool isClosed() const override; PDFSegmentType getType() const override; }; class PDFiumAnnotationImpl final : public PDFiumAnnotation { private: FPDF_ANNOTATION mpAnnotation; PDFiumAnnotationImpl(const PDFiumAnnotationImpl&) = delete; PDFiumAnnotationImpl& operator=(const PDFiumAnnotationImpl&) = delete; public: PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation); ~PDFiumAnnotationImpl(); FPDF_ANNOTATION getPointer() { return mpAnnotation; } PDFAnnotationSubType getSubType() override; basegfx::B2DRectangle getRectangle() override; bool hasKey(OString const& rKey) override; PDFObjectType getValueType(OString const& rKey) override; OUString getString(OString const& rKey) override; std::unique_ptr getLinked(OString const& rKey) override; int getObjectCount() override; std::unique_ptr getObject(int nIndex) override; std::vector> getInkStrokes() override; std::vector getVertices() override; Color getColor() override; Color getInteriorColor() override; float getBorderWidth() override; basegfx::B2DSize getBorderCornerRadius() override; size_t getAttachmentPointsCount() override; std::vector getAttachmentPoints(size_t nIndex) override; std::vector getLineGeometry() override; PDFFormFieldType getFormFieldType(PDFiumDocument* pDoc) override; float getFontSize(PDFiumDocument* pDoc) override; Color getFontColor(PDFiumDocument* pDoc) override; OUString getFormFieldAlternateName(PDFiumDocument* pDoc) override; int getFormFieldFlags(PDFiumDocument* pDoc) override; OUString getFormAdditionalActionJavaScript(PDFiumDocument* pDoc, PDFAnnotAActionType eEvent) override; OUString getFormFieldValue(PDFiumDocument* pDoc) override; int getOptionCount(PDFiumDocument* pDoc) override; }; class PDFiumPageObjectImpl final : public PDFiumPageObject { private: FPDF_PAGEOBJECT mpPageObject; PDFiumPageObjectImpl(const PDFiumPageObjectImpl&) = delete; PDFiumPageObjectImpl& operator=(const PDFiumPageObjectImpl&) = delete; public: PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject); PDFPageObjectType getType() override; OUString getText(std::unique_ptr const& pTextPage) override; int getFormObjectCount() override; std::unique_ptr getFormObject(int nIndex) override; basegfx::B2DHomMatrix getMatrix() override; basegfx::B2DRectangle getBounds() override; double getFontSize() override; OUString getFontName() override; PDFTextRenderMode getTextRenderMode() override; Color getFillColor() override; Color getStrokeColor() override; double getStrokeWidth() override; // Path int getPathSegmentCount() override; std::unique_ptr getPathSegment(int index) override; Size getImageSize(PDFiumPage& rPage) override; std::unique_ptr getImageBitmap() override; bool getDrawMode(PDFFillMode& eFillMode, bool& bStroke) override; }; class PDFiumSearchHandleImpl final : public PDFiumSearchHandle { private: FPDF_SCHHANDLE mpSearchHandle; PDFiumSearchHandleImpl(const PDFiumSearchHandleImpl&) = delete; PDFiumSearchHandleImpl& operator=(const PDFiumSearchHandleImpl&) = delete; public: PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle); ~PDFiumSearchHandleImpl(); bool findNext() override; bool findPrev() override; int getSearchResultIndex() override; int getSearchCount() override; }; class PDFiumTextPageImpl final : public PDFiumTextPage { private: FPDF_TEXTPAGE mpTextPage; PDFiumTextPageImpl(const PDFiumTextPageImpl&) = delete; PDFiumTextPageImpl& operator=(const PDFiumTextPageImpl&) = delete; public: PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage); ~PDFiumTextPageImpl(); FPDF_TEXTPAGE getPointer() { return mpTextPage; } int countChars() override; unsigned int getUnicode(int index) override; std::unique_ptr findStart(const OUString& rFindWhat, PDFFindFlags nFlags, sal_Int32 nStartIndex) override; /// Returned rect is no longer upside down and is in mm100. basegfx::B2DRectangle getCharBox(int nIndex, double fPageHeight) override; }; class PDFiumSignatureImpl final : public PDFiumSignature { private: FPDF_SIGNATURE mpSignature; PDFiumSignatureImpl(const PDFiumSignatureImpl&) = delete; PDFiumSignatureImpl& operator=(const PDFiumSignatureImpl&) = delete; public: PDFiumSignatureImpl(FPDF_SIGNATURE pSignature); std::vector getByteRange() override; int getDocMDPPermission() override; std::vector getContents() override; OString getSubFilter() override; OUString getReason() override; css::util::DateTime getTime() override; }; class PDFiumPageImpl final : public PDFiumPage { private: FPDF_PAGE mpPage; private: PDFiumPageImpl(const PDFiumPageImpl&) = delete; PDFiumPageImpl& operator=(const PDFiumPageImpl&) = delete; public: PDFiumPageImpl(FPDF_PAGE pPage) : mpPage(pPage) { } ~PDFiumPageImpl() override { if (mpPage) FPDF_ClosePage(mpPage); } FPDF_PAGE getPointer() { return mpPage; } int getObjectCount() override; std::unique_ptr getObject(int nIndex) override; int getAnnotationCount() override; int getAnnotationIndex(std::unique_ptr const& rAnnotation) override; std::unique_ptr getAnnotation(int nIndex) override; std::unique_ptr getTextPage() override; BitmapChecksum getChecksum(int nMDPPerm) override; double getWidth() override; double getHeight() override; bool hasTransparency() override; bool hasLinks() override; void onAfterLoadPage(PDFiumDocument* pDoc) override; }; /// Wrapper around FPDF_FORMHANDLE. class PDFiumFormHandle final { private: FPDF_FORMHANDLE mpHandle; PDFiumFormHandle(const PDFiumFormHandle&) = delete; PDFiumFormHandle& operator=(const PDFiumFormHandle&) = delete; public: PDFiumFormHandle(FPDF_FORMHANDLE pHandle); ~PDFiumFormHandle(); FPDF_FORMHANDLE getPointer(); }; class PDFiumDocumentImpl : public PDFiumDocument { private: FPDF_DOCUMENT mpPdfDocument; FPDF_FORMFILLINFO m_aFormCallbacks; std::unique_ptr m_pFormHandle; private: PDFiumDocumentImpl(const PDFiumDocumentImpl&) = delete; PDFiumDocumentImpl& operator=(const PDFiumDocumentImpl&) = delete; public: PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument); ~PDFiumDocumentImpl() override; FPDF_FORMHANDLE getFormHandlePointer(); // Page size in points basegfx::B2DSize getPageSize(int nIndex) override; int getPageCount() override; int getSignatureCount() override; int getFileVersion() override; bool saveWithVersion(SvMemoryStream& rStream, int nFileVersion) override; std::unique_ptr openPage(int nIndex) override; std::unique_ptr getSignature(int nIndex) override; std::vector getTrailerEnds() override; }; class PDFiumImpl : public PDFium { private: PDFiumImpl(const PDFiumImpl&) = delete; PDFiumImpl& operator=(const PDFiumImpl&) = delete; OUString maLastError; public: PDFiumImpl(); ~PDFiumImpl() override; const OUString& getLastError() const override { return maLastError; } std::unique_ptr openDocument(const void* pData, int nSize, const OString& rPassword) override; PDFErrorType getLastErrorCode() override; /// @brief creates bitmap, can reduce size if needed, check nWidth and nHeight std::unique_ptr createBitmap(int& nWidth, int& nHeight, int nAlpha) override; }; } PDFiumImpl::PDFiumImpl() { FPDF_LIBRARY_CONFIG aConfig; aConfig.version = 2; aConfig.m_pUserFontPaths = nullptr; aConfig.m_pIsolate = nullptr; aConfig.m_v8EmbedderSlot = 0; FPDF_InitLibraryWithConfig(&aConfig); } PDFiumImpl::~PDFiumImpl() { FPDF_DestroyLibrary(); } std::unique_ptr PDFiumImpl::openDocument(const void* pData, int nSize, const OString& rPassword) { maLastError = OUString(); std::unique_ptr pPDFiumDocument; FPDF_BYTESTRING pPassword = nullptr; if (!rPassword.isEmpty()) { pPassword = rPassword.getStr(); } FPDF_DOCUMENT pDocument = FPDF_LoadMemDocument(pData, nSize, pPassword); if (!pDocument) { switch (FPDF_GetLastError()) { case FPDF_ERR_SUCCESS: maLastError = "Success"; break; case FPDF_ERR_UNKNOWN: maLastError = "Unknown error"; break; case FPDF_ERR_FILE: maLastError = "File not found"; break; case FPDF_ERR_FORMAT: maLastError = "Input is not a PDF format"; break; case FPDF_ERR_PASSWORD: maLastError = "Incorrect password or password is required"; break; case FPDF_ERR_SECURITY: maLastError = "Security error"; break; case FPDF_ERR_PAGE: maLastError = "Content error"; break; default: break; } } else { pPDFiumDocument = std::make_unique(pDocument); } return pPDFiumDocument; } PDFErrorType PDFiumImpl::getLastErrorCode() { return static_cast(FPDF_GetLastError()); } std::unique_ptr PDFiumImpl::createBitmap(int& nWidth, int& nHeight, int nAlpha) { std::unique_ptr pPDFiumBitmap; FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha); if (!pPdfBitmap) { int nOriginal = nHeight; // PDFium cannot create big bitmaps, max 2^14 x 2^14 x 4 bytes per pixel if (nHeight > 16384) nHeight = 16384; if (nWidth > 16384) { nWidth = 16384.0 / nOriginal * nWidth; } if (nWidth * nHeight > 16384 * 16384) { nOriginal = nWidth; nHeight = 16384.0 / nOriginal * nHeight; } pPdfBitmap = FPDFBitmap_Create(nWidth, nHeight, nAlpha); } if (!pPdfBitmap) { maLastError = "Failed to create bitmap"; SAL_WARN("vcl.filter", "PDFiumImpl: " << getLastError()); } else { pPDFiumBitmap = std::make_unique(pPdfBitmap); } return pPDFiumBitmap; } PDFiumSignatureImpl::PDFiumSignatureImpl(FPDF_SIGNATURE pSignature) : mpSignature(pSignature) { } std::vector PDFiumSignatureImpl::getByteRange() { int nByteRangeLen = FPDFSignatureObj_GetByteRange(mpSignature, nullptr, 0); std::vector aByteRange(nByteRangeLen); if (nByteRangeLen <= 0) { return aByteRange; } FPDFSignatureObj_GetByteRange(mpSignature, aByteRange.data(), aByteRange.size()); return aByteRange; } int PDFiumSignatureImpl::getDocMDPPermission() { return FPDFSignatureObj_GetDocMDPPermission(mpSignature); } std::vector PDFiumSignatureImpl::getContents() { int nContentsLen = FPDFSignatureObj_GetContents(mpSignature, nullptr, 0); std::vector aContents(nContentsLen); if (aContents.empty()) { return aContents; } FPDFSignatureObj_GetContents(mpSignature, aContents.data(), aContents.size()); return aContents; } OString PDFiumSignatureImpl::getSubFilter() { int nSubFilterLen = FPDFSignatureObj_GetSubFilter(mpSignature, nullptr, 0); std::vector aSubFilterBuf(nSubFilterLen); FPDFSignatureObj_GetSubFilter(mpSignature, aSubFilterBuf.data(), aSubFilterBuf.size()); // Buffer is NUL-terminated. OString aSubFilter(aSubFilterBuf.data(), aSubFilterBuf.size() - 1); return aSubFilter; } OUString PDFiumSignatureImpl::getReason() { int nReasonLen = FPDFSignatureObj_GetReason(mpSignature, nullptr, 0); OUString aRet; if (nReasonLen > 0) { std::vector aReasonBuf(nReasonLen); FPDFSignatureObj_GetReason(mpSignature, aReasonBuf.data(), aReasonBuf.size()); aRet = OUString(aReasonBuf.data(), aReasonBuf.size() - 1); } return aRet; } util::DateTime PDFiumSignatureImpl::getTime() { util::DateTime aRet; int nTimeLen = FPDFSignatureObj_GetTime(mpSignature, nullptr, 0); if (nTimeLen <= 0) { return aRet; } // Example: "D:20161027100104". std::vector aTimeBuf(nTimeLen); FPDFSignatureObj_GetTime(mpSignature, aTimeBuf.data(), aTimeBuf.size()); OString aM(aTimeBuf.data(), aTimeBuf.size() - 1); if (aM.startsWith("D:") && aM.getLength() >= 16) { aRet.Year = o3tl::toInt32(aM.subView(2, 4)); aRet.Month = o3tl::toInt32(aM.subView(6, 2)); aRet.Day = o3tl::toInt32(aM.subView(8, 2)); aRet.Hours = o3tl::toInt32(aM.subView(10, 2)); aRet.Minutes = o3tl::toInt32(aM.subView(12, 2)); aRet.Seconds = o3tl::toInt32(aM.subView(14, 2)); } return aRet; } PDFiumDocumentImpl::PDFiumDocumentImpl(FPDF_DOCUMENT pPdfDocument) : mpPdfDocument(pPdfDocument) , m_aFormCallbacks() { m_aFormCallbacks.version = 1; m_pFormHandle = std::make_unique( FPDFDOC_InitFormFillEnvironment(pPdfDocument, &m_aFormCallbacks)); } PDFiumDocumentImpl::~PDFiumDocumentImpl() { m_pFormHandle.reset(); if (mpPdfDocument) FPDF_CloseDocument(mpPdfDocument); } FPDF_FORMHANDLE PDFiumDocumentImpl::getFormHandlePointer() { return m_pFormHandle->getPointer(); } std::unique_ptr PDFiumDocumentImpl::openPage(int nIndex) { std::unique_ptr pPDFiumPage; FPDF_PAGE pPage = FPDF_LoadPage(mpPdfDocument, nIndex); if (pPage) { pPDFiumPage = std::make_unique(pPage); } return pPDFiumPage; } std::unique_ptr PDFiumDocumentImpl::getSignature(int nIndex) { std::unique_ptr pPDFiumSignature; FPDF_SIGNATURE pSignature = FPDF_GetSignatureObject(mpPdfDocument, nIndex); if (pSignature) { pPDFiumSignature = std::make_unique(pSignature); } return pPDFiumSignature; } std::vector PDFiumDocumentImpl::getTrailerEnds() { int nNumTrailers = FPDF_GetTrailerEnds(mpPdfDocument, nullptr, 0); std::vector aTrailerEnds(nNumTrailers); FPDF_GetTrailerEnds(mpPdfDocument, aTrailerEnds.data(), aTrailerEnds.size()); return aTrailerEnds; } basegfx::B2DSize PDFiumDocumentImpl::getPageSize(int nIndex) { basegfx::B2DSize aSize; FS_SIZEF aPDFSize; if (FPDF_GetPageSizeByIndexF(mpPdfDocument, nIndex, &aPDFSize)) { aSize = basegfx::B2DSize(aPDFSize.width, aPDFSize.height); } return aSize; } int PDFiumDocumentImpl::getPageCount() { return FPDF_GetPageCount(mpPdfDocument); } int PDFiumDocumentImpl::getSignatureCount() { return FPDF_GetSignatureCount(mpPdfDocument); } int PDFiumDocumentImpl::getFileVersion() { int nFileVersion = 0; FPDF_GetFileVersion(mpPdfDocument, &nFileVersion); return nFileVersion; } bool PDFiumDocumentImpl::saveWithVersion(SvMemoryStream& rStream, int nFileVersion) { CompatibleWriter aWriter(rStream); aWriter.version = 1; aWriter.WriteBlock = &CompatibleWriterCallback; if (!FPDF_SaveWithVersion(mpPdfDocument, &aWriter, 0, nFileVersion)) { return false; } return true; } int PDFiumPageImpl::getObjectCount() { return FPDFPage_CountObjects(mpPage); } std::unique_ptr PDFiumPageImpl::getObject(int nIndex) { std::unique_ptr pPDFiumPageObject; FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(mpPage, nIndex); if (pPageObject) { pPDFiumPageObject = std::make_unique(pPageObject); } return pPDFiumPageObject; } int PDFiumPageImpl::getAnnotationCount() { return FPDFPage_GetAnnotCount(mpPage); } int PDFiumPageImpl::getAnnotationIndex(std::unique_ptr const& rAnnotation) { auto pAnnotation = static_cast(rAnnotation.get()); return FPDFPage_GetAnnotIndex(mpPage, pAnnotation->getPointer()); } std::unique_ptr PDFiumPageImpl::getAnnotation(int nIndex) { std::unique_ptr pPDFiumAnnotation; FPDF_ANNOTATION pAnnotation = FPDFPage_GetAnnot(mpPage, nIndex); if (pAnnotation) { pPDFiumAnnotation = std::make_unique(pAnnotation); } return pPDFiumAnnotation; } std::unique_ptr PDFiumPageImpl::getTextPage() { std::unique_ptr pPDFiumTextPage; FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(mpPage); if (pTextPage) { pPDFiumTextPage = std::make_unique(pTextPage); } return pPDFiumTextPage; } bool PDFiumPageImpl::hasLinks() { // This could be a full iterator, but at the moment we just determine if the list is empty or // not. int nStartPos = 0; FPDF_LINK pLinkAnnot = nullptr; return FPDFLink_Enumerate(mpPage, &nStartPos, &pLinkAnnot); } void PDFiumPageImpl::onAfterLoadPage(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); FORM_OnAfterLoadPage(mpPage, pDocImpl->getFormHandlePointer()); } PDFiumPageObjectImpl::PDFiumPageObjectImpl(FPDF_PAGEOBJECT pPageObject) : mpPageObject(pPageObject) { } OUString PDFiumPageObjectImpl::getText(std::unique_ptr const& rTextPage) { OUString sReturnText; auto pTextPage = static_cast(rTextPage.get()); int nBytes = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(), nullptr, 0); assert(nBytes % 2 == 0); nBytes /= 2; std::unique_ptr pText(new sal_Unicode[nBytes]); int nActualBytes = FPDFTextObj_GetText(mpPageObject, pTextPage->getPointer(), reinterpret_cast(pText.get()), nBytes * 2); assert(nActualBytes % 2 == 0); nActualBytes /= 2; if (nActualBytes > 1) { #if defined OSL_BIGENDIAN // The data returned by FPDFTextObj_GetText is documented to always be UTF-16LE: for (int i = 0; i != nActualBytes; ++i) { pText[i] = OSL_SWAPWORD(pText[i]); } #endif sReturnText = OUString(pText.get()); } return sReturnText; } PDFPageObjectType PDFiumPageObjectImpl::getType() { return static_cast(FPDFPageObj_GetType(mpPageObject)); } int PDFiumPageObjectImpl::getFormObjectCount() { return FPDFFormObj_CountObjects(mpPageObject); } std::unique_ptr PDFiumPageObjectImpl::getFormObject(int nIndex) { std::unique_ptr pPDFiumFormObject; FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(mpPageObject, nIndex); if (pFormObject) { pPDFiumFormObject = std::make_unique(pFormObject); } return pPDFiumFormObject; } basegfx::B2DHomMatrix PDFiumPageObjectImpl::getMatrix() { basegfx::B2DHomMatrix aB2DMatrix; FS_MATRIX matrix; if (FPDFPageObj_GetMatrix(mpPageObject, &matrix)) aB2DMatrix = basegfx::B2DHomMatrix::abcdef(matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f); return aB2DMatrix; } basegfx::B2DRectangle PDFiumPageObjectImpl::getBounds() { basegfx::B2DRectangle aB2DRectangle; float left = 0; float bottom = 0; float right = 0; float top = 0; if (FPDFPageObj_GetBounds(mpPageObject, &left, &bottom, &right, &top)) { aB2DRectangle = basegfx::B2DRectangle(left, top, right, bottom); } return aB2DRectangle; } double PDFiumPageObjectImpl::getFontSize() { float nSize{}; FPDFTextObj_GetFontSize(mpPageObject, &nSize); return nSize; } OUString PDFiumPageObjectImpl::getFontName() { OUString sFontName; const int nFontName = 80 + 1; std::unique_ptr pFontName(new char[nFontName]); // + terminating null FPDF_FONT pFontObject = FPDFTextObj_GetFont(mpPageObject); int nFontNameChars = FPDFFont_GetFontName(pFontObject, pFontName.get(), nFontName); if (nFontName >= nFontNameChars) { sFontName = OUString::createFromAscii(pFontName.get()); } return sFontName; } PDFTextRenderMode PDFiumPageObjectImpl::getTextRenderMode() { return static_cast(FPDFTextObj_GetTextRenderMode(mpPageObject)); } Color PDFiumPageObjectImpl::getFillColor() { Color aColor = COL_TRANSPARENT; unsigned int nR, nG, nB, nA; if (FPDFPageObj_GetFillColor(mpPageObject, &nR, &nG, &nB, &nA)) { aColor = Color(ColorAlpha, nA, nR, nG, nB); } return aColor; } Color PDFiumPageObjectImpl::getStrokeColor() { Color aColor = COL_TRANSPARENT; unsigned int nR, nG, nB, nA; if (FPDFPageObj_GetStrokeColor(mpPageObject, &nR, &nG, &nB, &nA)) { aColor = Color(ColorAlpha, nA, nR, nG, nB); } return aColor; } double PDFiumPageObjectImpl::getStrokeWidth() { float fWidth = 1; FPDFPageObj_GetStrokeWidth(mpPageObject, &fWidth); return fWidth; } int PDFiumPageObjectImpl::getPathSegmentCount() { return FPDFPath_CountSegments(mpPageObject); } std::unique_ptr PDFiumPageObjectImpl::getPathSegment(int index) { std::unique_ptr pPDFiumPathSegment; FPDF_PATHSEGMENT pPathSegment = FPDFPath_GetPathSegment(mpPageObject, index); if (pPathSegment) { pPDFiumPathSegment = std::make_unique(pPathSegment); } return pPDFiumPathSegment; } Size PDFiumPageObjectImpl::getImageSize(PDFiumPage& rPage) { FPDF_IMAGEOBJ_METADATA aMeta; auto& rPageImpl = static_cast(rPage); FPDFImageObj_GetImageMetadata(mpPageObject, rPageImpl.getPointer(), &aMeta); return Size(aMeta.width, aMeta.height); } std::unique_ptr PDFiumPageObjectImpl::getImageBitmap() { std::unique_ptr pPDFiumBitmap; FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(mpPageObject); if (pBitmap) { pPDFiumBitmap = std::make_unique(pBitmap); } return pPDFiumBitmap; } bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& rFillMode, bool& rStroke) { auto nFillMode = static_cast(rFillMode); auto bStroke = static_cast(rStroke); bool bRet = FPDFPath_GetDrawMode(mpPageObject, &nFillMode, &bStroke); rFillMode = static_cast(nFillMode); rStroke = static_cast(bStroke); return bRet; } BitmapChecksum PDFiumPageImpl::getChecksum(int nMDPPerm) { int nPageWidth = getWidth(); int nPageHeight = getHeight(); std::unique_ptr pPdfBitmap = PDFiumLibrary::get()->createBitmap(nPageWidth, nPageHeight, /*nAlpha=*/1); if (!pPdfBitmap) return 0; PDFiumBitmapImpl* pBitmapImpl = static_cast(pPdfBitmap.get()); int nFlags = 0; if (nMDPPerm != 3) { // Annotations/commenting should affect the checksum, signature verification wants this. nFlags = FPDF_ANNOT; } FPDF_RenderPageBitmap(pBitmapImpl->getPointer(), mpPage, /*start_x=*/0, /*start_y=*/0, nPageWidth, nPageHeight, /*rotate=*/0, nFlags); Bitmap aBitmap(Size(nPageWidth, nPageHeight), vcl::PixelFormat::N24_BPP); { BitmapScopedWriteAccess pWriteAccess(aBitmap); const auto pPdfBuffer = static_cast(FPDFBitmap_GetBuffer(pBitmapImpl->getPointer())); const int nStride = FPDFBitmap_GetStride(pBitmapImpl->getPointer()); for (int nRow = 0; nRow < nPageHeight; ++nRow) { ConstScanline pPdfLine = pPdfBuffer + (nStride * nRow); pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride); } } return aBitmap.GetChecksum(); } double PDFiumPageImpl::getWidth() { return FPDF_GetPageWidth(mpPage); } double PDFiumPageImpl::getHeight() { return FPDF_GetPageHeight(mpPage); } bool PDFiumPageImpl::hasTransparency() { return FPDFPage_HasTransparency(mpPage); } PDFiumPathSegmentImpl::PDFiumPathSegmentImpl(FPDF_PATHSEGMENT pPathSegment) : mpPathSegment(pPathSegment) { } basegfx::B2DPoint PDFiumPathSegmentImpl::getPoint() const { basegfx::B2DPoint aPoint; float fx, fy; if (FPDFPathSegment_GetPoint(mpPathSegment, &fx, &fy)) aPoint = basegfx::B2DPoint(fx, fy); return aPoint; } bool PDFiumPathSegmentImpl::isClosed() const { return FPDFPathSegment_GetClose(mpPathSegment); } PDFSegmentType PDFiumPathSegmentImpl::getType() const { return static_cast(FPDFPathSegment_GetType(mpPathSegment)); } PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle) : mpHandle(pHandle) { } PDFiumFormHandle::~PDFiumFormHandle() { FPDFDOC_ExitFormFillEnvironment(mpHandle); } FPDF_FORMHANDLE PDFiumFormHandle::getPointer() { return mpHandle; } PDFiumBitmapImpl::PDFiumBitmapImpl(FPDF_BITMAP pBitmap) : mpBitmap(pBitmap) { } PDFiumBitmapImpl::~PDFiumBitmapImpl() { if (mpBitmap) { FPDFBitmap_Destroy(mpBitmap); } } void PDFiumBitmapImpl::fillRect(int left, int top, int width, int height, sal_uInt32 nColor) { FPDFBitmap_FillRect(mpBitmap, left, top, width, height, nColor); } void PDFiumBitmapImpl::renderPageBitmap(PDFiumDocument* pDoc, PDFiumPage* pPage, int nStartX, int nStartY, int nSizeX, int nSizeY) { auto pPageImpl = static_cast(pPage); FPDF_RenderPageBitmap(mpBitmap, pPageImpl->getPointer(), nStartX, nStartY, nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0); // Render widget annotations for FormFields. auto pDocImpl = static_cast(pDoc); FPDF_FFLDraw(pDocImpl->getFormHandlePointer(), mpBitmap, pPageImpl->getPointer(), nStartX, nStartY, nSizeX, nSizeY, /*rotate=*/0, /*flags=*/0); } ConstScanline PDFiumBitmapImpl::getBuffer() { return static_cast(FPDFBitmap_GetBuffer(mpBitmap)); } int PDFiumBitmapImpl::getStride() { return FPDFBitmap_GetStride(mpBitmap); } int PDFiumBitmapImpl::getWidth() { return FPDFBitmap_GetWidth(mpBitmap); } int PDFiumBitmapImpl::getHeight() { return FPDFBitmap_GetHeight(mpBitmap); } PDFBitmapType PDFiumBitmapImpl::getFormat() { return static_cast(FPDFBitmap_GetFormat(mpBitmap)); } PDFiumAnnotationImpl::PDFiumAnnotationImpl(FPDF_ANNOTATION pAnnotation) : mpAnnotation(pAnnotation) { } PDFiumAnnotationImpl::~PDFiumAnnotationImpl() { if (mpAnnotation) FPDFPage_CloseAnnot(mpAnnotation); } PDFAnnotationSubType PDFiumAnnotationImpl::getSubType() { return PDFAnnotationSubType(FPDFAnnot_GetSubtype(mpAnnotation)); } basegfx::B2DRectangle PDFiumAnnotationImpl::getRectangle() { basegfx::B2DRectangle aB2DRectangle; FS_RECTF aRect; if (FPDFAnnot_GetRect(mpAnnotation, &aRect)) { aB2DRectangle = basegfx::B2DRectangle(aRect.left, aRect.top, aRect.right, aRect.bottom); } return aB2DRectangle; } Color PDFiumAnnotationImpl::getColor() { unsigned int nR, nG, nB, nA; if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_Color, &nR, &nG, &nB, &nA)) { return Color(ColorAlpha, nA, nR, nG, nB); } // FPDFAnnot_GetColor can return false if there is an appearance stream // So we search for a color with getStrokeColor for (int i = 0; i < getObjectCount(); ++i) { if (getObject(i)->getType() == PDFPageObjectType::Path) return getObject(i)->getStrokeColor(); } return COL_TRANSPARENT; } Color PDFiumAnnotationImpl::getInteriorColor() { unsigned int nR, nG, nB, nA; if (FPDFAnnot_GetColor(mpAnnotation, FPDFANNOT_COLORTYPE_InteriorColor, &nR, &nG, &nB, &nA)) { return Color(ColorAlpha, nA, nR, nG, nB); } // FPDFAnnot_GetColor can return false if there is an appearance stream // So we search for a color with getFillColor for (int i = 0; i < getObjectCount(); ++i) { if (getObject(i)->getType() == PDFPageObjectType::Path) return getObject(i)->getFillColor(); } return COL_TRANSPARENT; } size_t PDFiumAnnotationImpl::getAttachmentPointsCount() { return FPDFAnnot_CountAttachmentPoints(mpAnnotation); } std::vector PDFiumAnnotationImpl::getAttachmentPoints(size_t nIndex) { std::vector aQuads; FS_QUADPOINTSF aQuadpoints; if (FPDFAnnot_GetAttachmentPoints(mpAnnotation, nIndex, &aQuadpoints)) { aQuads.emplace_back(aQuadpoints.x1, aQuadpoints.y1); aQuads.emplace_back(aQuadpoints.x2, aQuadpoints.y2); aQuads.emplace_back(aQuadpoints.x3, aQuadpoints.y3); aQuads.emplace_back(aQuadpoints.x4, aQuadpoints.y4); } return aQuads; } std::vector PDFiumAnnotationImpl::getLineGeometry() { std::vector aLine; FS_POINTF aStart; FS_POINTF aEnd; if (FPDFAnnot_GetLine(mpAnnotation, &aStart, &aEnd)) { aLine.emplace_back(aStart.x, aStart.y); aLine.emplace_back(aEnd.x, aEnd.y); } return aLine; } PDFFormFieldType PDFiumAnnotationImpl::getFormFieldType(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); return PDFFormFieldType( FPDFAnnot_GetFormFieldType(pDocImpl->getFormHandlePointer(), mpAnnotation)); } int PDFiumAnnotationImpl::getFormFieldFlags(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); return FPDFAnnot_GetFormFieldFlags(pDocImpl->getFormHandlePointer(), mpAnnotation); } float PDFiumAnnotationImpl::getFontSize(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); float fRet{}; if (!FPDFAnnot_GetFontSize(pDocImpl->getFormHandlePointer(), mpAnnotation, &fRet)) { return 0.0f; } return fRet; } Color PDFiumAnnotationImpl::getFontColor(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); unsigned int nR, nG, nB; if (!FPDFAnnot_GetFontColor(pDocImpl->getFormHandlePointer(), mpAnnotation, &nR, &nG, &nB)) { return Color(); } return Color(nR, nG, nB); } OUString PDFiumAnnotationImpl::getFormFieldAlternateName(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); OUString aString; unsigned long nSize = FPDFAnnot_GetFormFieldAlternateName(pDocImpl->getFormHandlePointer(), mpAnnotation, nullptr, 0); assert(nSize % 2 == 0); nSize /= 2; if (nSize > 1) { std::unique_ptr pText(new sal_Unicode[nSize]); unsigned long nStringSize = FPDFAnnot_GetFormFieldAlternateName( pDocImpl->getFormHandlePointer(), mpAnnotation, reinterpret_cast(pText.get()), nSize * 2); assert(nStringSize % 2 == 0); nStringSize /= 2; if (nStringSize > 0) { #if defined OSL_BIGENDIAN for (unsigned long i = 0; i != nStringSize; ++i) { pText[i] = OSL_SWAPWORD(pText[i]); } #endif aString = OUString(pText.get()); } } return aString; } OUString PDFiumAnnotationImpl::getFormFieldValue(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); OUString aString; unsigned long nSize = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation, nullptr, 0); assert(nSize % 2 == 0); nSize /= 2; if (nSize > 1) { std::unique_ptr pText(new sal_Unicode[nSize]); unsigned long nStringSize = FPDFAnnot_GetFormFieldValue(pDocImpl->getFormHandlePointer(), mpAnnotation, reinterpret_cast(pText.get()), nSize * 2); assert(nStringSize % 2 == 0); nStringSize /= 2; if (nStringSize > 0) { #if defined OSL_BIGENDIAN for (unsigned long i = 0; i != nStringSize; ++i) { pText[i] = OSL_SWAPWORD(pText[i]); } #endif aString = OUString(pText.get()); } } return aString; } int PDFiumAnnotationImpl::getOptionCount(PDFiumDocument* pDoc) { auto pDocImpl = static_cast(pDoc); return FPDFAnnot_GetOptionCount(pDocImpl->getFormHandlePointer(), mpAnnotation); } OUString PDFiumAnnotationImpl::getFormAdditionalActionJavaScript(PDFiumDocument* pDoc, PDFAnnotAActionType eEvent) { auto pDocImpl = static_cast(pDoc); OUString aString; unsigned long nSize = FPDFAnnot_GetFormAdditionalActionJavaScript( pDocImpl->getFormHandlePointer(), mpAnnotation, static_cast(eEvent), nullptr, 0); assert(nSize % 2 == 0); nSize /= 2; if (nSize > 1) { std::unique_ptr pText(new sal_Unicode[nSize]); unsigned long nStringSize = FPDFAnnot_GetFormAdditionalActionJavaScript( pDocImpl->getFormHandlePointer(), mpAnnotation, static_cast(eEvent), reinterpret_cast(pText.get()), nSize * 2); assert(nStringSize % 2 == 0); nStringSize /= 2; if (nStringSize > 0) { #if defined OSL_BIGENDIAN for (unsigned long i = 0; i != nStringSize; ++i) { pText[i] = OSL_SWAPWORD(pText[i]); } #endif aString = OUString(pText.get()); } } return aString; } namespace { bool getBorderProperties(FPDF_ANNOTATION mpAnnotation, float& rHorizontalCornerRadius, float& rVerticalCornerRadius, float& rBorderWidth) { float fHoriRadius = 0.0f; float fVertRadius = 0.0f; float fWidth = 0.0f; if (!FPDFAnnot_GetBorder(mpAnnotation, &fHoriRadius, &fVertRadius, &fWidth)) return false; rHorizontalCornerRadius = fHoriRadius; rVerticalCornerRadius = fVertRadius; rBorderWidth = fWidth; return true; } } float PDFiumAnnotationImpl::getBorderWidth() { float fHorizontalCornerRadius; float fVerticalCornerRadius; float fBorderWidth; if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius, fBorderWidth)) return 0.0f; return fBorderWidth; } basegfx::B2DSize PDFiumAnnotationImpl::getBorderCornerRadius() { float fHorizontalCornerRadius; float fVerticalCornerRadius; float fBorderWidth; if (!getBorderProperties(mpAnnotation, fHorizontalCornerRadius, fVerticalCornerRadius, fBorderWidth)) return basegfx::B2DSize(0.0, 0.0); return basegfx::B2DSize(fHorizontalCornerRadius, fVerticalCornerRadius); } bool PDFiumAnnotationImpl::hasKey(OString const& rKey) { return FPDFAnnot_HasKey(mpAnnotation, rKey.getStr()); } PDFObjectType PDFiumAnnotationImpl::getValueType(OString const& rKey) { return static_cast(FPDFAnnot_GetValueType(mpAnnotation, rKey.getStr())); } OUString PDFiumAnnotationImpl::getString(OString const& rKey) { OUString rString; unsigned long nSize = FPDFAnnot_GetStringValue(mpAnnotation, rKey.getStr(), nullptr, 0); assert(nSize % 2 == 0); nSize /= 2; if (nSize > 1) { std::unique_ptr pText(new sal_Unicode[nSize]); unsigned long nStringSize = FPDFAnnot_GetStringValue( mpAnnotation, rKey.getStr(), reinterpret_cast(pText.get()), nSize * 2); assert(nStringSize % 2 == 0); nStringSize /= 2; if (nStringSize > 0) { #if defined OSL_BIGENDIAN // The data returned by FPDFAnnot_GetStringValue is documented to always be UTF-16LE: for (unsigned long i = 0; i != nStringSize; ++i) { pText[i] = OSL_SWAPWORD(pText[i]); } #endif rString = OUString(pText.get()); } } return rString; } std::vector> PDFiumAnnotationImpl::getInkStrokes() { std::vector> aB2DPointList; int nInkStrokes = FPDFAnnot_GetInkListCount(mpAnnotation); for (int i = 0; i < nInkStrokes; i++) { std::vector aB2DPoints; int nPoints = FPDFAnnot_GetInkListPath(mpAnnotation, i, nullptr, 0); if (nPoints) { std::vector aPoints(nPoints); if (FPDFAnnot_GetInkListPath(mpAnnotation, i, aPoints.data(), aPoints.size())) { for (auto const& rPoint : aPoints) { aB2DPoints.emplace_back(rPoint.x, rPoint.y); } aB2DPointList.push_back(aB2DPoints); } } } return aB2DPointList; } std::vector PDFiumAnnotationImpl::getVertices() { std::vector aB2DPoints; int nPoints = FPDFAnnot_GetVertices(mpAnnotation, nullptr, 0); if (nPoints) { std::vector aPoints(nPoints); if (FPDFAnnot_GetVertices(mpAnnotation, aPoints.data(), aPoints.size())) { for (auto const& rPoint : aPoints) aB2DPoints.emplace_back(rPoint.x, rPoint.y); } } return aB2DPoints; } std::unique_ptr PDFiumAnnotationImpl::getLinked(OString const& rKey) { std::unique_ptr pPDFiumAnnotation; FPDF_ANNOTATION pAnnotation = FPDFAnnot_GetLinkedAnnot(mpAnnotation, rKey.getStr()); if (pAnnotation) { pPDFiumAnnotation = std::make_unique(pAnnotation); } return pPDFiumAnnotation; } int PDFiumAnnotationImpl::getObjectCount() { return FPDFAnnot_GetObjectCount(mpAnnotation); } std::unique_ptr PDFiumAnnotationImpl::getObject(int nIndex) { std::unique_ptr pPDFiumPageObject; FPDF_PAGEOBJECT pPageObject = FPDFAnnot_GetObject(mpAnnotation, nIndex); if (pPageObject) { pPDFiumPageObject = std::make_unique(pPageObject); } return pPDFiumPageObject; } PDFiumTextPageImpl::PDFiumTextPageImpl(FPDF_TEXTPAGE pTextPage) : mpTextPage(pTextPage) { } PDFiumTextPageImpl::~PDFiumTextPageImpl() { if (mpTextPage) FPDFText_ClosePage(mpTextPage); } int PDFiumTextPageImpl::countChars() { return FPDFText_CountChars(mpTextPage); } basegfx::B2DRectangle PDFiumTextPageImpl::getCharBox(int nIndex, double fPageHeight) { double left = 0.0; double right = 0.0; double bottom = 0.0; double top = 0.0; if (FPDFText_GetCharBox(mpTextPage, nIndex, &left, &right, &bottom, &top)) { left = convertPointToMm100(left); right = convertPointToMm100(right); top = fPageHeight - convertPointToMm100(top); bottom = fPageHeight - convertPointToMm100(bottom); return basegfx::B2DRectangle(left, bottom, right, top); } return basegfx::B2DRectangle(); } unsigned int PDFiumTextPageImpl::getUnicode(int index) { return FPDFText_GetUnicode(mpTextPage, index); } std::unique_ptr PDFiumTextPageImpl::findStart(const OUString& rFindWhat, PDFFindFlags nFlags, sal_Int32 nStartIndex) { FPDF_WIDESTRING pFindWhat = reinterpret_cast(rFindWhat.getStr()); return std::make_unique( FPDFText_FindStart(mpTextPage, pFindWhat, static_cast(nFlags), nStartIndex)); } PDFiumSearchHandleImpl::PDFiumSearchHandleImpl(FPDF_SCHHANDLE pSearchHandle) : mpSearchHandle(pSearchHandle) { } PDFiumSearchHandleImpl::~PDFiumSearchHandleImpl() { if (mpSearchHandle) FPDFText_FindClose(mpSearchHandle); } bool PDFiumSearchHandleImpl::findNext() { return FPDFText_FindNext(mpSearchHandle); } bool PDFiumSearchHandleImpl::findPrev() { return FPDFText_FindPrev(mpSearchHandle); } int PDFiumSearchHandleImpl::getSearchResultIndex() { return FPDFText_GetSchResultIndex(mpSearchHandle); } int PDFiumSearchHandleImpl::getSearchCount() { return FPDFText_GetSchCount(mpSearchHandle); } std::shared_ptr& PDFiumLibrary::get() { static std::shared_ptr pInstance = std::make_shared(); return pInstance; } } // end vcl::pdf /* vim:set shiftwidth=4 softtabstop=4 expandtab: */