RepositoryExternal.mk | 12 ++- config_host.mk.in | 1 config_host/config_afdko.h.in | 14 ++++ configure.ac | 32 +++++++++ sw/qa/filter/md/data/table.odt |binary sw/qa/filter/md/md.cxx | 14 ++++ sw/source/filter/md/wrtmd.cxx | 5 - vcl/source/gdi/embeddedfontsafdko.cxx | 116 ++++++++++++++++++++++------------ 8 files changed, 147 insertions(+), 47 deletions(-)
New commits: commit 9e18540c73f2a218a855c1a8605b5a51e0b4d366 Author: Caolán McNamara <[email protected]> AuthorDate: Mon Nov 3 11:00:18 2025 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Mon Nov 3 20:28:29 2025 +0100 implement system afdko by shelling out to call the command line equivalents note: makeotf is makeotfexe on Fedora Change-Id: I933c456791ecf0f905f4595175a6d458b1444f89 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193343 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index c71d534a6211..57946597d5f6 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -4317,6 +4317,10 @@ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,ooo,\ pdfium \ )) +ifneq ($(SYSTEM_AFDKO),) + +else # !SYSTEM_AFDKO + define gb_LinkTarget__use_afdko $(call gb_LinkTarget_use_unpacked,$(1),afdko) $(call gb_LinkTarget_set_include,$(1),\ @@ -4326,19 +4330,17 @@ $(call gb_LinkTarget_set_include,$(1),\ -I$(gb_UnpackedTarball_workdir)/afdko/c/makeotf/source \ $$(INCLUDE) \ ) -$(call gb_LinkTarget_use_static_libraries,$(1),\ - afdko \ -) - +$(call gb_LinkTarget_use_static_libraries,$(1),afdko) endef define gb_ExternalProject__use_afdko $(call gb_ExternalProject_use_static_libraries,$(1),afdko) - endef endif +endif + ifneq ($(SYSTEM_DRAGONBOX),) define gb_LinkTarget__use_dragonbox diff --git a/config_host.mk.in b/config_host.mk.in index 72c3f6c6038f..2c105981e8ef 100644 --- a/config_host.mk.in +++ b/config_host.mk.in @@ -651,6 +651,7 @@ SYSTEM_ABSEIL=@SYSTEM_ABSEIL@ export ABSEIL_CFLAGS=@ABSEIL_CFLAGS@ export ABSEIL_LIBS=@ABSEIL_LIBS@ SYSTEM_ABW=@SYSTEM_ABW@ +SYSTEM_AFDKO=@SYSTEM_AFDKO@ ARGON2_CFLAGS=$(gb_SPACE)@ARGON2_CFLAGS@ ARGON2_LIBS=$(gb_SPACE)@ARGON2_LIBS@ SYSTEM_ARGON2=@SYSTEM_ARGON2@ diff --git a/config_host/config_afdko.h.in b/config_host/config_afdko.h.in new file mode 100644 index 000000000000..501d4bcbb103 --- /dev/null +++ b/config_host/config_afdko.h.in @@ -0,0 +1,14 @@ +/* +Settings for afdko +*/ + +#ifndef CONFIG_AFDKO_H +#define CONFIG_AFDKO_H + +#define USE_AFDKO_PROGRAMS 0 + +#define TX "tx" +#define MAKEOTF "makeotf" +#define MERGEFONTS "mergefonts" + +#endif diff --git a/configure.ac b/configure.ac index 2bc45d9887d1..3b7ec1a7fb90 100644 --- a/configure.ac +++ b/configure.ac @@ -2555,6 +2555,11 @@ AC_ARG_WITH(system-abseil, [Use the abseil libraries already on system.]),, [with_system_abseil="$with_system_libs"]) +AC_ARG_WITH(system-afdko, + AS_HELP_STRING([--with-system-afdko], + [Use system AKDKO (only needed for pdfium based PDF import.)]),, + [with_system_afdko="$with_system_libs"]) + AC_ARG_WITH(system-openjpeg, AS_HELP_STRING([--with-system-openjpeg], [Use the OpenJPEG library already on system.]),, @@ -12946,8 +12951,32 @@ if test "$ENABLE_PDFIUM" = "TRUE"; then # Only used by the pdf import code that uses pdfium # which doesn't currently have --with-system support if test "$ENABLE_PDFIMPORT" = "TRUE"; then - BUILD_TYPE="$BUILD_TYPE AFDKO" AC_DEFINE(HAVE_FEATURE_AFDKO) + AC_MSG_CHECKING([which AFDKO to use]) + if test "$with_system_afdko" = "yes"; then + SYSTEM_AFDKO=TRUE + AC_MSG_RESULT([external]) + AC_PATH_PROGS(TX, tx) + if test -z "$TX"; then + AC_MSG_ERROR([install 'tx' from Adobe Font Development Kit for OpenType (AFDKO)]) + fi + AC_PATH_PROGS(MAKEOTF, makeotfexe makeotf) + if test -z "$MAKEOTF"; then + AC_MSG_ERROR([install 'makeotf' from Adobe Font Development Kit for OpenType (AFDKO)]) + fi + AC_PATH_PROGS(MERGEFONTS, mergefonts) + if test -z "$MERGEFONTS"; then + AC_MSG_ERROR([install 'mergefonts' from Adobe Font Development Kit for OpenType (AFDKO)]) + fi + AC_DEFINE(USE_AFDKO_PROGRAMS) + AC_DEFINE_UNQUOTED(TX,"$TX") + AC_DEFINE_UNQUOTED(MAKEOTF,"$MAKEOTF") + AC_DEFINE_UNQUOTED(MERGEFONTS,"$MERGEFONTS") + else + AC_MSG_RESULT([internal]) + BUILD_TYPE="$BUILD_TYPE AFDKO" + fi + AC_SUBST(SYSTEM_AFDKO) fi fi AC_SUBST(SYSTEM_OPENJPEG2) @@ -16229,6 +16258,7 @@ AC_CONFIG_FILES([vs-code.code-workspace.template:.vscode/vs-code-template.code-w -e '/defaultProfile/s#Cygwin#Git Bash#' vs-code.code-workspace.template fi], [WSL_ONLY_AS_HELPER=$WSL_ONLY_AS_HELPER]) +AC_CONFIG_HEADERS([config_host/config_afdko.h]) AC_CONFIG_HEADERS([config_host/config_atspi.h]) AC_CONFIG_HEADERS([config_host/config_buildconfig.h]) AC_CONFIG_HEADERS([config_host/config_buildid.h]) diff --git a/vcl/source/gdi/embeddedfontsafdko.cxx b/vcl/source/gdi/embeddedfontsafdko.cxx index 57f56c7d4836..c725afba429f 100644 --- a/vcl/source/gdi/embeddedfontsafdko.cxx +++ b/vcl/source/gdi/embeddedfontsafdko.cxx @@ -16,12 +16,13 @@ #include <sal/config.h> #include <config_features.h> +#include <config_afdko.h> #include <osl/file.hxx> #include <rtl/strbuf.hxx> #include <vcl/embeddedfontsmanager.hxx> -#if HAVE_FEATURE_AFDKO +#if HAVE_FEATURE_AFDKO && !USE_AFDKO_PROGRAMS #include "afdko.hxx" @@ -103,6 +104,14 @@ bool EmbeddedFontsManager::tx_dump(const OUString& srcFontUrl, const OUString& d return false; } + OString srcFontPathA(srcFontPath.toUtf8()); + OString destFilePathA(destFilePath.toUtf8()); + OString txCommand = TX " -dump " + srcFontPathA + " " + destFilePathA; + SAL_INFO("vcl.fonts", txCommand); + +#if USE_AFDKO_PROGRAMS + return system(txCommand.getStr()) == 0; +#else txCtx h = txNew(nullptr); if (!h) return false; @@ -111,11 +120,6 @@ bool EmbeddedFontsManager::tx_dump(const OUString& srcFontUrl, const OUString& d h->appSpecificFree = txFatalCallback; suppressDebugMessagess(h); - OString srcFontPathA(srcFontPath.toUtf8()); - OString destFilePathA(destFilePath.toUtf8()); - - SAL_INFO("vcl.fonts", "tx -dump " << srcFontPathA << " " << destFilePathA); - h->src.stm.filename = const_cast<char*>(srcFontPathA.getStr()); h->dst.stm.filename = const_cast<char*>(destFilePathA.getStr()); try @@ -128,6 +132,7 @@ bool EmbeddedFontsManager::tx_dump(const OUString& srcFontUrl, const OUString& d { SAL_WARN("vcl.fonts", "tx failure: " << e.what()); } +#endif #else (void)srcFontUrl; (void)destFileUrl; @@ -148,6 +153,13 @@ bool EmbeddedFontsManager::tx_t1(const OUString& srcFontUrl, const OUString& des return false; } + OString srcFontPathA(srcFontPath.toUtf8()); + OString destFilePathA(destFilePath.toUtf8()); + OString txCommand = TX " -t1 " + srcFontPathA + " " + destFilePathA; + SAL_INFO("vcl.fonts", txCommand); +#if USE_AFDKO_PROGRAMS + return system(txCommand.getStr()) == 0; +#else txCtx h = txNew(nullptr); if (!h) return false; @@ -158,9 +170,7 @@ bool EmbeddedFontsManager::tx_t1(const OUString& srcFontUrl, const OUString& des setMode(h, mode_t1); - OString srcFontPathA(srcFontPath.toUtf8()); h->src.stm.filename = const_cast<char*>(srcFontPathA.getStr()); - OString destFilePathA(destFilePath.toUtf8()); h->dst.stm.filename = const_cast<char*>(destFilePathA.getStr()); try { @@ -172,6 +182,7 @@ bool EmbeddedFontsManager::tx_t1(const OUString& srcFontUrl, const OUString& des { SAL_WARN("vcl.fonts", "tx failure: " << e.what()); } +#endif #else (void)srcFontUrl; (void)destFileUrl; @@ -179,7 +190,7 @@ bool EmbeddedFontsManager::tx_t1(const OUString& srcFontUrl, const OUString& des return false; } -#if HAVE_FEATURE_AFDKO +#if HAVE_FEATURE_AFDKO && !USE_AFDKO_PROGRAMS static void mergeFontsFatalCallback(txCtx h) { mergeFontsFree(h); @@ -219,6 +230,20 @@ bool EmbeddedFontsManager::mergefonts(const OUString& cidFontInfoUrl, const OUSt paths.push_back(mergeFontFilePath.toUtf8()); } + OString cidFontInfoPathA(cidFontInfoPath.toUtf8()); + OString destFilePathA(destFilePath.toUtf8()); + + OStringBuffer aBuffer; + for (const auto& path : paths) + aBuffer.append(" "_ostr + path); + OString mergeFontsCommand + = MERGEFONTS " -cid " + cidFontInfoPathA + " " + destFilePathA + aBuffer; + SAL_INFO("vcl.fonts", mergeFontsCommand); + +#if USE_AFDKO_PROGRAMS + if (system(mergeFontsCommand.getStr()) != 0) + return false; +#else txCtx h = mergeFontsNew(nullptr); if (!h) return false; @@ -227,15 +252,6 @@ bool EmbeddedFontsManager::mergefonts(const OUString& cidFontInfoUrl, const OUSt h->appSpecificFree = mergeFontsFatalCallback; suppressDebugMessagess(h); - OString cidFontInfoPathA(cidFontInfoPath.toUtf8()); - OString destFilePathA(destFilePath.toUtf8()); - - OStringBuffer aBuffer; - for (const auto& path : paths) - aBuffer.append(" "_ostr + path); - SAL_INFO("vcl.fonts", - "mergefonts -cid " << cidFontInfoPathA << " " << destFilePathA << aBuffer.toString()); - try { readCIDFontInfo(h, const_cast<char*>(cidFontInfoPathA.getStr())); @@ -255,24 +271,40 @@ bool EmbeddedFontsManager::mergefonts(const OUString& cidFontInfoUrl, const OUSt size_t resultarg = doMergeFileSet(h, args.size(), args.data(), 0); SAL_WARN_IF(resultarg != args.size() - 1, "vcl.fonts", "suspicious doMergeFileSet result of: " << resultarg); + } + catch (const std::exception& e) + { + SAL_WARN("vcl.fonts", "mergeFonts failure: " << e.what()); + } +#endif - // convert that merged cid result to Type 1 + // convert that merged cid result to Type 1 + bool result = false; + OString tmpdestfile = destFilePathA + ".temp"; + + OString txCommand = TX " -t1 " + destFilePathA + " " + tmpdestfile; + SAL_INFO("vcl.fonts", txCommand); +#if USE_AFDKO_PROGRAMS + result = system(mergeFontsCommand.getStr()) == 0; +#else + try + { h->src.stm.filename = const_cast<char*>(destFilePathA.getStr()); - OString tmpdestfile = destFilePathA + ".temp"; h->dst.stm.filename = const_cast<char*>(tmpdestfile.getStr()); setMode(h, mode_t1); - bool result = convertTx(h); + result = convertTx(h); mergeFontsFree(h); - - remove(destFilePathA.getStr()); - rename(tmpdestfile.getStr(), destFilePathA.getStr()); - - return result; } catch (const std::exception& e) { SAL_WARN("vcl.fonts", "mergeFonts failure: " << e.what()); } +#endif + + remove(destFilePathA.getStr()); + rename(tmpdestfile.getStr(), destFilePathA.getStr()); + + return result; #else (void)cidFontInfoUrl; (void)destFileUrl; @@ -281,7 +313,7 @@ bool EmbeddedFontsManager::mergefonts(const OUString& cidFontInfoUrl, const OUSt return false; } -#if HAVE_FEATURE_AFDKO +#if HAVE_FEATURE_AFDKO && !USE_AFDKO_PROGRAMS static void* cb_memory(ctlMemoryCallbacks* /*cb*/, void* old, size_t size) { if (size == 0) @@ -333,24 +365,29 @@ bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& d return false; } - 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, makeOtfFatalCallback); - OString fontMenuNameDBPathA(fontMenuNameDBPath.toUtf8()); OString srcFontPathA(srcFontPath.toUtf8()); OString destFilePathA(destFilePath.toUtf8()); OString charMapPathA(charMapPath.toUtf8()); OString featuresPathA(featuresPath.toUtf8()); - SAL_INFO( - "vcl.fonts", "makeotf -nshw -mf " - << fontMenuNameDBPathA << " -f " << srcFontPathA << " -o " << destFilePathA - << (!charMapPathA.isEmpty() ? " -ch "_ostr + charMapPathA : OString()) - << (!featuresPathA.isEmpty() ? " -ff "_ostr + featuresPathA : OString())); + OString makeotfCommand = MAKEOTF " -nshw -mf " + fontMenuNameDBPathA + " -f " + srcFontPathA + + " -o " + destFilePathA; + if (!charMapPathA.isEmpty()) + makeotfCommand += " -ch "_ostr + charMapPathA; + if (!featuresPathA.isEmpty()) + makeotfCommand += " -ff "_ostr + featuresPathA; + SAL_INFO("vcl.fonts", makeotfCommand); + +#if USE_AFDKO_PROGRAMS + return system(makeotfCommand.getStr()) == 0; +#else + 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, makeOtfFatalCallback); ret = true; try @@ -378,6 +415,7 @@ bool EmbeddedFontsManager::makeotf(const OUString& srcFontUrl, const OUString& d } cbFree(cbctx); +#endif #else (void)srcFontUrl; (void)destFileUrl; commit 06e1483904d1fa2353c357b28de39bc8047240d2 Author: Caolán McNamara <[email protected]> AuthorDate: Mon Nov 3 12:40:12 2025 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Mon Nov 3 20:28:17 2025 +0100 null deref of SwOLENode seen on pasting as markdown from another writer document. The offending node is a SwNodeType::Table, not SwNodeType::Ole #0 0x00007fffefeb2a2a in std::__uniq_ptr_impl<svt::EmbeddedObjectRef_Impl, std::default_delete<svt::EmbeddedObjectRef_Impl> >::_M_ptr (this=0x1d0) at /usr/include/c++/15/bits/unique_ptr.h:193 #1 0x00007fffefeb22fe in std::unique_ptr<svt::EmbeddedObjectRef_Impl, std::default_delete<svt::EmbeddedObjectRef_Impl> >::get (this=0x1d0) at /usr/include/c++/15/bits/unique_ptr.h:473 #2 0x00007fffefeb0c70 in std::unique_ptr<svt::EmbeddedObjectRef_Impl, std::default_delete<svt::EmbeddedObjectRef_Impl> >::operator-> (this=0x1d0) at /usr/include/c++/15/bits/unique_ptr.h:466 #3 0x00007fffefeaa9fe in svt::EmbeddedObjectRef::is (this=0x1d0) at core/svtools/source/misc/embedhlp.cxx:406 #4 0x00007fff9ad2c6f7 in SwOLEObj::GetOleRef (this=0x1c0) at core/sw/source/core/ole/ndole.cxx:1048 #5 0x00007fff9ad29112 in SwOLENode::GetGraphic (this=0x0) at core/sw/source/core/ole/ndole.cxx:316 #6 0x00007fff9b533a2c in (anonymous namespace)::ApplyFlyFrameFormat (rFrameFormat=..., rWrt=..., rChange=...) at core/sw/source/filter/md/wrtmd.cxx:187 #7 0x00007fff9b535f2c in (anonymous namespace)::OutFormattingChange (rWrt=..., positions=..., pos=0, current=...) at core/sw/source/filter/md/wrtmd.cxx:490 #8 0x00007fff9b5380ae in (anonymous namespace)::OutMarkdown_SwTextNode (rWrt=..., rNode=..., bFirst=false) at core/sw/source/filter/md/wrtmd.cxx:827 #9 0x00007fff9b53962f in SwMDWriter::Out_SwDoc (this=0xc5d5030, pPam=0xc5cc6a8) at core/sw/source/filter/md/wrtmd.cxx:1069 #10 0x00007fff9b53931f in SwMDWriter::WriteStream (this=0xc5d5030) at core/sw/source/filter/md/wrtmd.cxx:1037 #11 0x00007fff9b578252 in Writer::Write (this=0xc5d5030, rPaM=SwPaM = {...}, rStrm=..., pFName=0x0) at core/sw/source/filter/writer/writer.cxx:231 #12 0x00007fff9b3b6958 in SwWriter::Write (this=0x7fffffffab50, rxWriter=..., pRealFileName=0x0) at core/sw/source/filter/basflt/shellio.cxx:871 #13 0x00007fff9b74914e in SwTransferable::WriteObject (this=0xbeed890, rOStream=..., pObject=0xbf05ce0, nObjectType=128) at core/sw/source/uibase/dochdl/swdtflvr.cxx:835 #14 0x00007fffed8d4d27 in TransferableHelper::SetObject (this=0xbeed890, pUserObject=0xbf05ce0, nUserObjectId=128, rFlavor=...) at core/vcl/source/treelist/transfer.cxx:912 Change-Id: I336a443b33de688d8397dff934c02c6ecc079829 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193349 Reviewed-by: Michael Stahl <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193348 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/sw/qa/filter/md/data/table.odt b/sw/qa/filter/md/data/table.odt new file mode 100644 index 000000000000..cd8a1c6a0268 Binary files /dev/null and b/sw/qa/filter/md/data/table.odt differ diff --git a/sw/qa/filter/md/md.cxx b/sw/qa/filter/md/md.cxx index 9a42785a1a55..d698082f28f4 100644 --- a/sw/qa/filter/md/md.cxx +++ b/sw/qa/filter/md/md.cxx @@ -74,6 +74,20 @@ CPPUNIT_TEST_FIXTURE(Test, testExportFormula) CPPUNIT_ASSERT_EQUAL(aExpected, aActual); } +CPPUNIT_TEST_FIXTURE(Test, testExportTableFrame) +{ + createSwDoc("table.odt"); + + // Without the fix in place, this test would have crashed here + save(mpFilter); + + std::string aActual = TempFileToString(); + std::string aExpected("Text" SAL_NEWLINE_STRING SAL_NEWLINE_STRING + "![]()Text" SAL_NEWLINE_STRING); + + CPPUNIT_ASSERT_EQUAL(aExpected, aActual); +} + CPPUNIT_TEST_FIXTURE(Test, testExportingBasicElements) { createSwDoc("basic-elements.fodt"); diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx index 34164d3f3d19..c1d5175537a4 100644 --- a/sw/source/filter/md/wrtmd.cxx +++ b/sw/source/filter/md/wrtmd.cxx @@ -161,7 +161,8 @@ void ApplyFlyFrameFormat(const SwFlyFrameFormat& rFrameFormat, SwMDWriter& rWrt, SwNodeOffset nStart = rFlyContent.GetContentIdx()->GetIndex() + 1; Graphic aGraphic; OUString aGraphicURL; - if (rWrt.m_pDoc->GetNodes()[nStart]->GetNodeType() == SwNodeType::Grf) + SwNodeType eNodeType = rWrt.m_pDoc->GetNodes()[nStart]->GetNodeType(); + if (eNodeType == SwNodeType::Grf) { SwGrfNode* pGrfNode = rWrt.m_pDoc->GetNodes()[nStart]->GetGrfNode(); aGraphic = pGrfNode->GetGraphic(); @@ -181,7 +182,7 @@ void ApplyFlyFrameFormat(const SwFlyFrameFormat& rFrameFormat, SwMDWriter& rWrt, aGraphicURL = "data:" + aGraphicInBase64; } } - else + else if (eNodeType == SwNodeType::Ole) { SwOLENode* pOLENode = rWrt.m_pDoc->GetNodes()[nStart]->GetOLENode(); assert(pOLENode->GetGraphic());
