include/vcl/embeddedfontsmanager.hxx | 2 + include/vcl/filter/PDFiumLibrary.hxx | 2 + sd/qa/unit/export-tests.cxx | 31 +++++++++++---- svx/source/svdraw/svdpdf.cxx | 3 + vcl/inc/sft.hxx | 3 + vcl/source/fontsubset/sft.cxx | 64 ++++++++++++++++++++++++++++++++ vcl/source/gdi/embeddedfontsmanager.cxx | 13 ++++++ vcl/source/pdf/PDFiumLibrary.cxx | 32 ++++++++++++++++ 8 files changed, 142 insertions(+), 8 deletions(-)
New commits: commit 2b319b7111433609d1820218bc19e76b9ba558cf 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 17:21:25 2025 +0200 pull weight directly from embedded/substituted font Change-Id: I2362b0a14d2c0169db6d20aaa37d741ecd207ffd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191006 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> (cherry picked from commit c2228afb4d92d45871140e7aa7cf2919f65a670c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191821 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]> diff --git a/include/vcl/embeddedfontsmanager.hxx b/include/vcl/embeddedfontsmanager.hxx index 383bc2facbd4..d0338aa26545 100644 --- a/include/vcl/embeddedfontsmanager.hxx +++ b/include/vcl/embeddedfontsmanager.hxx @@ -75,6 +75,8 @@ public: const css::uno::Reference<css::task::XInteractionHandler>& xHandler, bool& activatedRestrictedFonts); + static bool analyzeTTF(const void* data, tools::Long size, FontWeight& weight); + /** Removes all temporary fonts in the path used by fileUrlForTemporaryFont(). @internal diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx index f41eebcf4daa..5eb567928a47 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -21,6 +21,7 @@ #include <basegfx/matrix/b2dhommatrix.hxx> #include <rtl/ustring.hxx> #include <tools/color.hxx> +#include <tools/fontenum.hxx> #include <tools/gen.hxx> #include <vcl/checksum.hxx> #include <vcl/Scanline.hxx> @@ -155,6 +156,7 @@ public: virtual double getFontSize() = 0; virtual OUString getFontName() = 0; virtual int getFontAngle() = 0; + virtual bool getFontProperties(FontWeight& weight) = 0; virtual PDFTextRenderMode getTextRenderMode() = 0; virtual Color getFillColor() = 0; virtual Color getStrokeColor() = 0; diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index dd50ebbdb170..e0a823ca5247 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -1086,14 +1086,29 @@ CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfFont) 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); + { + 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); + } +#if !defined _WIN32 + //TODO, debug this + { + OUString sWeight = getXPath(pXml, "//font[4]", "weight"); + // was "normal" before + CPPUNIT_ASSERT_EQUAL(u"bold"_ustr, sWeight); + // check that the others remain as expected + OUString sFontName = getXPath(pXml, "//font[4]", "name"); + CPPUNIT_ASSERT_EQUAL(u"Liberation Sans"_ustr, sFontName); + int nFontHeight = getXPath(pXml, "//font[4]", "height").toInt32(); + CPPUNIT_ASSERT_EQUAL(564, nFontHeight); + } +#endif } CPPUNIT_TEST_FIXTURE(SdExportTest, testEmbeddedText) diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx index b2bbb8e94350..b7d608a968cf 100644 --- a/svx/source/svdraw/svdpdf.cxx +++ b/svx/source/svdraw/svdpdf.cxx @@ -742,6 +742,9 @@ void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> con const int italicAngle = pPageObject->getFontAngle(); aFnt.SetItalic(italicAngle == 0 ? ITALIC_NONE : (italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE)); + FontWeight eFontWeight(WEIGHT_DONTKNOW); + if (pPageObject->getFontProperties(eFontWeight)) + aFnt.SetWeight(eFontWeight); if (aFnt != mpVD->GetFont()) { diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx index 3bfac9963237..50705e6eb1a7 100644 --- a/vcl/inc/sft.hxx +++ b/vcl/inc/sft.hxx @@ -41,6 +41,7 @@ #include <config_options.h> #include <rtl/ustring.hxx> +#include <tools/fontenum.hxx> #include <vcl/dllapi.h> #include <vcl/fontcapabilities.hxx> #include <vcl/fontcharmap.hxx> @@ -610,6 +611,8 @@ bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int& xMin, int& yM OUString analyzeSfntName(const TrueTypeFont* pTTFont, sal_uInt16 nameId, const LanguageTag& rPrefLang); +void AnalyzeTTF(const TrueTypeFont* pTTFont, FontWeight& weight); + /*- private definitions */ /* indexes into TrueTypeFont::tables[] and TrueTypeFont::tlens[] */ diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index b1a9940c1d99..2721d93f2ade 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -1799,6 +1799,28 @@ bool getTTCoverage( return bRet; } +static FontWeight ImplWeightToSal( int nWeight ) +{ + if ( nWeight <= FW_THIN ) + return WEIGHT_THIN; + else if ( nWeight <= FW_EXTRALIGHT ) + return WEIGHT_ULTRALIGHT; + else if ( nWeight <= FW_LIGHT ) + return WEIGHT_LIGHT; + else if ( nWeight < FW_MEDIUM ) + return WEIGHT_NORMAL; + else if ( nWeight == FW_MEDIUM ) + return WEIGHT_MEDIUM; + else if ( nWeight <= FW_SEMIBOLD ) + return WEIGHT_SEMIBOLD; + else if ( nWeight <= FW_BOLD ) + return WEIGHT_BOLD; + else if ( nWeight <= FW_EXTRABOLD ) + return WEIGHT_ULTRABOLD; + else + return WEIGHT_BLACK; +} + /* * static helpers */ @@ -1989,6 +2011,48 @@ OUString analyzeSfntName(const TrueTypeFont* pTTFont, sal_uInt16 nameId, const L return aResult; } +void AnalyzeTTF(const TrueTypeFont* ttf, FontWeight& weight) +{ + sal_uInt32 table_size; + const sal_uInt8* table = ttf->table(O_OS2, table_size); + if (table_size >= 42) + { + sal_uInt16 weightOS2 = GetUInt16(table, OS2_usWeightClass_offset); + weight = ImplWeightToSal(weightOS2); + return; + } + + // Fallback to inferring from the style name (name ID 2). + OUString sStyle = analyzeSfntName(ttf, 2, LanguageTag(LANGUAGE_ENGLISH_US)); + + bool bBold(false), bItalic(false); + if (o3tl::equalsIgnoreAsciiCase(sStyle, u"Regular")) + { + bBold = false; + bItalic = false; + } + else if (o3tl::equalsIgnoreAsciiCase(sStyle, u"Bold")) + bBold = true; + else if (o3tl::equalsIgnoreAsciiCase(sStyle, u"Bold Italic")) + { + bBold = true; + bItalic = true; + } + else if (o3tl::equalsIgnoreAsciiCase(sStyle, u"Italic")) + { + bItalic = true; + } + else + { + SAL_WARN("vcl.fonts", "Unhandled font style: " << sStyle); + } + + if (bBold) + weight = WEIGHT_BOLD; + (void)bItalic; // we might need to use this in a similar scenario where + // italic cannot be found +} + } // namespace vcl int TestFontSubset(const void* data, sal_uInt32 size) diff --git a/vcl/source/gdi/embeddedfontsmanager.cxx b/vcl/source/gdi/embeddedfontsmanager.cxx index e740afea9c09..2281cc546e17 100644 --- a/vcl/source/gdi/embeddedfontsmanager.cxx +++ b/vcl/source/gdi/embeddedfontsmanager.cxx @@ -38,6 +38,7 @@ #include <font/PhysicalFontCollection.hxx> #include <salgdi.hxx> #include <sft.hxx> +#include <tools/stream.hxx> #include <com/sun/star/beans/StringPair.hpp> #include <com/sun/star/document/FontsDisallowEditingRequest.hpp> @@ -553,6 +554,18 @@ bool EmbeddedFontsManager::isEmbeddedAndRestricted(std::u16string_view familyNam return false; } +bool EmbeddedFontsManager::analyzeTTF(const void* data, tools::Long size, FontWeight& weight) +{ + TrueTypeFont* font; + if (OpenTTFontBuffer( data, size, 0 /*TODO*/, &font ) != SFErrCodes::Ok) + return false; + + AnalyzeTTF(font, weight); + CloseTTFont(font); + + return true; +} + OUString EmbeddedFontsManager::fontFileUrl( std::u16string_view familyName, FontFamily family, FontItalic italic, FontWeight weight, FontPitch pitch, FontRights rights ) { diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index 40a95382f4c0..e6c8eaf9d50b 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -25,6 +25,8 @@ #include <osl/endian.h> #include <vcl/bitmap.hxx> +#include <vcl/embeddedfontsmanager.hxx> +#include <vcl/font.hxx> #include <tools/stream.hxx> #include <tools/UnitConversion.hxx> #include <o3tl/string_view.hxx> @@ -415,6 +417,7 @@ public: double getFontSize() override; OUString getFontName() override; int getFontAngle() override; + bool getFontProperties(FontWeight& weight) override; PDFTextRenderMode getTextRenderMode() override; Color getFillColor() override; Color getStrokeColor() override; @@ -1159,6 +1162,35 @@ int PDFiumPageObjectImpl::getFontAngle() return nFontAngle; } +bool PDFiumPageObjectImpl::getFontProperties(FontWeight& weight) +{ + // FPDFFont_GetWeight turns out not to be that useful. It seems to just + // reports what explicit "FontWeight" feature is mentioned in the PDF font, + // which is an optional property. + // So pull the font data and analyze it directly. Though the font might not + // have an OS/2 table so we may end up eventually inferring the weight from + // the style name. + + FPDF_FONT pFontObject = FPDFTextObj_GetFont(mpPageObject); + size_t buflen(0); + bool bOk = FPDFFont_GetFontData(pFontObject, nullptr, 0, &buflen); + if (!bOk) + { + SAL_WARN("vcl.filter", "PDFiumImpl: failed to get font data"); + return false; + } + std::vector<uint8_t> aData(buflen); + bOk = FPDFFont_GetFontData(pFontObject, aData.data(), aData.size(), &buflen); + assert(bOk && aData.size() == buflen); + bOk = EmbeddedFontsManager::analyzeTTF(aData.data(), aData.size(), weight); + if (!bOk) + { + SAL_WARN("vcl.filter", "PDFiumImpl: failed to analyzeTTF"); + return false; + } + return true; +} + PDFTextRenderMode PDFiumPageObjectImpl::getTextRenderMode() { return static_cast<PDFTextRenderMode>(FPDFTextObj_GetTextRenderMode(mpPageObject));
