diff options
author | Mark Hung <marklh9@gmail.com> | 2022-04-03 14:53:14 +0800 |
---|---|---|
committer | Mark Hung <marklh9@gmail.com> | 2022-04-08 15:25:37 +0200 |
commit | 257bb11cbc5b1eb1f90014f528b9e7d6ccfeae86 (patch) | |
tree | 5b1aad0787c01d86759e514ccee52e9d27fb62ba /vcl | |
parent | 2b2d1c08c94fdc3982971c2b19ea241f05e578c9 (diff) |
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 <marklh9@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/fontinstance.hxx | 8 | ||||
-rw-r--r-- | vcl/source/font/fontinstance.cxx | 37 | ||||
-rw-r--r-- | vcl/source/gdi/CommonSalLayout.cxx | 13 |
3 files changed, 58 insertions, 0 deletions
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 { |