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));

Reply via email to