include/vcl/filter/PDFiumLibrary.hxx | 1 sd/qa/unit/data/pdf/differentfonts.pdf |binary sd/qa/unit/export-tests.cxx | 24 ++++ svx/source/svdraw/svdpdf.cxx | 17 +-- vcl/inc/sft.hxx | 2 vcl/source/fontsubset/sft.cxx | 139 ++++++++++++++++++++++++++++ vcl/source/pdf/PDFiumLibrary.cxx | 9 + vcl/unx/generic/fontmanager/fontmanager.cxx | 138 --------------------------- 8 files changed, 184 insertions(+), 146 deletions(-)
New commits: commit 1f489500415ebea22722da57851dd63782452ee2 Author: Caolán McNamara <[email protected]> AuthorDate: Tue Aug 12 13:24:10 2025 +0100 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Oct 4 11:24:20 2025 +0200 move convertSfntName from fontmanager to sft Change-Id: I67327fdef59538fcafe92f0c6d42f94d9aca06bc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191160 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191819 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx index c02f383c5680..259bfbbe44db 100644 --- a/vcl/inc/sft.hxx +++ b/vcl/inc/sft.hxx @@ -146,6 +146,8 @@ namespace vcl std::vector<sal_uInt8> sptr; /**< string data (not zero-terminated!) */ }; + OUString convertSfntName(const NameRecord& rNameRecord); + /** Return value of GetTTGlobalFontInfo() */ typedef struct TTGlobalFontInfo_ { diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index cfee9552ed0e..dab5aff157ec 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -42,11 +42,13 @@ #include <tools/fix16.hxx> #endif #include "ttcr.hxx" +#include <i18nlangtag/applelangid.hxx> #include <rtl/crc.h> #include <rtl/ustring.hxx> #include <rtl/ustrbuf.hxx> #include <sal/log.hxx> #include <o3tl/safeint.hxx> +#include <o3tl/string_view.hxx> #include <osl/endian.h> #include <osl/thread.h> #include <unotools/tempfile.hxx> @@ -1797,6 +1799,143 @@ bool getTTCoverage( return bRet; } +/* + * static helpers + */ +static sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer ) +{ + sal_uInt16 nRet = static_cast<sal_uInt16>(pBuffer[1]) | + (static_cast<sal_uInt16>(pBuffer[0]) << 8); + pBuffer+=2; + return nRet; +} + +OUString convertSfntName( const NameRecord& rNameRecord ) +{ + OUString aValue; + if( + ( rNameRecord.platformID == 3 && ( rNameRecord.encodingID == 0 || rNameRecord.encodingID == 1 ) ) // MS, Unicode + || + ( rNameRecord.platformID == 0 ) // Apple, Unicode + ) + { + OUStringBuffer aName( rNameRecord.sptr.size()/2 ); + const sal_uInt8* pNameBuffer = rNameRecord.sptr.data(); + for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ ) + aName.append( static_cast<sal_Unicode>(getUInt16BE( pNameBuffer )) ); + aValue = aName.makeStringAndClear(); + } + else if( rNameRecord.platformID == 3 ) + { + if( rNameRecord.encodingID >= 2 && rNameRecord.encodingID <= 6 ) + { + /* + * and now for a special kind of madness: + * some fonts encode their byte value string as BE uint16 + * (leading to stray zero bytes in the string) + * while others code two bytes as a uint16 and swap to BE + */ + OStringBuffer aName; + const sal_uInt8* pNameBuffer = rNameRecord.sptr.data(); + for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ ) + { + sal_Unicode aCode = static_cast<sal_Unicode>(getUInt16BE( pNameBuffer )); + char aChar = aCode >> 8; + if( aChar ) + aName.append( aChar ); + aChar = aCode & 0x00ff; + if( aChar ) + aName.append( aChar ); + } + switch( rNameRecord.encodingID ) + { + case 2: + aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_932 ); + break; + case 3: + aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_936 ); + break; + case 4: + aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_950 ); + break; + case 5: + aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_949 ); + break; + case 6: + aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_1361 ); + break; + } + } + } + else if( rNameRecord.platformID == 1 ) + { + std::string_view aName(reinterpret_cast<const char*>(rNameRecord.sptr.data()), rNameRecord.sptr.size()); + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + switch (rNameRecord.encodingID) + { + case 0: + eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; + break; + case 1: + eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE; + break; + case 2: + eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD; + break; + case 3: + eEncoding = RTL_TEXTENCODING_APPLE_KOREAN; + break; + case 4: + eEncoding = RTL_TEXTENCODING_APPLE_ARABIC; + break; + case 5: + eEncoding = RTL_TEXTENCODING_APPLE_HEBREW; + break; + case 6: + eEncoding = RTL_TEXTENCODING_APPLE_GREEK; + break; + case 7: + eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; + break; + case 9: + eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI; + break; + case 10: + eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI; + break; + case 11: + eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI; + break; + case 21: + eEncoding = RTL_TEXTENCODING_APPLE_THAI; + break; + case 25: + eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP; + break; + case 29: + eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; + break; + case 32: //Uninterpreted + eEncoding = RTL_TEXTENCODING_UTF8; + break; + default: + if (o3tl::starts_with(aName, "Khmer OS") || // encoding '20' (Khmer) isn't implemented + o3tl::starts_with(aName, "YoavKtav")) // tdf#152278 + { + eEncoding = RTL_TEXTENCODING_UTF8; + } + SAL_WARN_IF(eEncoding == RTL_TEXTENCODING_DONTKNOW, "vcl.fonts", "mac encoding " << + rNameRecord.encodingID << " in font '" << aName << "'" << + (rNameRecord.encodingID > 32 ? " is invalid" : " has unimplemented conversion")); + break; + } + if (eEncoding != RTL_TEXTENCODING_DONTKNOW) + aValue = OStringToOUString(aName, eEncoding); + } + + return aValue; +} + } // namespace vcl int TestFontSubset(const void* data, sal_uInt32 size) diff --git a/vcl/unx/generic/fontmanager/fontmanager.cxx b/vcl/unx/generic/fontmanager/fontmanager.cxx index d755f317362a..fd2b1dbad382 100644 --- a/vcl/unx/generic/fontmanager/fontmanager.cxx +++ b/vcl/unx/generic/fontmanager/fontmanager.cxx @@ -62,18 +62,6 @@ using namespace psp; using namespace com::sun::star::uno; using namespace com::sun::star::lang; -/* - * static helpers - */ - -static sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer ) -{ - sal_uInt16 nRet = static_cast<sal_uInt16>(pBuffer[1]) | - (static_cast<sal_uInt16>(pBuffer[0]) << 8); - pBuffer+=2; - return nRet; -} - /* * PrintFont implementations */ @@ -311,132 +299,6 @@ std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString namespace { -OUString convertSfntName( const NameRecord& rNameRecord ) -{ - OUString aValue; - if( - ( rNameRecord.platformID == 3 && ( rNameRecord.encodingID == 0 || rNameRecord.encodingID == 1 ) ) // MS, Unicode - || - ( rNameRecord.platformID == 0 ) // Apple, Unicode - ) - { - OUStringBuffer aName( rNameRecord.sptr.size()/2 ); - const sal_uInt8* pNameBuffer = rNameRecord.sptr.data(); - for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ ) - aName.append( static_cast<sal_Unicode>(getUInt16BE( pNameBuffer )) ); - aValue = aName.makeStringAndClear(); - } - else if( rNameRecord.platformID == 3 ) - { - if( rNameRecord.encodingID >= 2 && rNameRecord.encodingID <= 6 ) - { - /* - * and now for a special kind of madness: - * some fonts encode their byte value string as BE uint16 - * (leading to stray zero bytes in the string) - * while others code two bytes as a uint16 and swap to BE - */ - OStringBuffer aName; - const sal_uInt8* pNameBuffer = rNameRecord.sptr.data(); - for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ ) - { - sal_Unicode aCode = static_cast<sal_Unicode>(getUInt16BE( pNameBuffer )); - char aChar = aCode >> 8; - if( aChar ) - aName.append( aChar ); - aChar = aCode & 0x00ff; - if( aChar ) - aName.append( aChar ); - } - switch( rNameRecord.encodingID ) - { - case 2: - aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_932 ); - break; - case 3: - aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_936 ); - break; - case 4: - aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_950 ); - break; - case 5: - aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_949 ); - break; - case 6: - aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_1361 ); - break; - } - } - } - else if( rNameRecord.platformID == 1 ) - { - std::string_view aName(reinterpret_cast<const char*>(rNameRecord.sptr.data()), rNameRecord.sptr.size()); - rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; - switch (rNameRecord.encodingID) - { - case 0: - eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; - break; - case 1: - eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE; - break; - case 2: - eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD; - break; - case 3: - eEncoding = RTL_TEXTENCODING_APPLE_KOREAN; - break; - case 4: - eEncoding = RTL_TEXTENCODING_APPLE_ARABIC; - break; - case 5: - eEncoding = RTL_TEXTENCODING_APPLE_HEBREW; - break; - case 6: - eEncoding = RTL_TEXTENCODING_APPLE_GREEK; - break; - case 7: - eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; - break; - case 9: - eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI; - break; - case 10: - eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI; - break; - case 11: - eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI; - break; - case 21: - eEncoding = RTL_TEXTENCODING_APPLE_THAI; - break; - case 25: - eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP; - break; - case 29: - eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; - break; - case 32: //Uninterpreted - eEncoding = RTL_TEXTENCODING_UTF8; - break; - default: - if (o3tl::starts_with(aName, "Khmer OS") || // encoding '20' (Khmer) isn't implemented - o3tl::starts_with(aName, "YoavKtav")) // tdf#152278 - { - eEncoding = RTL_TEXTENCODING_UTF8; - } - SAL_WARN_IF(eEncoding == RTL_TEXTENCODING_DONTKNOW, "vcl.fonts", "mac encoding " << - rNameRecord.encodingID << " in font '" << aName << "'" << - (rNameRecord.encodingID > 32 ? " is invalid" : " has unimplemented conversion")); - break; - } - if (eEncoding != RTL_TEXTENCODING_DONTKNOW) - aValue = OStringToOUString(aName, eEncoding); - } - - return aValue; -} - OUString analyzeSfntFamilyName(void const * pTTFont) { OUString aFamily; commit ebe962007e39df9010aa1a641ef66cee0dbcb54c Author: Caolán McNamara <[email protected]> AuthorDate: Tue Aug 12 12:51:23 2025 +0100 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Oct 4 11:24:11 2025 +0200 extract italic/oblique info about font Change-Id: Idf9943cede5b63e98e13265f99fcde9d649987ac Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190994 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191818 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 c91c0cef6a77..f41eebcf4daa 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -154,6 +154,7 @@ public: virtual basegfx::B2DRectangle getBounds() = 0; virtual double getFontSize() = 0; virtual OUString getFontName() = 0; + virtual int getFontAngle() = 0; virtual PDFTextRenderMode getTextRenderMode() = 0; virtual Color getFillColor() = 0; virtual Color getStrokeColor() = 0; diff --git a/sd/qa/unit/data/pdf/differentfonts.pdf b/sd/qa/unit/data/pdf/differentfonts.pdf new file mode 100644 index 000000000000..9b5582716328 Binary files /dev/null and b/sd/qa/unit/data/pdf/differentfonts.pdf differ diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 443ee00b4431..dd50ebbdb170 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -1072,6 +1072,30 @@ CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfTextPos) CPPUNIT_ASSERT_DOUBLES_EQUAL(3063, y, 0); } +CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfFont) +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + return; + UsePdfium aGuard; + + loadFromFile(u"pdf/differentfonts.pdf"); + + setFilterOptions("{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}"); + setImportFilterName(u"OpenDocument Drawing Flat XML"_ustr); + saveAndReload(u"OpenDocument Drawing Flat XML"_ustr); + + xmlDocUniquePtr pXml = parseLayout(); + OUString sItalic = getXPath(pXml, "//font[2]", "italic"); + // was "none" before + CPPUNIT_ASSERT_EQUAL(u"normal"_ustr, sItalic); + // check that the others remain as expected + OUString sFontName = getXPath(pXml, "//font[2]", "name"); + CPPUNIT_ASSERT_EQUAL(u"Liberation Serif"_ustr, sFontName); + int nFontHeight = getXPath(pXml, "//font[2]", "height").toInt32(); + CPPUNIT_ASSERT_EQUAL(494, nFontHeight); +} + CPPUNIT_TEST_FIXTURE(SdExportTest, testEmbeddedText) { createSdDrawDoc("objectwithtext.fodg"); diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx index 3d9de5d5c151..b2bbb8e94350 100644 --- a/svx/source/svdraw/svdpdf.cxx +++ b/svx/source/svdraw/svdpdf.cxx @@ -733,17 +733,18 @@ void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> con const Size aFontSize(dFontSizeH, dFontSizeV); vcl::Font aFnt = mpVD->GetFont(); - if (aFontSize != aFnt.GetFontSize()) - { - aFnt.SetFontSize(aFontSize); - mpVD->SetFont(aFnt); - mbFntDirty = true; - } + aFnt.SetFontSize(aFontSize); OUString sFontName = pPageObject->getFontName(); - if (!sFontName.isEmpty() && sFontName != aFnt.GetFamilyName()) - { + if (!sFontName.isEmpty()) aFnt.SetFamilyName(sFontName); + + const int italicAngle = pPageObject->getFontAngle(); + aFnt.SetItalic(italicAngle == 0 ? ITALIC_NONE + : (italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE)); + + if (aFnt != mpVD->GetFont()) + { mpVD->SetFont(aFnt); mbFntDirty = true; } diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index 13d6eedec9f1..40a95382f4c0 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -414,6 +414,7 @@ public: basegfx::B2DRectangle getBounds() override; double getFontSize() override; OUString getFontName() override; + int getFontAngle() override; PDFTextRenderMode getTextRenderMode() override; Color getFillColor() override; Color getStrokeColor() override; @@ -1150,6 +1151,14 @@ OUString PDFiumPageObjectImpl::getFontName() return sFamilyName; } +int PDFiumPageObjectImpl::getFontAngle() +{ + int nFontAngle(0); + FPDF_FONT pFontObject = FPDFTextObj_GetFont(mpPageObject); + FPDFFont_GetItalicAngle(pFontObject, &nFontAngle); + return nFontAngle; +} + PDFTextRenderMode PDFiumPageObjectImpl::getTextRenderMode() { return static_cast<PDFTextRenderMode>(FPDFTextObj_GetTextRenderMode(mpPageObject));
