vcl/inc/fontinstance.hxx           |    8 ++++++++
 vcl/source/font/fontinstance.cxx   |   37 +++++++++++++++++++++++++++++++++++++
 vcl/source/gdi/CommonSalLayout.cxx |   13 +++++++++++++
 3 files changed, 58 insertions(+)

New commits:
commit 257bb11cbc5b1eb1f90014f528b9e7d6ccfeae86
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Sun Apr 3 14:53:14 2022 +0800
Commit:     Mark Hung <mark...@gmail.com>
CommitDate: Fri Apr 8 15:25:37 2022 +0200

    tdf#148330 fix vertical offset for DFKai-SB (ukai.ttf).
    
    DFKai-SB (ukai.ttf) is a built-in font under tradtional Chinese
    Windows. The font is very common, especially for official documents.
    It is one of the so-called tricky fonts in FreeType[1].
    
    DFKai-SB has incorrect extent in the glyf table[2]. It results in
    incorrect glyph positions in vertical writing.
    
    FreeType recalculates the extents based on the
    glyph outline, but LibreOffice uses Harfbuzz with
    built-in ot font functions instead of ft (FreeType).
    
    This patch decides if the fix is necessary by
    checking the family name of the font and the y-offset
    value, and recaculates the glyph offset based on glyph
    height and top bearing obtained from the glyph bound rect.
    
    
[1]https://freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_face_flag_tricky
    [2]https://github.com/harfbuzz/harfbuzz/issues/3521
    
    Change-Id: If632dd38c462c229837e1efb5446e2142f8f0639
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132511
    Tested-by: Jenkins
    Reviewed-by: Mark Hung <mark...@gmail.com>

diff --git a/vcl/inc/fontinstance.hxx b/vcl/inc/fontinstance.hxx
index 5822bd1a08b5..5b5ab206c26a 100644
--- a/vcl/inc/fontinstance.hxx
+++ b/vcl/inc/fontinstance.hxx
@@ -86,6 +86,9 @@ public: // TODO: make data members private
 
     inline hb_font_t* GetHbFont();
     bool IsGraphiteFont();
+    // NeedOffsetCorrection: Return if the font need offset correction in TTB 
direction.
+    // nYOffset is the original offset. It is used to check if the correction 
is necessary.
+    bool NeedOffsetCorrection(sal_Int32 nYOffset);
     void SetAverageWidthFactor(double nFactor) { m_nAveWidthFactor = 
std::abs(nFactor); }
     double GetAverageWidthFactor() const { return m_nAveWidthFactor; }
     const vcl::font::FontSelectPattern& GetFontSelectPattern() const { return 
m_aFontSelData; }
@@ -129,6 +132,11 @@ private:
     double m_nAveWidthFactor;
     rtl::Reference<vcl::font::PhysicalFontFace> m_pFontFace;
     std::optional<bool> m_xbIsGraphiteFont;
+
+    enum class FontFamilyEnum { Unclassified, DFKaiSB };
+
+    // The value is initialized and used in NeedOffsetCorrection().
+    std::optional<FontFamilyEnum> m_xeFontFamilyEnum;
 };
 
 inline hb_font_t* LogicalFontInstance::GetHbFont()
diff --git a/vcl/source/font/fontinstance.cxx b/vcl/source/font/fontinstance.cxx
index 5dbd1748a3c3..6f5bc7d1f37a 100644
--- a/vcl/source/font/fontinstance.cxx
+++ b/vcl/source/font/fontinstance.cxx
@@ -152,4 +152,41 @@ bool LogicalFontInstance::IsGraphiteFont()
     return *m_xbIsGraphiteFont;
 }
 
+bool LogicalFontInstance::NeedOffsetCorrection(sal_Int32 nYOffset)
+{
+    if (!m_xeFontFamilyEnum)
+    {
+        char familyname[10];
+        unsigned int familyname_size = 10;
+
+        m_xeFontFamilyEnum = FontFamilyEnum::Unclassified;
+
+        if (hb_ot_name_get_utf8 (hb_font_get_face(GetHbFont()),
+                HB_OT_NAME_ID_FONT_FAMILY , HB_LANGUAGE_INVALID, 
&familyname_size, familyname) == 8)
+        {
+            // DFKai-SB (ukai.ttf) is a built-in font under tradtional Chinese
+            // Windows. It has wrong extent values in glyf table. The problem 
results
+            // in wrong positioning of glyphs in vertical writing.
+            // Check https://github.com/harfbuzz/harfbuzz/issues/3521 for 
reference.
+            if (!strncmp("DFKai-SB", familyname, 8))
+                m_xeFontFamilyEnum = FontFamilyEnum::DFKaiSB;
+        }
+    }
+
+    bool bRet = true;
+
+    switch (*m_xeFontFamilyEnum)
+    {
+        case FontFamilyEnum::DFKaiSB:
+        // -839: optimization for one third of ukai.ttf
+        if (nYOffset == -839)
+            bRet = false;
+        break;
+        default:
+            bRet = false;
+    }
+
+    return bRet;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index be6480bfde1a..8dee28727997 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -621,6 +621,19 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
                     nAdvance = -pHbPositions[i].y_advance;
                     nXOffset = -pHbPositions[i].y_offset;
                     nYOffset = -pHbPositions[i].x_offset - nBaseOffset;
+
+                    if 
(GetFont().NeedOffsetCorrection(pHbPositions[i].y_offset))
+                    {
+                        // We need glyph's advance, top bearing, and height to
+                        // correct y offset.
+                        tools::Rectangle aRect;
+                        // Get cached bound rect value for the font,
+                        GetFont().GetGlyphBoundRect(nGlyphIndex, aRect, true);
+
+                        nXOffset = -(aRect.Top() / nXScale  + ( 
pHbPositions[i].y_advance
+                                    + ( aRect.GetHeight() / nXScale ) ) / 2 );
+                    }
+
                 }
                 else
                 {

Reply via email to