summaryrefslogtreecommitdiff
path: root/vcl/source/font/fontmetric.cxx
diff options
context:
space:
mode:
authorKhaled Hosny <khaledhosny@eglug.org>2016-11-09 15:22:43 +0200
committerKhaled Hosny <khaledhosny@eglug.org>2016-11-22 15:32:11 +0000
commit34d7602954d4483b3bc9db700e7df2c15348947a (patch)
tree8dcfb93fc29815fd89481a7840d64d6c187534db /vcl/source/font/fontmetric.cxx
parentc855aec445628f96d3d32cfde6efd4e51e4489c9 (diff)
tdf#55469 Consistent line spacing across platforms
We current use platform APIs to calculate line spacing, however different platforms behave differently: * FreeType and Core Text will prefer hhea table over OS/2, and OS/2 Typo metrics over Win ones. * GDI’s TEXTMETRIC only uses OS/2 Win metrics, while NEWTEXTMETRIC seems to use Typo one, but we use only the old TEXTMETRIC. So we get inconsistent line spacing and we have no control which of three competing sets of line spacing metrics we end up using. The current conventional wisdom is that: * 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. This patch does this by reading the hhea and OS/2 tables directly and implementing the algorithm above. Quick comparison with Microsoft Office 2016 shows similar line spacing as the new line spacing here, so I guess we are improving compatibility as well. Change-Id: I4541e67e3e14508e3529e73083056a09de02e637 Reviewed-on: https://gerrit.libreoffice.org/31053 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
Diffstat (limited to 'vcl/source/font/fontmetric.cxx')
-rw-r--r--vcl/source/font/fontmetric.cxx72
1 files changed, 72 insertions, 0 deletions
diff --git a/vcl/source/font/fontmetric.cxx b/vcl/source/font/fontmetric.cxx
index 9cde929ce649..3d7bf9a0b375 100644
--- a/vcl/source/font/fontmetric.cxx
+++ b/vcl/source/font/fontmetric.cxx
@@ -24,6 +24,7 @@
#include "impfontmetric.hxx"
#include "impfontmetricdata.hxx"
#include "PhysicalFontFace.hxx"
+#include "sft.hxx"
#include <vector>
#include <set>
@@ -214,6 +215,7 @@ bool ImplFontMetric::operator==( const ImplFontMetric& r ) const
ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
: FontAttributes( rFontSelData )
+ , mnHeight ( rFontSelData.mnHeight )
, mnWidth ( rFontSelData.mnWidth )
, mnOrientation( (short)(rFontSelData.mnOrientation) )
, mnAscent( 0 )
@@ -424,4 +426,74 @@ void ImplFontMetricData::ImplInitAboveTextLineSize()
mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
}
+/*
+ * 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(const std::vector<uint8_t>& rHheaData,
+ const std::vector<uint8_t>& rOS2Data, int nUPEM)
+{
+ mnAscent = mnDescent = mnExtLeading = mnIntLeading = 0;
+
+ double fScale = static_cast<double>(mnHeight) / nUPEM;
+
+ vcl::TTGlobalFontInfo rInfo;
+ memset(&rInfo, 0, sizeof(vcl::TTGlobalFontInfo));
+ GetTTFontMterics(rHheaData, rOS2Data, &rInfo);
+
+ // Try hhea table first.
+ if (rInfo.ascender || rInfo.descender)
+ {
+ mnAscent = rInfo.ascender * fScale;
+ mnDescent = -rInfo.descender * fScale;
+ mnExtLeading = rInfo.linegap * fScale;
+ }
+
+ // But if OS/2 is present, prefer it.
+ if (rInfo.winAscent || rInfo.winDescent || rInfo.typoAscender || rInfo.typoDescender)
+ {
+ if (mnAscent == 0 && mnDescent == 0)
+ {
+ mnAscent = rInfo.winAscent * fScale;
+ mnDescent = rInfo.winDescent * fScale;
+ mnExtLeading = 0;
+ }
+
+ const uint16_t kUseTypoMetricsMask = 1 << 7;
+ if (rInfo.fsSelection & kUseTypoMetricsMask)
+ {
+ mnAscent = rInfo.typoAscender * fScale;
+ mnDescent = -rInfo.typoDescender * fScale;
+ mnExtLeading = rInfo.typoLineGap * fScale;
+ }
+ }
+
+ if (mnAscent || mnDescent)
+ mnIntLeading = mnAscent + mnDescent - mnHeight;
+
+ SAL_INFO("vcl.gdi.fontmetric",
+ "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
+ );
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */