summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKhaled Hosny <khaled@aliftype.com>2022-09-30 12:35:10 +0200
committerخالد حسني <khaled@aliftype.com>2022-09-30 16:17:22 +0200
commitfb417ee082afdd2e80a1f48aa420bb8d5cb97686 (patch)
tree384a831e01a38e825a829636b901a9be6e535083
parent5948e2e9f032916e3278f904097eff6b47b869d6 (diff)
vcl: Apply variations to font metrics
Use HarfBuzz API instead of reading the raw font table directly, since HarfBuzz will apply the font variations as needed. For non-variable fonts we still also use HarfBuzz font metrics API, but in a more fine-grained way to maintain backward-compatibility. Change-Id: If6b12a11ecb63356be92ef4f0714355ae77378f2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140799 Tested-by: Jenkins Reviewed-by: خالد حسني <khaled@aliftype.com>
-rw-r--r--configure.ac2
-rw-r--r--vcl/inc/impfontmetricdata.hxx3
-rw-r--r--vcl/inc/sft.hxx14
-rw-r--r--vcl/source/font/fontmetric.cxx168
-rw-r--r--vcl/source/fontsubset/sft.cxx26
5 files changed, 107 insertions, 106 deletions
diff --git a/configure.ac b/configure.ac
index 340e87d75b55..ab2c744fb26d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -10882,7 +10882,7 @@ libo_CHECK_SYSTEM_MODULE([graphite],[GRAPHITE],[graphite2 >= 0.9.3])
HARFBUZZ_CFLAGS_internal="-I${WORKDIR}/UnpackedTarball/harfbuzz/src"
HARFBUZZ_LIBS_internal="-L${WORKDIR}/UnpackedTarball/harfbuzz/src/.libs -lharfbuzz"
-libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 2.1.0])
+libo_CHECK_SYSTEM_MODULE([harfbuzz],[HARFBUZZ],[harfbuzz-icu >= 2.6.0])
if test "$COM" = "MSC"; then # override the above
GRAPHITE_LIBS="${WORKDIR}/LinkTarget/StaticLibrary/graphite.lib"
diff --git a/vcl/inc/impfontmetricdata.hxx b/vcl/inc/impfontmetricdata.hxx
index 0d6ab70e97b5..d5b244309047 100644
--- a/vcl/inc/impfontmetricdata.hxx
+++ b/vcl/inc/impfontmetricdata.hxx
@@ -25,7 +25,6 @@
#include <tools/long.hxx>
#include <tools/ref.hxx>
#include "fontattributes.hxx"
-#include "sft.hxx"
#include <vector>
@@ -103,7 +102,7 @@ public:
void ImplInitBaselines(LogicalFontInstance *pFontInstance);
private:
- bool ShouldUseWinMetrics(const vcl::TTGlobalFontInfo& rInfo) const;
+ bool ShouldUseWinMetrics(int, int, int, int, int, int) const;
// font instance attributes from the font request
tools::Long mnHeight; // Font size
diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx
index 3b72df3826a8..780dd867d304 100644
--- a/vcl/inc/sft.hxx
+++ b/vcl/inc/sft.hxx
@@ -691,20 +691,6 @@ class TrueTypeFace;
*/
VCL_DLLPUBLIC bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int& xMin, int& yMin, int& xMax, int& yMax, sal_uInt16& macStyle);
-/**
- * Returns fonts metrics.
- * @see TTGlobalFontInfo
- *
- * @param hhea hhea table data
- * @param os2 OS/2 table data
- * @param info pointer to a TTGlobalFontInfo structure
- * @ingroup sft
- *
- */
- void GetTTFontMetrics(const uint8_t *pHhea, size_t nHhea,
- const uint8_t *pOs2, size_t nOs2,
- TTGlobalFontInfo *info);
-
/*- private definitions */
/* indexes into TrueTypeFont::tables[] and TrueTypeFont::tlens[] */
diff --git a/vcl/source/font/fontmetric.cxx b/vcl/source/font/fontmetric.cxx
index f03edd201982..95263c694b3b 100644
--- a/vcl/source/font/fontmetric.cxx
+++ b/vcl/source/font/fontmetric.cxx
@@ -21,10 +21,11 @@
#include <i18nlangtag/mslangid.hxx>
#include <officecfg/Office/Common.hxx>
+#include <sal/log.hxx>
+#include <tools/stream.hxx>
#include <unotools/configmgr.hxx>
#include <vcl/metric.hxx>
#include <vcl/outdev.hxx>
-#include <sal/log.hxx>
#include <font/FontSelectPattern.hxx>
#include <font/PhysicalFontFace.hxx>
@@ -332,16 +333,18 @@ void ImplFontMetricData::ImplInitFlags( const OutputDevice* pDev )
SetFullstopCenteredFlag( bCentered );
}
-bool ImplFontMetricData::ShouldUseWinMetrics(const vcl::TTGlobalFontInfo& rInfo) const
+bool ImplFontMetricData::ShouldUseWinMetrics(int nAscent, int nDescent, int nTypoAscent,
+ int nTypoDescent, int nWinAscent,
+ int nWinDescent) const
{
if (utl::ConfigManager::IsFuzzing())
return false;
OUString aFontIdentifier(
GetFamilyName() + ","
- + OUString::number(rInfo.ascender) + "," + OUString::number(rInfo.descender) + ","
- + OUString::number(rInfo.typoAscender) + "," + OUString::number(rInfo.typoDescender) + ","
- + OUString::number(rInfo.winAscent) + "," + OUString::number(rInfo.winDescent));
+ + OUString::number(nAscent) + "," + OUString::number(nDescent) + ","
+ + OUString::number(nTypoAscent) + "," + OUString::number(nTypoDescent) + ","
+ + OUString::number(nWinAscent) + "," + OUString::number(nWinDescent));
css::uno::Sequence<OUString> rWinMetricFontList(
officecfg::Office::Common::Misc::FontsUseWinMetrics::get());
@@ -353,65 +356,116 @@ bool ImplFontMetricData::ShouldUseWinMetrics(const vcl::TTGlobalFontInfo& rInfo)
return false;
}
-/*
- * Calculate line spacing:
- *
- * - hhea metrics should be used, since hhea is a mandatory font table and
- * should always be present.
- * - But if OS/2 is present, it should be used since it is mandatory in
- * Windows.
- * OS/2 has Typo and Win metrics, but the later was meant to control
- * text clipping not line spacing and can be ridiculously large.
- * Unfortunately many Windows application incorrectly use the Win metrics
- * (thanks to GDI’s TEXTMETRIC) and old fonts might be designed with this
- * in mind, so OpenType introduced a flag for fonts to indicate that they
- * really want to use Typo metrics. So for best backward compatibility:
- * - Use Win metrics if available.
- * - Unless USE_TYPO_METRICS flag is set, in which case use Typo metrics.
-*/
-void ImplFontMetricData::ImplCalcLineSpacing(LogicalFontInstance *pFontInstance)
+// These are “private” HarfBuzz metrics tags, they are supported by not exposed
+// in the public header. They are safe ti use, HarfBuzz just does not want to
+// advertise them.
+constexpr auto ASCENT_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'a', 's', 'c'));
+constexpr auto DESCENT_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'd', 's', 'c'));
+constexpr auto LINEGAP_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'l', 'g', 'p'));
+constexpr auto ASCENT_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'a', 's', 'c'));
+constexpr auto DESCENT_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'd', 's', 'c'));
+constexpr auto LINEGAP_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'l', 'g', 'p'));
+
+void ImplFontMetricData::ImplCalcLineSpacing(LogicalFontInstance* pFontInstance)
{
mnAscent = mnDescent = mnExtLeading = mnIntLeading = 0;
auto* pFace = pFontInstance->GetFontFace();
+ auto* pHbFont = pFontInstance->GetHbFont();
- auto aHhea(pFace->GetRawFontData(HB_TAG('h', 'h', 'e', 'a')));
- auto aOS_2(pFace->GetRawFontData(HB_TAG('O', 'S', '/', '2')));
-
- vcl::TTGlobalFontInfo rInfo = {};
- GetTTFontMetrics(aHhea.data(), aHhea.size(), aOS_2.data(), aOS_2.size(), &rInfo);
-
- double nUPEM = pFace->UnitsPerEm();
- double fScale = mnHeight / nUPEM;
+ double fScale = 0;
+ pFontInstance->GetScale(nullptr, &fScale);
double fAscent = 0, fDescent = 0, fExtLeading = 0;
- // Try hhea table first.
- // tdf#107605: Some fonts have weird values here, so check that ascender is
- // +ve and descender is -ve as they normally should.
- if (rInfo.ascender >= 0 && rInfo.descender <= 0)
+ auto aFvar(pFace->GetRawFontData(HB_TAG('f', 'v', 'a', 'r')));
+ if (!aFvar.empty())
{
- fAscent = rInfo.ascender * fScale;
- fDescent = -rInfo.descender * fScale;
- fExtLeading = rInfo.linegap * fScale;
+ // This is a variable font, trust HarfBuzz to give us the right metrics
+ // and apply variations to them.
+ hb_position_t nAscent, nDescent, nLineGap;
+ if (hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &nAscent)
+ && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
+ &nDescent)
+ && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
+ &nLineGap))
+ {
+ fAscent = nAscent * fScale;
+ fDescent = -nDescent * fScale;
+ fExtLeading = nLineGap * fScale;
+ }
}
-
- // But if OS/2 is present, prefer it.
- if (rInfo.winAscent || rInfo.winDescent ||
- rInfo.typoAscender || rInfo.typoDescender)
+ else
{
- if (ShouldUseWinMetrics(rInfo) || (fAscent == 0.0 && fDescent == 0.0))
+ // This is not a variable font, we try to chose the best metrics
+ // ourselves for backward comparability:
+ //
+ // - hhea metrics should be used, since hhea is a mandatory font table
+ // and should always be present.
+ // - But if OS/2 is present, it should be used since it is mandatory in
+ // Windows.
+ // OS/2 has Typo and Win metrics, but the later was meant to control
+ // text clipping not line spacing and can be ridiculously large.
+ // Unfortunately many Windows application incorrectly use the Win
+ // metrics (thanks to GDI’s TEXTMETRIC) and old fonts might be
+ // designed with this in mind, so OpenType introduced a flag for
+ // fonts to indicate that they really want to use Typo metrics. So
+ // for best backward compatibility:
+ // - Use Win metrics if available.
+ // - Unless USE_TYPO_METRICS flag is set, in which case use Typo
+ // metrics.
+
+ // Try hhea table first.
+ hb_position_t nAscent = 0, nDescent = 0, nLineGap = 0;
+ if (hb_ot_metrics_get_position(pHbFont, ASCENT_HHEA, &nAscent)
+ && hb_ot_metrics_get_position(pHbFont, DESCENT_HHEA, &nDescent)
+ && hb_ot_metrics_get_position(pHbFont, LINEGAP_HHEA, &nLineGap))
{
- fAscent = rInfo.winAscent * fScale;
- fDescent = rInfo.winDescent * fScale;
- fExtLeading = 0;
+ // tdf#107605: Some fonts have weird values here, so check that
+ // ascender is +ve and descender is -ve as they normally should.
+ if (nAscent >= 0 && nDescent <= 0)
+ {
+ fAscent = nAscent * fScale;
+ fDescent = -nDescent * fScale;
+ fExtLeading = nLineGap * fScale;
+ }
}
- const uint16_t kUseTypoMetricsMask = 1 << 7;
- if (rInfo.fsSelection & kUseTypoMetricsMask &&
- rInfo.typoAscender >= 0 && rInfo.typoDescender <= 0)
+ // But if OS/2 is present, prefer it.
+ hb_position_t nTypoAscent, nTypoDescent, nTypoLineGap, nWinAscent, nWinDescent;
+ if (hb_ot_metrics_get_position(pHbFont, ASCENT_OS2, &nTypoAscent)
+ && hb_ot_metrics_get_position(pHbFont, DESCENT_OS2, &nTypoDescent)
+ && hb_ot_metrics_get_position(pHbFont, LINEGAP_OS2, &nTypoLineGap)
+ && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT,
+ &nWinAscent)
+ && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT,
+ &nWinDescent))
{
- fAscent = rInfo.typoAscender * fScale;
- fDescent = -rInfo.typoDescender * fScale;
- fExtLeading = rInfo.typoLineGap * fScale;
+ if ((fAscent == 0.0 && fDescent == 0.0)
+ || ShouldUseWinMetrics(nAscent, nDescent, nTypoAscent, nTypoDescent, nWinAscent,
+ nWinDescent))
+ {
+ fAscent = nWinAscent * fScale;
+ fDescent = nWinDescent * fScale;
+ fExtLeading = 0;
+ }
+
+ bool bUseTypoMetrics = false;
+ {
+ // TODO: Use HarfBuzz API instead of raw access
+ // https://github.com/harfbuzz/harfbuzz/issues/1920
+ sal_uInt16 fsSelection = 0;
+ auto aOS2(pFace->GetRawFontData(HB_TAG('O', 'S', '/', '2')));
+ SvMemoryStream aStream(const_cast<uint8_t*>(aOS2.data()), aOS2.size(),
+ StreamMode::READ);
+ if (aStream.Seek(vcl::OS2_fsSelection_offset) == vcl::OS2_fsSelection_offset)
+ aStream.ReadUInt16(fsSelection);
+ bUseTypoMetrics = fsSelection & (1 << 7);
+ }
+ if (bUseTypoMetrics && nTypoAscent >= 0 && nTypoDescent <= 0)
+ {
+ fAscent = nTypoAscent * fScale;
+ fDescent = -nTypoDescent * fScale;
+ fExtLeading = nTypoLineGap * fScale;
+ }
}
}
@@ -421,18 +475,6 @@ void ImplFontMetricData::ImplCalcLineSpacing(LogicalFontInstance *pFontInstance)
if (mnAscent || mnDescent)
mnIntLeading = mnAscent + mnDescent - mnHeight;
-
- SAL_INFO("vcl.gdi.fontmetric", GetFamilyName()
- << ": fsSelection: " << rInfo.fsSelection
- << ", typoAscender: " << rInfo.typoAscender
- << ", typoDescender: " << rInfo.typoDescender
- << ", typoLineGap: " << rInfo.typoLineGap
- << ", winAscent: " << rInfo.winAscent
- << ", winDescent: " << rInfo.winDescent
- << ", ascender: " << rInfo.ascender
- << ", descender: " << rInfo.descender
- << ", linegap: " << rInfo.linegap
- );
}
void ImplFontMetricData::ImplInitBaselines(LogicalFontInstance *pFontInstance)
diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx
index 441838e01c8e..deb18ff73177 100644
--- a/vcl/source/fontsubset/sft.cxx
+++ b/vcl/source/fontsubset/sft.cxx
@@ -2279,32 +2279,6 @@ std::unique_ptr<sal_uInt16[]> GetTTSimpleGlyphMetrics(AbstractTrueTypeFont const
return res;
}
-// TODO, clean up table parsing and re-use it elsewhere in this file.
-void GetTTFontMetrics(const uint8_t *pHhea, size_t nHhea,
- const uint8_t *pOs2, size_t nOs2,
- TTGlobalFontInfo *info)
-{
- /* There are 3 different versions of OS/2 table: original (68 bytes long),
- * Microsoft old (78 bytes long) and Microsoft new (86 bytes long,)
- * Apple's documentation recommends looking at the table length.
- */
- if (nOs2 >= OS2_V0_length)
- {
- info->fsSelection = GetUInt16(pOs2, OS2_fsSelection_offset);
- info->typoAscender = GetInt16(pOs2, OS2_typoAscender_offset);
- info->typoDescender = GetInt16(pOs2, OS2_typoDescender_offset);
- info->typoLineGap = GetInt16(pOs2, OS2_typoLineGap_offset);
- info->winAscent = GetUInt16(pOs2, OS2_winAscent_offset);
- info->winDescent = GetUInt16(pOs2, OS2_winDescent_offset);
- }
-
- if (nHhea >= HHEA_lineGap_offset + 2) {
- info->ascender = GetInt16(pHhea, HHEA_ascender_offset);
- info->descender = GetInt16(pHhea, HHEA_descender_offset);
- info->linegap = GetInt16(pHhea, HHEA_lineGap_offset);
- }
-}
-
bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int& xMin, int& yMin, int& xMax, int& yMax, sal_uInt16& macStyle)
{
sal_uInt32 table_size;