external/afdko/extern_makeotf.patch | 29 +++++++++++++++++ include/vcl/filter/PDFiumLibrary.hxx | 14 ++++++++ svx/source/inc/svdpdf.hxx | 5 +++ svx/source/svdraw/svdpdf.cxx | 42 +++++++++++++++++-------- vcl/source/gdi/embeddedfontsafdko.cxx | 41 ++++++++++++++++-------- vcl/source/pdf/PDFiumLibrary.cxx | 56 ++++++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 28 deletions(-)
New commits: commit 9dc6687e8c2ae00f324b5ed11a557491844bb863 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Oct 28 15:17:58 2025 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Oct 28 20:32:48 2025 +0100 add PDFiumClipPath Change-Id: I32a535d94b392871eb3ebe047586ecb030ee1314 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193115 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx index ef305387389c..336edf18d8ba 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -158,6 +158,17 @@ public: virtual PDFSegmentType getType() const = 0; }; +class VCL_DLLPUBLIC PDFiumClipPath +{ +public: + virtual ~PDFiumClipPath() = default; + + virtual int getPathCount() = 0; + virtual int getPathSegmentCount(int nPathIndex) = 0; + virtual std::unique_ptr<PDFiumPathSegment> getPathSegment(int nPathIndex, int nSegmentIndex) + = 0; +}; + class VCL_DLLPUBLIC PDFiumPageObject { public: @@ -193,6 +204,9 @@ public: virtual Size getImageSize(PDFiumPage& rPage) = 0; virtual std::unique_ptr<PDFiumBitmap> getImageBitmap() = 0; virtual bool getDrawMode(PDFFillMode& eFillMode, bool& bStroke) = 0; + + // ClipPath + virtual std::unique_ptr<PDFiumClipPath> getClipPath() = 0; }; class VCL_DLLPUBLIC PDFiumSearchHandle diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index 9f23053b967d..35d5de43c4ae 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -17,6 +17,7 @@ #include <fpdf_annot.h> #include <fpdf_edit.h> #include <fpdf_text.h> +#include <fpdf_transformpage.h> #include <fpdf_save.h> #include <fpdf_signature.h> #include <fpdf_formfill.h> @@ -299,6 +300,22 @@ public: PDFSegmentType getType() const override; }; +class PDFiumClipPathImpl final : public PDFiumClipPath +{ +private: + FPDF_CLIPPATH mpClipPath; + + PDFiumClipPathImpl(const PDFiumClipPathImpl&) = delete; + PDFiumClipPathImpl& operator=(const PDFiumClipPathImpl&) = delete; + +public: + PDFiumClipPathImpl(FPDF_CLIPPATH pClipPath); + + int getPathCount() override; + int getPathSegmentCount(int nPathIndex) override; + std::unique_ptr<PDFiumPathSegment> getPathSegment(int nPathIndex, int nSegmentIndex) override; +}; + class PDFiumAnnotationImpl final : public PDFiumAnnotation { private: @@ -434,6 +451,9 @@ public: Size getImageSize(PDFiumPage& rPage) override; std::unique_ptr<PDFiumBitmap> getImageBitmap() override; bool getDrawMode(PDFFillMode& eFillMode, bool& bStroke) override; + + // ClipPath + std::unique_ptr<PDFiumClipPath> getClipPath() override; }; class PDFiumFontImpl final : public PDFiumFont @@ -1388,6 +1408,17 @@ std::unique_ptr<PDFiumPathSegment> PDFiumPageObjectImpl::getPathSegment(int inde return pPDFiumPathSegment; } +std::unique_ptr<PDFiumClipPath> PDFiumPageObjectImpl::getClipPath() +{ + std::unique_ptr<PDFiumClipPath> pPDFiumClipPath; + FPDF_CLIPPATH pClipPath = FPDFPageObj_GetClipPath(mpPageObject); + if (pClipPath) + { + pPDFiumClipPath = std::make_unique<PDFiumClipPathImpl>(pClipPath); + } + return pPDFiumClipPath; +} + Size PDFiumPageObjectImpl::getImageSize(PDFiumPage& rPage) { FPDF_IMAGEOBJ_METADATA aMeta; @@ -1509,6 +1540,31 @@ PDFSegmentType PDFiumPathSegmentImpl::getType() const return static_cast<PDFSegmentType>(FPDFPathSegment_GetType(mpPathSegment)); } +PDFiumClipPathImpl::PDFiumClipPathImpl(FPDF_CLIPPATH pClipPath) + : mpClipPath(pClipPath) +{ +} + +int PDFiumClipPathImpl::getPathCount() { return FPDFClipPath_CountPaths(mpClipPath); } + +int PDFiumClipPathImpl::getPathSegmentCount(int nPathIndex) +{ + return FPDFClipPath_CountPathSegments(mpClipPath, nPathIndex); +} + +std::unique_ptr<PDFiumPathSegment> PDFiumClipPathImpl::getPathSegment(int nPathIndex, + int nSegmentIndex) +{ + std::unique_ptr<PDFiumPathSegment> pPDFiumPathSegment; + FPDF_PATHSEGMENT pPathSegment + = FPDFClipPath_GetPathSegment(mpClipPath, nPathIndex, nSegmentIndex); + if (pPathSegment) + { + pPDFiumPathSegment = std::make_unique<PDFiumPathSegmentImpl>(pPathSegment); + } + return pPDFiumPathSegment; +} + PDFiumFormHandle::PDFiumFormHandle(FPDF_FORMHANDLE pHandle) : mpHandle(pHandle) { commit 8e9817b8ee5426b9a61ee8875dbbbbc5324ebeb7 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Oct 28 15:02:25 2025 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Oct 28 20:32:40 2025 +0100 split out pdfium segments to polypolygon conversion Change-Id: Ib3af196943324a8ae543a1306c008060e53aa5a6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193114 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx index 7f6c0a6103a8..f3eee410d920 100644 --- a/svx/source/inc/svdpdf.hxx +++ b/svx/source/inc/svdpdf.hxx @@ -157,6 +157,11 @@ class ImpSdrPdfImport final void InsertObj(SdrObject* pObj, bool bScale = true); void MapScaling(); + void appendSegmentsToPolyPoly( + basegfx::B2DPolyPolygon& rPolyPoly, + const std::vector<std::unique_ptr<vcl::pdf::PDFiumPathSegment>>& rPathSegments, + const basegfx::B2DHomMatrix& rPathMatrix); + // #i73407# reformulation to use new B2DPolygon classes bool CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon& rPolyPolygon); diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx index 2cfe4595edae..cb358c636e6c 100644 --- a/svx/source/svdraw/svdpdf.cxx +++ b/svx/source/svdraw/svdpdf.cxx @@ -1987,26 +1987,20 @@ void ImpSdrPdfImport::ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> co InsertObj(pGraf.get()); } -void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, - std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, - int /*nPageObjectIndex*/) +void ImpSdrPdfImport::appendSegmentsToPolyPoly( + basegfx::B2DPolyPolygon& rPolyPoly, + const std::vector<std::unique_ptr<vcl::pdf::PDFiumPathSegment>>& rPathSegments, + const basegfx::B2DHomMatrix& rPathMatrix) { - auto aPathMatrix = pPageObject->getMatrix(); - - aPathMatrix *= maCurrentMatrix; - - basegfx::B2DPolyPolygon aPolyPoly; basegfx::B2DPolygon aPoly; std::vector<basegfx::B2DPoint> aBezier; - const int nSegments = pPageObject->getPathSegmentCount(); - for (int nSegmentIndex = 0; nSegmentIndex < nSegments; ++nSegmentIndex) + for (const auto& pPathSegment : rPathSegments) { - auto pPathSegment = pPageObject->getPathSegment(nSegmentIndex); if (pPathSegment != nullptr) { basegfx::B2DPoint aB2DPoint = pPathSegment->getPoint(); - aB2DPoint *= aPathMatrix; + aB2DPoint *= rPathMatrix; const bool bClose = pPathSegment->isClosed(); if (bClose) @@ -2036,7 +2030,7 @@ void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> con // New Poly. if (aPoly.count() > 0) { - aPolyPoly.append(aPoly, 1); + rPolyPoly.append(aPoly, 1); aPoly.clear(); } @@ -2060,9 +2054,29 @@ void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> con if (aPoly.count() > 0) { - aPolyPoly.append(aPoly, 1); + rPolyPoly.append(aPoly, 1); aPoly.clear(); } +} + +void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, + int /*nPageObjectIndex*/) +{ + auto aPathMatrix = pPageObject->getMatrix(); + + aPathMatrix *= maCurrentMatrix; + + basegfx::B2DPolyPolygon aPolyPoly; + + std::vector<std::unique_ptr<vcl::pdf::PDFiumPathSegment>> aPathSegments; + const int nSegments = pPageObject->getPathSegmentCount(); + for (int nSegmentIndex = 0; nSegmentIndex < nSegments; ++nSegmentIndex) + { + aPathSegments.push_back(pPageObject->getPathSegment(nSegmentIndex)); + } + + appendSegmentsToPolyPoly(aPolyPoly, aPathSegments, aPathMatrix); const basegfx::B2DHomMatrix aTransform( basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y())); commit a987919caeb24fd8b34fd8d9e93280cd6e0b44ea Author: Caolán McNamara <[email protected]> AuthorDate: Tue Oct 28 16:04:28 2025 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Oct 28 20:32:33 2025 +0100 handle errors from makeotf Change-Id: I97b702f32ca125fd2eb5c652b079ed94e521d47a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193112 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/external/afdko/extern_makeotf.patch b/external/afdko/extern_makeotf.patch index fd827b0f0ceb..4021d52dec45 100644 --- a/external/afdko/extern_makeotf.patch +++ b/external/afdko/extern_makeotf.patch @@ -66,6 +66,25 @@ } // [fcdb callback] Report database parsing warning. +@@ -1185,7 +1185,8 @@ + + /* Create new callback context */ + cbCtx cbNew(char *progname, char *pfbdir, char *otfdir, +- char *cmapdir, char *featdir, dnaCtx mainDnaCtx) { ++ char *cmapdir, char *featdir, dnaCtx mainDnaCtx, ++ void (*fatal)(void*)) { + static hotCallbacks template = { + NULL, /* Callback context; set after creation */ + myfatal, +@@ -1233,6 +1234,8 @@ + h->dir.cmap = cmapdir; + + h->hot.cb = template; /* Copy template */ ++ if (fatal) ++ h->hot.cb.fatal = fatal; + h->hot.cb.ctx = h; + + h->dnaCtx = mainDnaCtx; --- afdko/c/makeotf/source/file.c 2025-09-23 13:18:57.919265608 +0100 +++ afdko/c/makeotf/source/file.c 2025-09-23 13:20:04.148358137 +0100 @@ -23,7 +23,7 @@ @@ -314,6 +333,16 @@ typedef struct cbCtx_ *cbCtx; /* Define to supply Microsoft-specific function calling info, e.g. __cdecl */ +@@ -22,7 +22,8 @@ + + /* --- Basic functions --- */ + extern cbCtx cbNew(char *progname, char *pfbdir, char *otfdir, +- char *cmapdir, char *featdir, dnaCtx mainDnaCtx); ++ char *cmapdir, char *featdir, dnaCtx mainDnaCtx, ++ void (*fatal)(void*)); + extern void cbConvert(cbCtx h, int flags, char *clientVers, + char *pfbfile, char *otffile, + char *featurefile, char *hcmapfile, char *vcmapfile, @@ -80,4 +85,8 @@ #define OTHERFLAGS_VERBOSE (1 << 15) #define OTHERFLAGS_FINAL_NAMES (1 << 16) diff --git a/vcl/source/gdi/embeddedfontsafdko.cxx b/vcl/source/gdi/embeddedfontsafdko.cxx index a2b83cdb4161..0d4a3cee75a4 100644 --- a/vcl/source/gdi/embeddedfontsafdko.cxx +++ b/vcl/source/gdi/embeddedfontsafdko.cxx @@ -295,11 +295,14 @@ static void* cb_memory(ctlMemoryCallbacks* /*cb*/, void* old, size_t size) } #endif +static void makeOtfFatalCallback(void*) { throw std::runtime_error("fatal tx error"); } + // System afdko could be used by calling: makeotf[exe] -mf fontMenuNameDB -f srcFont -o destFile -ch charMap [-ff features] bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& destFileUrl, const OUString& fontMenuNameDBUrl, const OUString& charMapUrl, const OUString& featuresUrl) { + bool ret = false; #if HAVE_FEATURE_AFDKO OUString srcFontPath, destFilePath, charMapPath, fontMenuNameDBPath, featuresPath; if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(srcFontUrl, srcFontPath) @@ -331,8 +334,9 @@ bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& d ctlMemoryCallbacks cb_dna_memcb{ nullptr, cb_memory }; dnaCtx mainDnaCtx = dnaNew(&cb_dna_memcb, DNA_CHECK_ARGS); - cbCtx cbctx = cbNew(nullptr, const_cast<char*>(""), const_cast<char*>(""), - const_cast<char*>(""), const_cast<char*>(""), mainDnaCtx); + cbCtx cbctx + = cbNew(nullptr, const_cast<char*>(""), const_cast<char*>(""), const_cast<char*>(""), + const_cast<char*>(""), mainDnaCtx, makeOtfFatalCallback); OString fontMenuNameDBPathA(fontMenuNameDBPath.toUtf8()); OString srcFontPathA(srcFontPath.toUtf8()); @@ -346,31 +350,40 @@ bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& d << (!charMapPathA.isEmpty() ? " -ch "_ostr + charMapPathA : OString()) << (!featuresPathA.isEmpty() ? " -ff "_ostr + featuresPathA : OString())); - cbFCDBRead(cbctx, const_cast<char*>(fontMenuNameDBPathA.getStr())); + ret = true; + try + { + cbFCDBRead(cbctx, const_cast<char*>(fontMenuNameDBPathA.getStr())); - int flags = HOT_NO_OLD_OPS; - int fontConvertFlags = 0; + int flags = HOT_NO_OLD_OPS; + int fontConvertFlags = 0; #if !SUPERVERBOSE - flags |= HOT_SUPRESS_WARNINGS | HOT_SUPRESS_HINT_WARNINGS; + flags |= HOT_SUPRESS_WARNINGS | HOT_SUPRESS_HINT_WARNINGS; #else - fontConvertFlags |= HOT_CONVERT_VERBOSE; + fontConvertFlags |= HOT_CONVERT_VERBOSE; #endif - cbConvert(cbctx, flags, nullptr, const_cast<char*>(srcFontPathA.getStr()), - const_cast<char*>(destFilePathA.getStr()), - !featuresPathA.isEmpty() ? const_cast<char*>(featuresPathA.getStr()) : nullptr, - !charMapPathA.isEmpty() ? const_cast<char*>(charMapPathA.getStr()) : nullptr, nullptr, - nullptr, nullptr, fontConvertFlags, 0, 0, 0, 0, -1, -1, 0, nullptr); + cbConvert(cbctx, flags, nullptr, const_cast<char*>(srcFontPathA.getStr()), + const_cast<char*>(destFilePathA.getStr()), + !featuresPathA.isEmpty() ? const_cast<char*>(featuresPathA.getStr()) : nullptr, + !charMapPathA.isEmpty() ? const_cast<char*>(charMapPathA.getStr()) : nullptr, + nullptr, nullptr, nullptr, fontConvertFlags, 0, 0, 0, 0, -1, -1, 0, nullptr); + } + catch (const std::exception& e) + { + SAL_WARN("vcl.fonts", "mergeFonts failure: " << e.what()); + ret = false; + } - return true; + cbFree(cbctx); #else (void)srcFontUrl; (void)destFileUrl; (void)fontMenuNameDBUrl; (void)charMapUrl; (void)featuresUrl; - return false; #endif + return ret; } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
