diff options
Diffstat (limited to 'vcl/inc/pdf')
-rw-r--r-- | vcl/inc/pdf/BitmapID.hxx | 40 | ||||
-rw-r--r-- | vcl/inc/pdf/ExternalPDFStreams.hxx | 73 | ||||
-rw-r--r-- | vcl/inc/pdf/Matrix3.hxx | 52 | ||||
-rw-r--r-- | vcl/inc/pdf/PdfConfig.hxx | 18 | ||||
-rw-r--r-- | vcl/inc/pdf/ResourceDict.hxx | 38 | ||||
-rw-r--r-- | vcl/inc/pdf/XmpMetadata.hxx | 57 | ||||
-rw-r--r-- | vcl/inc/pdf/objectcopier.hxx | 64 | ||||
-rw-r--r-- | vcl/inc/pdf/pdfbuildin_fonts.hxx | 79 | ||||
-rw-r--r-- | vcl/inc/pdf/pdfcompat.hxx | 40 | ||||
-rw-r--r-- | vcl/inc/pdf/pdfwriter_impl.hxx | 1358 |
10 files changed, 1819 insertions, 0 deletions
diff --git a/vcl/inc/pdf/BitmapID.hxx b/vcl/inc/pdf/BitmapID.hxx new file mode 100644 index 0000000000..34f99944dc --- /dev/null +++ b/vcl/inc/pdf/BitmapID.hxx @@ -0,0 +1,40 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <vcl/checksum.hxx> +#include <tools/gen.hxx> + +namespace vcl::pdf +{ +struct BitmapID +{ + Size m_aPixelSize; + sal_Int32 m_nSize; + BitmapChecksum m_nChecksum; + BitmapChecksum m_nMaskChecksum; + + BitmapID() + : m_nSize(0) + , m_nChecksum(0) + , m_nMaskChecksum(0) + { + } + + bool operator==(const BitmapID& rComp) const + { + return (m_aPixelSize == rComp.m_aPixelSize && m_nSize == rComp.m_nSize + && m_nChecksum == rComp.m_nChecksum && m_nMaskChecksum == rComp.m_nMaskChecksum); + } +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/ExternalPDFStreams.hxx b/vcl/inc/pdf/ExternalPDFStreams.hxx new file mode 100644 index 0000000000..b2936f01a8 --- /dev/null +++ b/vcl/inc/pdf/ExternalPDFStreams.hxx @@ -0,0 +1,73 @@ +/* -*- 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/. + */ + +#pragma once + +#include <sal/types.h> +#include <sal/log.hxx> +#include <vcl/dllapi.h> + +#include <map> +#include <vector> +#include <memory> + +#include <vcl/filter/pdfdocument.hxx> +#include <vcl/BinaryDataContainer.hxx> + +namespace vcl +{ +// A external PDF stream, which stores the PDF stream data as byte array. +// This struct is also responsible to parsing the stream as a PDFDocument, +// and store its instance for the life-cycle of the struct, so that it +// reused to avoid unnecessary parsing. +struct VCL_DLLPUBLIC ExternalPDFStream +{ + BinaryDataContainer maDataContainer; + std::shared_ptr<filter::PDFDocument> mpPDFDocument; + std::map<sal_Int32, sal_Int32> maCopiedResources; + + std::map<sal_Int32, sal_Int32>& getCopiedResources() { return maCopiedResources; } + + std::shared_ptr<filter::PDFDocument>& getPDFDocument() + { + if (!mpPDFDocument) + { + std::shared_ptr<SvStream> aPDFStream = maDataContainer.getAsStream(); + auto pPDFDocument = std::make_shared<filter::PDFDocument>(); + if (!pPDFDocument->ReadWithPossibleFixup(*aPDFStream)) + { + SAL_WARN("vcl.pdfwriter", + "PDFWriterImpl::writeReferenceXObject: reading the PDF document failed"); + } + else + { + mpPDFDocument = pPDFDocument; + } + } + return mpPDFDocument; + } +}; + +// Class to manage external PDF streams, for the de-duplication purpose. +class ExternalPDFStreams +{ +private: + std::map<std::vector<sal_uInt8>, sal_Int32> maStreamIndexMap; + std::vector<ExternalPDFStream> maStreamList; + +public: + ExternalPDFStreams() {} + + sal_Int32 store(BinaryDataContainer const& rDataContainer); + + ExternalPDFStream& get(sal_uInt32 nIndex); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/Matrix3.hxx b/vcl/inc/pdf/Matrix3.hxx new file mode 100644 index 0000000000..226235f526 --- /dev/null +++ b/vcl/inc/pdf/Matrix3.hxx @@ -0,0 +1,52 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <basegfx/point/b2dpoint.hxx> +#include <tools/gen.hxx> + +namespace vcl::pdf +{ +// matrix helper class +// TODO: use basegfx matrix class instead or derive from it + +/* for sparse matrices of the form (2D linear transformations) + * f[0] f[1] 0 + * f[2] f[3] 0 + * f[4] f[5] 1 + */ +class Matrix3 +{ + double f[6]; + + void set(const double* pn) + { + for (int i = 0; i < 6; i++) + f[i] = pn[i]; + } + +public: + Matrix3(); + + void skew(double alpha, double beta); + void scale(double sx, double sy); + void rotate(double angle); + void translate(double tx, double ty); + void invert(); + + double get(size_t i) const { return f[i]; } + + Point transform(const Point& rPoint) const; + basegfx::B2DPoint transform(const basegfx::B2DPoint& rPoint) const; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/PdfConfig.hxx b/vcl/inc/pdf/PdfConfig.hxx new file mode 100644 index 0000000000..235fd008ea --- /dev/null +++ b/vcl/inc/pdf/PdfConfig.hxx @@ -0,0 +1,18 @@ +/* -*- 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/. + * + */ + +#pragma once + +namespace vcl::pdf +{ +double getDefaultPdfResolutionDpi(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/ResourceDict.hxx b/vcl/inc/pdf/ResourceDict.hxx new file mode 100644 index 0000000000..119d9314f4 --- /dev/null +++ b/vcl/inc/pdf/ResourceDict.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <rtl/strbuf.hxx> +#include <map> + +namespace vcl::pdf +{ +enum class ResourceKind +{ + XObject, + ExtGState, + Shading, + Pattern +}; + +struct ResourceDict +{ + // note: handle fonts globally for performance + std::map<OString, sal_Int32> m_aXObjects; + std::map<OString, sal_Int32> m_aExtGStates; + std::map<OString, sal_Int32> m_aShadings; + std::map<OString, sal_Int32> m_aPatterns; + + void append(OStringBuffer& rBuffer, sal_Int32 nFontDictObject); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/XmpMetadata.hxx b/vcl/inc/pdf/XmpMetadata.hxx new file mode 100644 index 0000000000..33fce97a21 --- /dev/null +++ b/vcl/inc/pdf/XmpMetadata.hxx @@ -0,0 +1,57 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <rtl/string.hxx> +#include <tools/stream.hxx> +#include <memory> +#include <vector> + +namespace vcl::pdf +{ +class XmpMetadata +{ +private: + bool mbWritten; + std::unique_ptr<SvMemoryStream> mpMemoryStream; + +public: + OString msTitle; + OString msAuthor; + OString msSubject; + OString msProducer; + OString msPDFVersion; + OString msKeywords; + std::vector<OString> maContributor; + OString msCoverage; + OString msIdentifier; + std::vector<OString> maPublisher; + std::vector<OString> maRelation; + OString msRights; + OString msSource; + OString msType; + OString m_sCreatorTool; + OString m_sCreateDate; + + sal_Int32 mnPDF_A; + bool mbPDF_UA; + +public: + XmpMetadata(); + sal_uInt64 getSize(); + const void* getData(); + +private: + void write(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/objectcopier.hxx b/vcl/inc/pdf/objectcopier.hxx new file mode 100644 index 0000000000..0168f69717 --- /dev/null +++ b/vcl/inc/pdf/objectcopier.hxx @@ -0,0 +1,64 @@ +/* -*- 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/. + */ + +#pragma once + +#include <map> +#include <vector> + +#include <rtl/strbuf.hxx> +#include <rtl/string.hxx> +#include <sal/types.h> + +class SvMemoryStream; + +namespace vcl +{ +class PDFObjectContainer; +namespace filter +{ +class PDFObjectElement; +class PDFElement; +} + +/// Copies objects from one PDF file into another one. +class PDFObjectCopier +{ + PDFObjectContainer& m_rContainer; + + void copyRecursively(OStringBuffer& rLine, filter::PDFElement& rInputElement, + SvMemoryStream& rDocBuffer, + std::map<sal_Int32, sal_Int32>& rCopiedResources); + +public: + PDFObjectCopier(PDFObjectContainer& rContainer); + + /// Copies resources of a given kind from an external page to the output, + /// returning what has to be included in the new resource dictionary. + OString copyExternalResources(filter::PDFObjectElement& rPage, const OString& rKind, + std::map<sal_Int32, sal_Int32>& rCopiedResources); + + /// Copies a single resource from an external document, returns the new + /// object ID in our document. + sal_Int32 copyExternalResource(SvMemoryStream& rDocBuffer, filter::PDFObjectElement& rObject, + std::map<sal_Int32, sal_Int32>& rCopiedResources); + + /// Copies resources of pPage into rLine. + void copyPageResources(filter::PDFObjectElement* pPage, OStringBuffer& rLine); + + void copyPageResources(filter::PDFObjectElement* pPage, OStringBuffer& rLine, + std::map<sal_Int32, sal_Int32>& rCopiedResources); + + /// Copies page one or more page streams from rContentStreams into rStream. + static sal_Int32 copyPageStreams(std::vector<filter::PDFObjectElement*>& rContentStreams, + SvMemoryStream& rStream, bool& rCompressed); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/pdfbuildin_fonts.hxx b/vcl/inc/pdf/pdfbuildin_fonts.hxx new file mode 100644 index 0000000000..a0c2fc0628 --- /dev/null +++ b/vcl/inc/pdf/pdfbuildin_fonts.hxx @@ -0,0 +1,79 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <font/PhysicalFontFace.hxx> +#include <font/LogicalFontInstance.hxx> + +namespace vcl::pdf +{ +struct BuildinFont +{ + const char* m_pName; + const char* m_pStyleName; + const char* m_pPSName; + int const m_nAscent; + int const m_nDescent; + FontFamily const m_eFamily; + rtl_TextEncoding const m_eCharSet; + FontPitch const m_ePitch; + FontWidth const m_eWidthType; + FontWeight const m_eWeight; + FontItalic const m_eItalic; + int const m_aWidths[256]; + mutable FontCharMapRef m_xFontCharMap; + + OString getNameObject() const; + const FontCharMapRef& GetFontCharMap() const; + FontAttributes GetFontAttributes() const; +}; + +class BuildinFontInstance final : public LogicalFontInstance +{ +public: + BuildinFontInstance(const vcl::font::PhysicalFontFace&, const vcl::font::FontSelectPattern&); + + bool GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rPoly, bool) const override; +}; + +class BuildinFontFace final : public vcl::font::PhysicalFontFace +{ + static const BuildinFont m_aBuildinFonts[14]; + const BuildinFont& mrBuildin; + + rtl::Reference<LogicalFontInstance> + CreateFontInstance(const vcl::font::FontSelectPattern& rFSD) const override; + +public: + explicit BuildinFontFace(int nId); + + const BuildinFont& GetBuildinFont() const { return mrBuildin; } + sal_IntPtr GetFontId() const override { return reinterpret_cast<sal_IntPtr>(&mrBuildin); } + FontCharMapRef GetFontCharMap() const override { return mrBuildin.GetFontCharMap(); } + bool GetFontCapabilities(vcl::FontCapabilities&) const override { return false; } + + static const BuildinFont& Get(int nId) { return m_aBuildinFonts[nId]; } +}; + +} // namespace vcl::pdf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/pdfcompat.hxx b/vcl/inc/pdf/pdfcompat.hxx new file mode 100644 index 0000000000..0664a400f9 --- /dev/null +++ b/vcl/inc/pdf/pdfcompat.hxx @@ -0,0 +1,40 @@ +/* -*- 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/. + */ + +#pragma once + +#include <o3tl/unit_conversion.hxx> +#include <tools/stream.hxx> +#include <vcl/BinaryDataContainer.hxx> + +namespace vcl::pdf +{ +/// Convert to inch, then apply custom resolution. +inline double pointToPixel(const double fPoint, const double fResolutionDPI) +{ + return o3tl::convert(fPoint, o3tl::Length::pt, o3tl::Length::in) * fResolutionDPI; +} + +/// Decide if PDF data is old enough to be compatible. +bool isCompatible(SvStream& rInStream, sal_uInt64 nPos, sal_uInt64 nSize); + +/// Converts to highest supported format version (currently 1.6). +/// Usually used to deal with missing referenced objects in the +/// source pdf stream. +bool convertToHighestSupported(SvStream& rInStream, SvStream& rOutStream); + +/// Takes care of transparently downgrading the version of the PDF stream in +/// case it's too new for our PDF export. +bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream); + +BinaryDataContainer createBinaryDataContainer(SvStream& rStream); + +} // end of vcl::filter::ipdf namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx new file mode 100644 index 0000000000..090f3e090c --- /dev/null +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -0,0 +1,1358 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <map> +#include <list> +#include <unordered_map> +#include <unordered_set> +#include <memory> +#include <string_view> +#include <vector> +#include <stack> +#include <variant> + +#include <pdf/ResourceDict.hxx> +#include <pdf/BitmapID.hxx> +#include <pdf/Matrix3.hxx> + +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <osl/file.hxx> +#include <rtl/cipher.h> +#include <rtl/strbuf.hxx> +#include <rtl/ustring.hxx> +#include <tools/gen.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/gradient.hxx> +#include <vcl/graphictools.hxx> +#include <vcl/hatch.hxx> +#include <vcl/virdev.hxx> +#include <vcl/pdfwriter.hxx> +#include <vcl/wall.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/typed_flags_set.hxx> +#include <o3tl/lru_map.hxx> +#include <comphelper/hash.hxx> +#include <tools/stream.hxx> +#include <vcl/BinaryDataContainer.hxx> + +#include <vcl/filter/pdfobjectcontainer.hxx> +#include <vcl/settings.hxx> +#include <pdf/ExternalPDFStreams.hxx> +#include <pdf/pdfbuildin_fonts.hxx> +#include <salgdi.hxx> + +class FontSubsetInfo; +class ZCodec; +class EncHashTransporter; +struct BitStreamState; +namespace vcl::font { class PhysicalFontFace; } +class SvStream; +class SvMemoryStream; + +// the maximum password length +constexpr sal_Int32 ENCRYPTED_PWD_SIZE = 32; +constexpr sal_Int32 MD5_DIGEST_SIZE = 16; +// security 128 bit +constexpr sal_Int32 SECUR_128BIT_KEY = 16; +// maximum length of MD5 digest input, in step 2 of algorithm 3.1 +// PDF spec ver. 1.4: see there for details +constexpr sal_Int32 MAXIMUM_RC4_KEY_LENGTH = SECUR_128BIT_KEY + 3 + 2; + +namespace vcl::pdf +{ + +enum class GraphicsStateUpdateFlags { + Font = 0x0001, + MapMode = 0x0002, + LineColor = 0x0004, + FillColor = 0x0008, + ClipRegion = 0x0040, + LayoutMode = 0x0100, + TransparentPercent = 0x0200, + DigitLanguage = 0x0400, + All = 0x077f +}; + +} // end vcl::pdf + +namespace o3tl { + template<> struct typed_flags<vcl::pdf::GraphicsStateUpdateFlags> : is_typed_flags<vcl::pdf::GraphicsStateUpdateFlags, 0x077f> {}; +} + +namespace vcl +{ + +using namespace vcl::pdf; + +class PDFStreamIf; + +namespace filter +{ +class PDFObjectElement; +} + +namespace pdf +{ +struct PDFPage +{ + VclPtr<PDFWriterImpl> m_pWriter; + double m_nPageWidth; // in inch/72 + double m_nPageHeight; // in inch/72 + /** + * A positive number that gives the size of default user space units, in multiples of points. + * Typically 1, larger if page size is > 508 cm. + */ + sal_Int32 m_nUserUnit; + PDFWriter::Orientation m_eOrientation; + sal_Int32 m_nPageObject; + std::vector<sal_Int32> m_aStreamObjects; + sal_Int32 m_nStreamLengthObject; + sal_uInt64 m_nBeginStreamPos; + std::vector<sal_Int32> m_aAnnotations; + std::vector<sal_Int32> m_aMCIDParents; + PDFWriter::PageTransition m_eTransition; + sal_uInt32 m_nTransTime; + + PDFPage( PDFWriterImpl* pWriter, double nPageWidth, double nPageHeight, PDFWriter::Orientation eOrientation ); + + void beginStream(); + void endStream(); + bool emit( sal_Int32 nParentPage ); + + // converts point from ref device coordinates to + // page coordinates and appends the point to the buffer + // if pOutPoint is set it will be updated to the emitted point + // (in PDF map mode, that is 10th of point) + void appendPoint( const Point& rPoint, OStringBuffer& rBuffer ) const; + // appends a B2DPoint without further transformation + void appendPixelPoint( const basegfx::B2DPoint& rPoint, OStringBuffer& rBuffer ) const; + // appends a rectangle + void appendRect( const tools::Rectangle& rRect, OStringBuffer& rBuffer ) const; + // converts a rectangle to 10th points page space + void convertRect( tools::Rectangle& rRect ) const; + // appends a polygon optionally closing it + void appendPolygon( const tools::Polygon& rPoly, OStringBuffer& rBuffer, bool bClose = true ) const; + // appends a polygon optionally closing it + void appendPolygon( const basegfx::B2DPolygon& rPoly, OStringBuffer& rBuffer ) const; + // appends a polypolygon optionally closing the subpaths + void appendPolyPolygon( const tools::PolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const; + // appends a polypolygon optionally closing the subpaths + void appendPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly, OStringBuffer& rBuffer ) const; + // converts a length (either vertical or horizontal; this + // can be important if the source MapMode is not + // symmetrical) to page length and appends it to the buffer + // if pOutLength is set it will be updated to the emitted length + // (in PDF map mode, that is 10th of point) + void appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32* pOutLength = nullptr ) const; + // the same for double values + void appendMappedLength( double fLength, OStringBuffer& rBuffer, bool bVertical = true, sal_Int32 nPrecision = 5 ) const; + // appends LineInfo + // returns false if too many dash array entry were created for + // the implementation limits of some PDF readers + bool appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer ) const; + // appends a horizontal waveline with vertical offset (helper for drawWaveLine) + void appendWaveLine( sal_Int32 nLength, sal_Int32 nYOffset, sal_Int32 nDelta, OStringBuffer& rBuffer ) const; + + void appendMatrix3(Matrix3 const & rMatrix, OStringBuffer& rBuffer); + + double getHeight() const; +}; + +/// Contains information to emit a reference XObject. +struct ReferenceXObjectEmit +{ + /// ID of the Form XObject, if any. + sal_Int32 m_nFormObject; + /// ID of the vector/embedded object, if m_nFormObject is used. + sal_Int32 m_nEmbeddedObject; + /// ID of the bitmap object, if m_nFormObject is used. + sal_Int32 m_nBitmapObject; + /// Size of the bitmap replacement, in pixels. + Size m_aPixelSize; + /// PDF data from the graphic object, if not writing a reference XObject. + sal_Int32 m_nExternalPDFDataIndex; + sal_Int32 m_nExternalPDFPageIndex; + + ReferenceXObjectEmit() + : m_nFormObject(0) + , m_nEmbeddedObject(0) + , m_nBitmapObject(0) + , m_nExternalPDFDataIndex(-1) + , m_nExternalPDFPageIndex(-1) + { + } + + /// Returns the ID one should use when referring to this bitmap. + sal_Int32 getObject() const; + + bool hasExternalPDFData() const + { + return m_nExternalPDFDataIndex >= 0; + } +}; + +struct BitmapEmit +{ + BitmapID m_aID; + BitmapEx m_aBitmap; + sal_Int32 m_nObject; + ReferenceXObjectEmit m_aReferenceXObject; + + BitmapEmit() + : m_nObject(0) + { + } +}; + +struct JPGEmit +{ + BitmapID m_aID; + std::unique_ptr<SvMemoryStream> + m_pStream; + AlphaMask m_aAlphaMask; + sal_Int32 m_nObject; + bool m_bTrueColor; + ReferenceXObjectEmit m_aReferenceXObject; + + JPGEmit() + : m_nObject(0) + , m_bTrueColor(false) + { + } +}; + +struct GradientEmit +{ + Gradient m_aGradient; + Size m_aSize; + sal_Int32 m_nObject; +}; + +// for tilings (drawWallpaper, begin/endPattern) +struct TilingEmit +{ + sal_Int32 m_nObject; + tools::Rectangle m_aRectangle; + Size m_aCellSize; + SvtGraphicFill::Transform m_aTransform; + ResourceDict m_aResources; + std::unique_ptr<SvMemoryStream> m_pTilingStream; + + TilingEmit() + : m_nObject( 0 ) + {} +}; + +// for transparency group XObjects +struct TransparencyEmit +{ + sal_Int32 m_nObject; + sal_Int32 m_nExtGStateObject; + double m_fAlpha; + tools::Rectangle m_aBoundRect; + std::unique_ptr<SvMemoryStream> m_pContentStream; + + TransparencyEmit() + : m_nObject( 0 ), + m_nExtGStateObject( -1 ), + m_fAlpha( 0.0 ) + {} +}; + +// font subsets + +struct ColorLayer +{ + sal_Int32 m_nFontID; + sal_uInt8 m_nSubsetGlyphID; + uint32_t m_nColorIndex; +}; + +class GlyphEmit +{ + // performance: actually this should probably a vector; + std::vector<sal_Ucs> m_CodeUnits; + sal_uInt8 m_nSubsetGlyphID; + sal_Int32 m_nGlyphWidth; + std::vector<ColorLayer> m_aColorLayers; + font::RawFontData m_aColorBitmap; + tools::Rectangle m_aRect; + basegfx::B2DPolyPolygon m_aOutline; + +public: + GlyphEmit() : m_nSubsetGlyphID(0), m_nGlyphWidth(0) + { + } + + void setGlyphId( sal_uInt8 i_nId ) { m_nSubsetGlyphID = i_nId; } + sal_uInt8 getGlyphId() const { return m_nSubsetGlyphID; } + + void setGlyphWidth( sal_Int32 nWidth ) { m_nGlyphWidth = nWidth; } + sal_Int32 getGlyphWidth() const { return m_nGlyphWidth; } + + void addColorLayer(ColorLayer aLayer) { m_aColorLayers.push_back(aLayer); } + const std::vector<ColorLayer>& getColorLayers() const { return m_aColorLayers; } + + void setColorBitmap(font::RawFontData aData, tools::Rectangle aRect) + { + m_aColorBitmap = aData; + m_aRect = aRect; + } + const font::RawFontData& getColorBitmap(tools::Rectangle& rRect) const + { + rRect = m_aRect; + return m_aColorBitmap; + } + + void setOutline(const basegfx::B2DPolyPolygon& rOutline) { m_aOutline = rOutline; } + const basegfx::B2DPolyPolygon& getOutline() const { return m_aOutline; } + + void addCode( sal_Ucs i_cCode ) + { + m_CodeUnits.push_back(i_cCode); + } + sal_Int32 countCodes() const { return m_CodeUnits.size(); } + const std::vector<sal_Ucs>& codes() const { return m_CodeUnits; } + sal_Ucs getCode( sal_Int32 i_nIndex ) const + { + sal_Ucs nRet = 0; + if (o3tl::make_unsigned(i_nIndex) < m_CodeUnits.size()) + nRet = m_CodeUnits[i_nIndex]; + return nRet; + } +}; + +struct FontEmit +{ + sal_Int32 m_nFontID; + std::map<sal_GlyphId, GlyphEmit> m_aMapping; + + explicit FontEmit( sal_Int32 nID ) : m_nFontID( nID ) {} +}; + +struct Glyph +{ + sal_Int32 m_nFontID; + sal_uInt8 m_nSubsetGlyphID; +}; + +struct FontSubset +{ + std::vector< FontEmit > m_aSubsets; + std::map<sal_GlyphId, Glyph> m_aMapping; +}; + +struct EmbedFont +{ + sal_Int32 m_nNormalFontID; + LogicalFontInstance* m_pFontInstance; + + EmbedFont() + : m_nNormalFontID(0) + , m_pFontInstance(nullptr) {} +}; + +struct PDFDest +{ + sal_Int32 m_nPage; + PDFWriter::DestAreaType m_eType; + tools::Rectangle m_aRect; +}; + +//--->i56629 +struct PDFNamedDest +{ + OUString m_aDestName; + sal_Int32 m_nPage; + PDFWriter::DestAreaType m_eType; + tools::Rectangle m_aRect; +}; + +struct PDFOutlineEntry +{ + sal_Int32 m_nObject; + sal_Int32 m_nParentObject; + sal_Int32 m_nNextObject; + sal_Int32 m_nPrevObject; + std::vector< sal_Int32 > m_aChildren; + OUString m_aTitle; + sal_Int32 m_nDestID; + + PDFOutlineEntry() + : m_nObject( 0 ), + m_nParentObject( 0 ), + m_nNextObject( 0 ), + m_nPrevObject( 0 ), + m_nDestID( -1 ) + {} +}; + +struct PDFAnnotation +{ + sal_Int32 m_nObject; + tools::Rectangle m_aRect; + sal_Int32 m_nPage; + + PDFAnnotation() + : m_nObject( -1 ), + m_nPage( -1 ) + {} +}; + +struct PDFLink : public PDFAnnotation +{ + sal_Int32 m_nDest; // set to -1 for URL, to a dest else + OUString m_aURL; + sal_Int32 m_nStructParent; // struct parent entry + OUString m_AltText; + + PDFLink(OUString const& rAltText) + : m_nDest( -1 ), + m_nStructParent( -1 ) + , m_AltText(rAltText) + {} +}; + +/// A PDF embedded file. +struct PDFEmbeddedFile +{ + /// ID of the file. + sal_Int32 m_nObject; + OUString m_aSubType; + /// Contents of the file. + BinaryDataContainer m_aDataContainer; + std::unique_ptr<PDFOutputStream> m_pStream; + + PDFEmbeddedFile() + : m_nObject(0) + { + } +}; + +struct PDFPopupAnnotation : public PDFAnnotation +{ + /// ID of the parent object. + sal_Int32 m_nParentObject; +}; + +struct PDFNoteEntry : public PDFAnnotation +{ + PDFNote m_aContents; + + PDFPopupAnnotation m_aPopUpAnnotation; + + PDFNoteEntry() + {} +}; + +/// A PDF Screen annotation. +struct PDFScreen : public PDFAnnotation +{ + /// Linked video. + OUString m_aURL; + /// Embedded video. + OUString m_aTempFileURL; + /// ID of the EmbeddedFile object. + sal_Int32 m_nTempFileObject; + /// alternative text description + OUString m_AltText; + sal_Int32 m_nStructParent; + OUString m_MimeType; + + PDFScreen(OUString const& rAltText, OUString const& rMimeType) + : m_nTempFileObject(0) + , m_AltText(rAltText) + , m_nStructParent(-1) + , m_MimeType(rMimeType) + { + } +}; + +struct PDFWidget : public PDFAnnotation +{ + PDFWriter::WidgetType m_eType; + OString m_aName; + OUString m_aDescription; + OUString m_aText; + DrawTextFlags m_nTextStyle; + OUString m_aValue; + OString m_aDAString; + OString m_aDRDict; + OString m_aMKDict; + OString m_aMKDictCAString; // i12626, added to be able to encrypt the /CA text string + // since the object number is not known at the moment + // of filling m_aMKDict, the string will be encrypted when emitted. + // the /CA string MUST BE the last added to m_aMKDict + // see code for details + sal_Int32 m_nFlags; + sal_Int32 m_nParent; // if not 0, parent's object number + std::vector<sal_Int32> m_aKids; // widget children, contains object numbers + std::vector<sal_Int32> m_aKidsIndex; // widget children, contains index to m_aWidgets + OUString m_aOnValue; + OUString m_aOffValue; + sal_Int32 m_nTabOrder; // lowest number gets first in tab order + sal_Int32 m_nRadioGroup; + sal_Int32 m_nMaxLen; + PDFWriter::FormatType m_nFormat; + OUString m_aCurrencySymbol; + sal_Int32 m_nDecimalAccuracy; + bool m_bPrependCurrencySymbol; + OUString m_aTimeFormat; + OUString m_aDateFormat; + bool m_bSubmit; + bool m_bSubmitGet; + sal_Int32 m_nDest; + std::vector<OUString> m_aListEntries; + std::vector<sal_Int32> m_aSelectedEntries; + typedef std::unordered_map<OString, SvMemoryStream*> PDFAppearanceStreams; + std::unordered_map<OString, PDFAppearanceStreams> m_aAppearances; + sal_Int32 m_nStructParent = -1; + + PDFWidget() + : m_eType( PDFWriter::PushButton ), + m_nTextStyle( DrawTextFlags::NONE ), + m_nFlags( 0 ), + m_nParent( 0 ), + m_nTabOrder( 0 ), + m_nRadioGroup( -1 ), + m_nMaxLen( 0 ), + m_nFormat( PDFWriter::FormatType::Text ), + m_nDecimalAccuracy ( 0 ), + m_bPrependCurrencySymbol( false ), + m_bSubmit( false ), + m_bSubmitGet( false ), + m_nDest( -1 ) + {} +}; + +struct PDFStructureAttribute +{ + PDFWriter::StructAttributeValue eValue; + sal_Int32 nValue; + + PDFStructureAttribute() + : eValue( PDFWriter::Invalid ), + nValue( 0 ) + {} + + explicit PDFStructureAttribute( PDFWriter::StructAttributeValue eVal ) + : eValue( eVal ), + nValue( 0 ) + {} + + explicit PDFStructureAttribute( sal_Int32 nVal ) + : eValue( PDFWriter::Invalid ), + nValue( nVal ) + {} +}; + +struct ObjReference { sal_Int32 const nObject; }; +struct ObjReferenceObj { sal_Int32 const nObject; }; +struct MCIDReference { sal_Int32 const nPageObj; sal_Int32 const nMCID; }; +typedef ::std::variant<ObjReference, ObjReferenceObj, MCIDReference> PDFStructureElementKid; + +struct PDFStructureElement +{ + sal_Int32 m_nObject; + ::std::optional<PDFWriter::StructElement> m_oType; + OString m_aAlias; + sal_Int32 m_nOwnElement; // index into structure vector + sal_Int32 m_nParentElement; // index into structure vector + sal_Int32 m_nFirstPageObject; + bool m_bOpenMCSeq; + std::vector< sal_Int32 > m_aChildren; // indexes into structure vector + std::list< PDFStructureElementKid > m_aKids; + std::map<PDFWriter::StructAttribute, PDFStructureAttribute > + m_aAttributes; + ::std::vector<sal_Int32> m_AnnotIds; + tools::Rectangle m_aBBox; + OUString m_aActualText; + OUString m_aAltText; + css::lang::Locale m_aLocale; + + // m_aContents contains the element's marked content sequence + // as pairs of (page nr, MCID) + + PDFStructureElement() + : m_nObject( 0 ), + m_nOwnElement( -1 ), + m_nParentElement( -1 ), + m_nFirstPageObject( 0 ), + m_bOpenMCSeq( false ) + { + } + +}; + +// helper structure for drawLayout and friends +struct PDFGlyph +{ + basegfx::B2DPoint const m_aPos; + const GlyphItem* m_pGlyph; + const LogicalFontInstance* m_pFont; + sal_Int32 const m_nNativeWidth; + sal_Int32 const m_nMappedFontId; + sal_uInt8 const m_nMappedGlyphId; + int const m_nCharPos; + + PDFGlyph( const basegfx::B2DPoint& rPos, + const GlyphItem* pGlyph, + const LogicalFontInstance* pFont, + sal_Int32 nNativeWidth, + sal_Int32 nFontId, + sal_uInt8 nMappedGlyphId, + int nCharPos ) + : m_aPos( rPos ), m_pGlyph(pGlyph), m_pFont(pFont), m_nNativeWidth( nNativeWidth ), + m_nMappedFontId( nFontId ), m_nMappedGlyphId( nMappedGlyphId ), + m_nCharPos(nCharPos) + {} +}; + +struct StreamRedirect +{ + SvStream* m_pStream; + MapMode m_aMapMode; + tools::Rectangle m_aTargetRect; + ResourceDict m_aResourceDict; +}; + +// graphics state +struct GraphicsState +{ + vcl::Font m_aFont; + MapMode m_aMapMode; + Color m_aLineColor; + Color m_aFillColor; + Color m_aTextLineColor; + Color m_aOverlineColor; + basegfx::B2DPolyPolygon m_aClipRegion; + bool m_bClipRegion; + vcl::text::ComplexTextLayoutFlags m_nLayoutMode; + LanguageType m_aDigitLanguage; + PushFlags m_nFlags; + GraphicsStateUpdateFlags m_nUpdateFlags; + + GraphicsState() : + m_aLineColor( COL_TRANSPARENT ), + m_aFillColor( COL_TRANSPARENT ), + m_aTextLineColor( COL_TRANSPARENT ), + m_aOverlineColor( COL_TRANSPARENT ), + m_bClipRegion( false ), + m_nLayoutMode( vcl::text::ComplexTextLayoutFlags::Default ), + m_aDigitLanguage( 0 ), + m_nFlags( PushFlags::ALL ), + m_nUpdateFlags( GraphicsStateUpdateFlags::All ) + {} +}; + +enum class Mode { DEFAULT, NOWRITE }; + +struct PDFDocumentAttachedFile +{ + OUString maFilename; + OUString maMimeType; + OUString maDescription; + sal_Int32 mnEmbeddedFileObjectId; + sal_Int32 mnObjectId; +}; + +} // end pdf namespace + +class PDFWriterImpl final : public VirtualDevice, public PDFObjectContainer +{ + friend class PDFStreamIf; + +public: + friend struct vcl::pdf::PDFPage; + + const char* getStructureTag( PDFWriter::StructElement ); + static const char* getAttributeTag( PDFWriter::StructAttribute eAtr ); + static const char* getAttributeValueTag( PDFWriter::StructAttributeValue eVal ); + + // returns true if compression was done + // else false + static bool compressStream( SvMemoryStream* ); + + static void convertLineInfoToExtLineInfo( const LineInfo& rIn, PDFWriter::ExtLineInfo& rOut ); + +private: + bool ImplNewFont() const override; + void ImplClearFontData(bool bNewFontLists) override; + void ImplRefreshFontData(bool bNewFontLists) override; + vcl::Region ClipToDeviceBounds(vcl::Region aRegion) const override; + void DrawHatchLine_DrawLine(const Point& rStartPoint, const Point& rEndPoint) override; + + MapMode m_aMapMode; // PDFWriterImpl scaled units + StyleSettings m_aWidgetStyleSettings; + std::vector< PDFPage > m_aPages; + /* maps object numbers to file offsets (needed for xref) */ + std::vector< sal_uInt64 > m_aObjects; + /* contains Bitmaps until they are written to the + * file stream as XObjects*/ + std::list< BitmapEmit > m_aBitmaps; + /* contains JPG streams until written to file */ + std::vector<JPGEmit> m_aJPGs; + /*--->i56629 contains all named destinations ever set during the PDF creation, + destination id is always the destination's position in this vector + */ + std::vector<PDFNamedDest> m_aNamedDests; + /* contains all dests ever set during the PDF creation, + dest id is always the dest's position in this vector + */ + std::vector<PDFDest> m_aDests; + /** contains destinations accessible via a public Id, instead of being linked to by an ordinary link + */ + ::std::map< sal_Int32, sal_Int32 > m_aDestinationIdTranslation; + /* contains all links ever set during PDF creation, + link id is always the link's position in this vector + */ + std::vector<PDFLink> m_aLinks; + /// Contains all screen annotations. + std::vector<PDFScreen> m_aScreens; + /// Contains embedded files. + std::vector<PDFEmbeddedFile> m_aEmbeddedFiles; + + std::vector<PDFDocumentAttachedFile> m_aDocumentAttachedFiles; + + /* makes correctly encoded for export to PDF URLS + */ + css::uno::Reference< css::util::XURLTransformer > m_xTrans; + /* maps arbitrary link ids for structure attributes to real link ids + (for setLinkPropertyId) + */ + std::map<sal_Int32, sal_Int32> m_aLinkPropertyMap; + /* contains all outline items, + object 0 is the outline root + */ + std::vector<PDFOutlineEntry> m_aOutline; + /* contains all notes set during PDF creation + */ + std::vector<PDFNoteEntry> m_aNotes; + /* the root of the structure tree + */ + std::vector<PDFStructureElement> m_aStructure; + /* current object in the structure hierarchy + */ + sal_Int32 m_nCurrentStructElement; + std::stack<sal_Int32> m_StructElementStack; + /* structure parent tree */ + std::vector< OString > m_aStructParentTree; + /* emit structure marks currently (aka. NonStructElement or not) + */ + bool m_bEmitStructure; + /* role map of struct tree root */ + std::unordered_map< OString, OString > + m_aRoleMap; + /* structure elements (object ids) that should have ID */ + std::unordered_set<sal_Int32> m_StructElemObjsWithID; + + /* contains all widgets used in the PDF + */ + std::vector<PDFWidget> m_aWidgets; + /* maps radio group id to index of radio group control in m_aWidgets */ + std::map< sal_Int32, sal_Int32 > m_aRadioGroupWidgets; + /* unordered_map for field names, used to ensure unique field names */ + std::unordered_map< OString, sal_Int32 > m_aFieldNameMap; + + /* contains Bitmaps for gradient functions until they are written + * to the file stream */ + std::list< GradientEmit > m_aGradients; + /* contains bitmap tiling patterns */ + std::vector< TilingEmit > m_aTilings; + std::vector< TransparencyEmit > m_aTransparentObjects; + /* contains all font subsets in use */ + std::map<const vcl::font::PhysicalFontFace*, FontSubset> m_aSubsets; + std::map<const vcl::font::PhysicalFontFace*, EmbedFont> m_aSystemFonts; + std::map<const vcl::font::PhysicalFontFace*, FontSubset> m_aType3Fonts; + sal_Int32 m_nNextFID; + + /// Cache some most recent bitmaps we've exported, in case we encounter them again.. + o3tl::lru_map<BitmapChecksum, + std::shared_ptr<SvMemoryStream>> m_aPDFBmpCache; + + sal_Int32 m_nCurrentPage; + + sal_Int32 m_nCatalogObject; + // object number of the main signature dictionary + sal_Int32 m_nSignatureObject; + sal_Int64 m_nSignatureContentOffset; + sal_Int64 m_nSignatureLastByteRangeNoOffset; + sal_Int32 m_nResourceDict; + ResourceDict m_aGlobalResourceDict; + sal_Int32 m_nFontDictObject; + std::map< sal_Int32, sal_Int32 > m_aBuildinFontToObjectMap; + + PDFWriter::PDFWriterContext m_aContext; + osl::File m_aFile; + bool m_bOpen; + + ExternalPDFStreams m_aExternalPDFStreams; + + /* output redirection; e.g. to accumulate content streams for + XObjects + */ + std::list< StreamRedirect > m_aOutputStreams; + + std::list< GraphicsState > m_aGraphicsStack; + GraphicsState m_aCurrentPDFState; + + std::unique_ptr<ZCodec> m_pCodec; + std::unique_ptr<SvMemoryStream> m_pMemStream; + + std::set< PDFWriter::ErrorCode > m_aErrors; + + ::comphelper::Hash m_DocDigest; + + sal_uInt64 getCurrentFilePosition() + { + sal_uInt64 nPosition{}; + if (osl::File::E_None != m_aFile.getPos(nPosition)) + { + m_aFile.close(); + m_bOpen = false; + } + return nPosition; + } +/* +variables for PDF security +i12626 +*/ +/* used to cipher the stream data and for password management */ + rtlCipher m_aCipher; + /* pad string used for password in Standard security handler */ + static const sal_uInt8 s_nPadString[ENCRYPTED_PWD_SIZE]; + + /* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2 + for 128 bit security */ + sal_Int32 m_nKeyLength; // key length, 16 or 5 + sal_Int32 m_nRC4KeyLength; // key length, 16 or 10, to be input to the algorithm 3.1 + + /* set to true if the following stream must be encrypted, used inside writeBuffer() */ + bool m_bEncryptThisStream; + + /* the numerical value of the access permissions, according to PDF spec, must be signed */ + sal_Int32 m_nAccessPermissions; + /* string to hold the PDF creation date */ + OString m_aCreationDateString; + /* string to hold the PDF creation date, for PDF/A metadata */ + OString m_aCreationMetaDateString; + /* the buffer where the data are encrypted, dynamically allocated */ + std::vector<sal_uInt8> m_vEncryptionBuffer; + + void addRoleMap(OString aAlias, PDFWriter::StructElement eType); + + /* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ + void checkAndEnableStreamEncryption( sal_Int32 nObject ) override; + + void disableStreamEncryption() override { m_bEncryptThisStream = false; }; + + /* */ + void enableStringEncryption( sal_Int32 nObject ); + +// test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter + void appendUnicodeTextStringEncrypt( const OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ); + + void appendLiteralStringEncrypt( std::u16string_view rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer, rtl_TextEncoding nEnc = RTL_TEXTENCODING_ASCII_US ); + void appendLiteralStringEncrypt( std::string_view rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ); + + /* creates fonts and subsets that will be emitted later */ + void registerGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const LogicalFontInstance* pFont, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&); + void registerSimpleGlyph(const sal_GlyphId, const vcl::font::PhysicalFontFace*, const std::vector<sal_Ucs>&, sal_Int32, sal_uInt8&, sal_Int32&); + + /* emits a text object according to the passed layout */ + /* TODO: remove rText as soon as SalLayout will change so that rText is not necessary anymore */ + void drawVerticalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, const Matrix3& rRotScale, double fAngle, double fXScale, sal_Int32 nFontHeight ); + void drawHorizontalGlyphs( const std::vector<PDFGlyph>& rGlyphs, OStringBuffer& rLine, const Point& rAlignOffset, bool bFirst, double fAngle, double fXScale, sal_Int32 nFontHeight, sal_Int32 nPixelFontHeight ); + void drawLayout( SalLayout& rLayout, const OUString& rText, bool bTextLines ); + void drawRelief( SalLayout& rLayout, const OUString& rText, bool bTextLines ); + void drawShadow( SalLayout& rLayout, const OUString& rText, bool bTextLines ); + + /* writes differences between graphics stack and current real PDF + * state to the file + */ + void updateGraphicsState(Mode mode = Mode::DEFAULT); + + /* writes a transparency group object */ + void writeTransparentObject( TransparencyEmit& rObject ); + + /* writes an XObject of type image, may create + a second for the mask + */ + bool writeBitmapObject( const BitmapEmit& rObject, bool bMask = false ); + + void writeJPG( const JPGEmit& rEmit ); + /// Writes the form XObject proxy for the image. + void writeReferenceXObject(const ReferenceXObjectEmit& rEmit); + + /* tries to find the bitmap by its id and returns its emit data if exists, + else creates a new emit data block */ + const BitmapEmit& createBitmapEmit( const BitmapEx& rBitmapEx, const Graphic& rGraphic, std::list<BitmapEmit>& rBitmaps, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams ); + const BitmapEmit& createBitmapEmit( const BitmapEx& rBitmapEx, const Graphic& rGraphic ); + + /* writes the Do operation inside the content stream */ + void drawBitmap( const Point& rDestPt, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor ); + /* write the function object for a Gradient */ + bool writeGradientFunction( GradientEmit const & rObject ); + /* creates a GradientEmit and returns its object number */ + sal_Int32 createGradient( const Gradient& rGradient, const Size& rSize ); + + /* writes all tilings */ + bool emitTilings(); + /* writes all gradient patterns */ + bool emitGradients(); + /* writes a builtin font object and returns its objectid (or 0 in case of failure ) */ + sal_Int32 emitBuildinFont( const pdf::BuildinFontFace*, sal_Int32 nObject ); + /* writes a type1 system font object and returns its mapping from font ids to object ids (or 0 in case of failure ) */ + std::map< sal_Int32, sal_Int32 > emitSystemFont(const vcl::font::PhysicalFontFace*, EmbedFont const &); + /* writes a type3 font object and appends it to the font id mapping, or returns false in case of failure */ + bool emitType3Font(const vcl::font::PhysicalFontFace*, const FontSubset&, std::map<sal_Int32, sal_Int32>&); + /* writes a font descriptor and returns its object id (or 0) */ + sal_Int32 emitFontDescriptor(const vcl::font::PhysicalFontFace*, FontSubsetInfo const &, sal_Int32 nSubsetID, sal_Int32 nStream); + /* writes a ToUnicode cmap, returns the corresponding stream object */ + sal_Int32 createToUnicodeCMap( sal_uInt8 const * pEncoding, const std::vector<sal_Ucs>& CodeUnits, const sal_Int32* pCodeUnitsPerGlyph, + const sal_Int32* pEncToUnicodeIndex, uint32_t nGlyphs ); + + /* get resource dict object number */ + sal_Int32 getResourceDictObj() + { + if( m_nResourceDict <= 0 ) + m_nResourceDict = createObject(); + return m_nResourceDict; + } + /* get the font dict object */ + sal_Int32 getFontDictObject() + { + if( m_nFontDictObject <= 0 ) + m_nFontDictObject = createObject(); + return m_nFontDictObject; + } + /* push resource into current (redirected) resource dict */ + static void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject, ResourceDict& rResourceDict, std::list<StreamRedirect>& rOutputStreams ); + void pushResource( ResourceKind eKind, const OString& rResource, sal_Int32 nObject ); + + void appendBuildinFontsToDict( OStringBuffer& rDict ) const; + /* writes the font dictionary and emits all font objects + * returns object id of font directory (or 0 on error) + */ + bool emitFonts(); + /* writes the Resource dictionary; + * returns dict object id (or 0 on error) + */ + sal_Int32 emitResources(); + // appends a dest + bool appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer ); + // write all links + bool emitLinkAnnotations(); + // Write all screen annotations. + bool emitScreenAnnotations(); + + void emitTextAnnotationLine(OStringBuffer & aLine, PDFNoteEntry const & rNote); + static void emitPopupAnnotationLine(OStringBuffer & aLine, PDFPopupAnnotation const & rPopUp); + // write all notes + bool emitNoteAnnotations(); + + // write the appearance streams of a widget + bool emitAppearances( PDFWidget& rWidget, OStringBuffer& rAnnotDict ); + // clean up radio button "On" values + void ensureUniqueRadioOnValues(); + // write all widgets + bool emitWidgetAnnotations(); + // writes all annotation objects + bool emitAnnotations(); + /// Writes embedded files. + bool emitEmbeddedFiles(); + //write the named destination stuff + sal_Int32 emitNamedDestinations();//i56629 + // writes outline dict and tree + sal_Int32 emitOutline(); + template<typename T> void AppendAnnotKid(PDFStructureElement& i_rEle, T & rAnnot); + // puts the attribute objects of a structure element into the returned string, + // helper for emitStructure + OString emitStructureAttributes( PDFStructureElement& rEle ); + //--->i94258 + // the maximum array elements allowed for PDF array object + static const sal_uInt32 ncMaxPDFArraySize = 8191; + //check if internal dummy container are needed in the structure elements + void addInternalStructureContainer( PDFStructureElement& rEle ); + //<---i94258 + // writes document structure + sal_Int32 emitStructure( PDFStructureElement& rEle ); + // writes structure parent tree + sal_Int32 emitStructParentTree( sal_Int32 nTreeObject ); + // writes structure IDTree + sal_Int32 emitStructIDTree(sal_Int32 nTreeObject); + // writes page tree and catalog + bool emitCatalog(); + // writes signature dictionary object + bool emitSignature(); + // creates a PKCS7 object using the ByteRange and overwrite /Contents + // of the signature dictionary + bool finalizeSignature(); + // writes xref and trailer + bool emitTrailer(); + // emits info dict (if applicable) + sal_Int32 emitInfoDict( ); + + // acrobat reader 5 and 6 use the order of the annotations + // as their tab order; since PDF1.5 one can make the + // tab order explicit by using the structure tree + void sortWidgets(); + + // updates the count numbers of outline items + sal_Int32 updateOutlineItemCount( std::vector< sal_Int32 >& rCounts, + sal_Int32 nItemLevel, + sal_Int32 nCurrentItemId ); + // default appearances for widgets + sal_Int32 findRadioGroupWidget( const PDFWriter::RadioButtonWidget& rRadio ); + Font replaceFont( const Font& rControlFont, const Font& rAppSetFont ); + sal_Int32 getBestBuildinFont( const Font& rFont ); + sal_Int32 getSystemFont( const Font& i_rFont ); + + // used for edit and listbox + Font drawFieldBorder( PDFWidget&, const PDFWriter::AnyWidget&, const StyleSettings& ); + + void createDefaultPushButtonAppearance( PDFWidget&, const PDFWriter::PushButtonWidget& rWidget ); + void createDefaultCheckBoxAppearance( PDFWidget&, const PDFWriter::CheckBoxWidget& rWidget ); + void createDefaultRadioButtonAppearance( PDFWidget&, const PDFWriter::RadioButtonWidget& rWidget ); + void createDefaultEditAppearance( PDFWidget&, const PDFWriter::EditWidget& rWidget ); + void createDefaultListBoxAppearance( PDFWidget&, const PDFWriter::ListBoxWidget& rWidget ); + + /* ensure proper escapement and uniqueness of field names */ + void createWidgetFieldName( sal_Int32 i_nWidgetsIndex, const PDFWriter::AnyWidget& i_rInWidget ); + /// See vcl::PDFObjectContainer::createObject(). + sal_Int32 createObject() override; + /// See vcl::PDFObjectContainer::updateObject(). + bool updateObject( sal_Int32 n ) override; + + /// See vcl::PDFObjectContainer::writeBuffer(). + bool writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes ) override; + void beginCompression(); + void endCompression(); + void beginRedirect( SvStream* pStream, const tools::Rectangle& ); + SvStream* endRedirect(); + + void endPage(); + + void beginStructureElementMCSeq(); + enum class EndMode { Default, OnlyStruct }; + void endStructureElementMCSeq(EndMode = EndMode::Default); + /** checks whether a non struct element lies in the ancestor hierarchy + of the current structure element + + @returns + true if no NonStructElement was found in ancestor path and tagged + PDF output is enabled + false else + */ + bool checkEmitStructure(); + + /* draws an emphasis mark */ + void drawEmphasisMark( tools::Long nX, tools::Long nY, const tools::PolyPolygon& rPolyPoly, bool bPolyLine, const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 ); + + /* true if PDF/A-1a or PDF/A-1b is output */ + bool m_bIsPDF_A1; + /* true if PDF/A-2a is output */ + bool m_bIsPDF_A2; + + /* PDF/UA support enabled */ + bool m_bIsPDF_UA; + + bool m_bIsPDF_A3; + + PDFWriter& m_rOuterFace; + + /* + i12626 + methods for PDF security + + pad a password according algorithm 3.2, step 1 */ + static void padPassword( std::u16string_view i_rPassword, sal_uInt8* o_pPaddedPW ); + /* algorithm 3.2: compute an encryption key */ + static bool computeEncryptionKey( EncHashTransporter*, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nAccessPermissions + ); + /* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */ + static bool computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, const sal_uInt8* i_pPaddedUserPassword, + std::vector< sal_uInt8 >& io_rOValue, + sal_Int32 i_nKeyLength + ); + /* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */ + static bool computeUDictionaryValue( EncHashTransporter* i_pTransporter, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, + sal_Int32 i_nAccessPermissions + ); + + static void computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, + const OString& i_rCString1, + const css::util::DateTime& rCreationMetaDate, + OString& o_rCString2 + ); + static sal_Int32 computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, + sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ); + void setupDocInfo(); + bool prepareEncryption( const css::uno::Reference< css::beans::XMaterialHolder >& ); + + // helper for playMetafile + void implWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, + VirtualDevice* pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); + void implWriteBitmapEx( const Point& rPoint, const Size& rSize, const BitmapEx& rBitmapEx, const Graphic& i_pGraphic, + VirtualDevice const * pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); + + // helpers for CCITT 1bit bitmap stream + void putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState ); + void putG4Span( tools::Long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState ); + void writeG4Stream( BitmapReadAccess const * i_pBitmap ); + + // color helper functions + void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer ); + void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer ); +public: + PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, const css::uno::Reference< css::beans::XMaterialHolder >&, PDFWriter& ); + ~PDFWriterImpl() override; + void dispose() override; + + static css::uno::Reference< css::beans::XMaterialHolder > + initEncryption( const OUString& i_rOwnerPassword, + const OUString& i_rUserPassword ); + + /* document structure */ + void newPage( double nPageWidth , double nPageHeight, PDFWriter::Orientation eOrientation ); + bool emit(); + const std::set< PDFWriter::ErrorCode > & getErrors() const { return m_aErrors;} + void insertError( PDFWriter::ErrorCode eErr ) { m_aErrors.insert( eErr ); } + void playMetafile( const GDIMetaFile&, vcl::PDFExtOutDevData*, const vcl::PDFWriter::PlayMetafileContext&, VirtualDevice* pDummyDev = nullptr ); + + Size getCurPageSize() const + { + Size aSize; + if( m_nCurrentPage >= 0 && o3tl::make_unsigned(m_nCurrentPage) < m_aPages.size() ) + aSize = Size( m_aPages[ m_nCurrentPage ].m_nPageWidth, m_aPages[ m_nCurrentPage ].m_nPageHeight ); + return aSize; + } + + void setDocumentLocale( const css::lang::Locale& rLoc ) + { m_aContext.DocumentLocale = rLoc; } + + /* graphics state */ + void push( PushFlags nFlags ); + void pop(); + + void setFont( const Font& rFont ); + + void setMapMode( const MapMode& rMapMode ); + + const MapMode& getMapMode() { return m_aGraphicsStack.front().m_aMapMode; } + + void setLineColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aLineColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor; + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LineColor; + } + + void setFillColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aFillColor = rColor.IsTransparent() ? COL_TRANSPARENT : rColor; + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::FillColor; + } + + void setTextLineColor() + { + m_aGraphicsStack.front().m_aTextLineColor = COL_TRANSPARENT; + } + + void setTextLineColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aTextLineColor = rColor; + } + + void setOverlineColor() + { + m_aGraphicsStack.front().m_aOverlineColor = COL_TRANSPARENT; + } + + void setOverlineColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aOverlineColor = rColor; + } + + void setTextFillColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aFont.SetFillColor( rColor ); + m_aGraphicsStack.front().m_aFont.SetTransparent( rColor.IsTransparent() ); + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; + } + void setTextFillColor() + { + m_aGraphicsStack.front().m_aFont.SetFillColor( COL_TRANSPARENT ); + m_aGraphicsStack.front().m_aFont.SetTransparent( true ); + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; + } + void setTextColor( const Color& rColor ) + { + m_aGraphicsStack.front().m_aFont.SetColor( rColor ); + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; + } + + void clearClipRegion() + { + m_aGraphicsStack.front().m_aClipRegion.clear(); + m_aGraphicsStack.front().m_bClipRegion = false; + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::ClipRegion; + } + + void setClipRegion( const basegfx::B2DPolyPolygon& rRegion ); + + void moveClipRegion( sal_Int32 nX, sal_Int32 nY ); + + void intersectClipRegion( const tools::Rectangle& rRect ); + + void intersectClipRegion( const basegfx::B2DPolyPolygon& rRegion ); + + void setLayoutMode( vcl::text::ComplexTextLayoutFlags nLayoutMode ) + { + m_aGraphicsStack.front().m_nLayoutMode = nLayoutMode; + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::LayoutMode; + } + + void setDigitLanguage( LanguageType eLang ) + { + m_aGraphicsStack.front().m_aDigitLanguage = eLang; + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::DigitLanguage; + } + + void setTextAlign( TextAlign eAlign ) + { + m_aGraphicsStack.front().m_aFont.SetAlignment( eAlign ); + m_aGraphicsStack.front().m_nUpdateFlags |= GraphicsStateUpdateFlags::Font; + } + + /* actual drawing functions */ + void drawText( const Point& rPos, const OUString& rText, sal_Int32 nIndex, sal_Int32 nLen, bool bTextLines = true ); + void drawTextArray( const Point& rPos, const OUString& rText, KernArraySpan pDXArray, std::span<const sal_Bool> pKashidaArray, sal_Int32 nIndex, sal_Int32 nLen ); + void drawStretchText( const Point& rPos, sal_Int32 nWidth, const OUString& rText, + sal_Int32 nIndex, sal_Int32 nLen ); + void drawText( const tools::Rectangle& rRect, const OUString& rOrigStr, DrawTextFlags nStyle ); + void drawTextLine( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout, FontLineStyle eUnderline, FontLineStyle eOverline, bool bUnderlineAbove ); + void drawWaveTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove ); + void drawStraightTextLine( OStringBuffer& aLine, tools::Long nWidth, FontLineStyle eTextLine, Color aColor, bool bIsAbove ); + void drawStrikeoutLine( OStringBuffer& aLine, tools::Long nWidth, FontStrikeout eStrikeout, Color aColor ); + void drawStrikeoutChar( const Point& rPos, tools::Long nWidth, FontStrikeout eStrikeout ); + + void drawLine( const Point& rStart, const Point& rStop ); + void drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo ); + void drawPolygon( const tools::Polygon& rPoly ); + void drawPolyPolygon( const tools::PolyPolygon& rPolyPoly ); + void drawPolyLine( const tools::Polygon& rPoly ); + void drawPolyLine( const tools::Polygon& rPoly, const LineInfo& rInfo ); + void drawPolyLine( const tools::Polygon& rPoly, const PDFWriter::ExtLineInfo& rInfo ); + + void drawPixel( const Point& rPt, const Color& rColor ); + + void drawRectangle( const tools::Rectangle& rRect ); + void drawRectangle( const tools::Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound ); + void drawEllipse( const tools::Rectangle& rRect ); + void drawArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWidthChord ); + + void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Graphic& rGraphic ); + void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap ); + void drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const Size& rSizePixel, const tools::Rectangle& rTargetArea, const AlphaMask& rAlphaMask, const Graphic& rGraphic ); + /// Stores the original PDF data from rGraphic as an embedded file. + void createEmbeddedFile(const Graphic& rGraphic, ReferenceXObjectEmit& rEmit, sal_Int32 nBitmapObject); + + void drawGradient( const tools::Rectangle& rRect, const Gradient& rGradient ); + void drawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch ); + void drawWallpaper( const tools::Rectangle& rRect, const Wallpaper& rWall ); + void drawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent ); + void beginTransparencyGroup(); + void endTransparencyGroup( const tools::Rectangle& rBoundingBox, sal_uInt32 nTransparentPercent ); + + void emitComment( const char* pComment ); + + //--->i56629 named destinations + sal_Int32 createNamedDest( const OUString& sDestName, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); + + //--->i59651 + //emits output intent + sal_Int32 emitOutputIntent(); + + //emits the document metadata + sal_Int32 emitDocumentMetadata(); + + // links + sal_Int32 createLink(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText); + sal_Int32 createDest( const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); + sal_Int32 registerDestReference( sal_Int32 nDestId, const tools::Rectangle& rRect, sal_Int32 nPageNr, PDFWriter::DestAreaType eType ); + void setLinkDest( sal_Int32 nLinkId, sal_Int32 nDestId ); + void setLinkURL( sal_Int32 nLinkId, const OUString& rURL ); + void setLinkPropertyId( sal_Int32 nLinkId, sal_Int32 nPropertyId ); + + // screens + sal_Int32 createScreen(const tools::Rectangle& rRect, sal_Int32 nPageNr, OUString const& rAltText, OUString const& rMimeType); + void setScreenURL(sal_Int32 nScreenId, const OUString& rURL); + void setScreenStream(sal_Int32 nScreenId, const OUString& rURL); + + // outline + sal_Int32 createOutlineItem( sal_Int32 nParent, std::u16string_view rText, sal_Int32 nDestID ); + void setOutlineItemParent( sal_Int32 nItem, sal_Int32 nNewParent ); + void setOutlineItemText( sal_Int32 nItem, std::u16string_view rText ); + void setOutlineItemDest( sal_Int32 nItem, sal_Int32 nDestID ); + + // notes + void createNote( const tools::Rectangle& rRect, const PDFNote& rNote, sal_Int32 nPageNr ); + // structure elements + sal_Int32 ensureStructureElement(); + void initStructureElement(sal_Int32 id, PDFWriter::StructElement eType, std::u16string_view rAlias); + void beginStructureElement(sal_Int32 id); + void endStructureElement(); + bool setCurrentStructureElement( sal_Int32 nElement ); + bool setStructureAttribute( enum PDFWriter::StructAttribute eAttr, enum PDFWriter::StructAttributeValue eVal ); + bool setStructureAttributeNumerical( enum PDFWriter::StructAttribute eAttr, sal_Int32 nValue ); + void setStructureBoundingBox( const tools::Rectangle& rRect ); + void setStructureAnnotIds(::std::vector<sal_Int32> const& rAnnotIds); + void setActualText( const OUString& rText ); + void setAlternateText( const OUString& rText ); + + // transitional effects + void setPageTransition( PDFWriter::PageTransition eType, sal_uInt32 nMilliSec, sal_Int32 nPageNr ); + + // controls + sal_Int32 createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr = -1 ); + + // attached file + void addDocumentAttachedFile(OUString const& rFileName, OUString const& rMimeType, OUString const& rDescription, std::unique_ptr<PDFOutputStream> rStream); + + sal_Int32 addEmbeddedFile(BinaryDataContainer const & rDataContainer); + sal_Int32 addEmbeddedFile(std::unique_ptr<PDFOutputStream> rStream, OUString const& rMimeType); + + // helper: eventually begin marked content sequence and + // emit a comment in debug case + void MARK( const char* pString ); +}; + +} // namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |