diff options
author | Khaled Hosny <khaledhosny@eglug.org> | 2016-11-09 15:22:43 +0200 |
---|---|---|
committer | Khaled Hosny <khaledhosny@eglug.org> | 2016-11-22 15:32:11 +0000 |
commit | 34d7602954d4483b3bc9db700e7df2c15348947a (patch) | |
tree | 8dcfb93fc29815fd89481a7840d64d6c187534db /vcl/win/gdi | |
parent | c855aec445628f96d3d32cfde6efd4e51e4489c9 (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/win/gdi')
-rw-r--r-- | vcl/win/gdi/salfont.cxx | 42 |
1 files changed, 13 insertions, 29 deletions
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index d2e11f8cfb2d..d2d964d47f4b 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -1245,14 +1245,21 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFa if( ::GetTextFaceW( getHDC(), sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) ) rxFontMetric->SetFamilyName(OUString(reinterpret_cast<const sal_Unicode*>(aFaceName))); + const DWORD nHheaTag = CalcTag("hhea"); + const DWORD nOS2Tag = CalcTag("OS/2"); + const RawFontData aHheaRawData(getHDC(), nHheaTag); + const RawFontData aOS2RawData(getHDC(), nOS2Tag); + // get the font metric - TEXTMETRICA aWinMetric; - const bool bOK = GetTextMetricsA( getHDC(), &aWinMetric ); + OUTLINETEXTMETRICW aOutlineMetric; + const bool bOK = GetOutlineTextMetricsW(getHDC(), sizeof(OUTLINETEXTMETRICW), &aOutlineMetric); // restore the HDC to the font in the base level SelectFont( getHDC(), hOldFont ); if( !bOK ) return; + TEXTMETRICW aWinMetric = aOutlineMetric.otmTextMetrics; + // device independent font attributes rxFontMetric->SetFamilyType(ImplFamilyToSal( aWinMetric.tmPitchAndFamily )); rxFontMetric->SetSymbolFlag(aWinMetric.tmCharSet == SYMBOL_CHARSET); @@ -1282,33 +1289,10 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFa // transformation dependent font metrics rxFontMetric->SetWidth( static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAveCharWidth ) ); - rxFontMetric->SetInternalLeading( static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmInternalLeading ) ); - rxFontMetric->SetExternalLeading( static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmExternalLeading ) ); - rxFontMetric->SetAscent( static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAscent ) ); - rxFontMetric->SetDescent( static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmDescent ) ); - - // #107888# improved metric compatibility for Asian fonts... - // TODO: assess workaround below for CWS >= extleading - // TODO: evaluate use of aWinMetric.sTypo* members for CJK - if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() ) - { - rxFontMetric->SetInternalLeading( rxFontMetric->GetInternalLeading() + rxFontMetric->GetExternalLeading() ); - - // #109280# The line height for Asian fonts is too small. - // Therefore we add half of the external leading to the - // ascent, the other half is added to the descent. - const long nHalfTmpExtLeading = rxFontMetric->GetExternalLeading() / 2; - const long nOtherHalfTmpExtLeading = rxFontMetric->GetExternalLeading() - nHalfTmpExtLeading; - - // #110641# external leading for Asian fonts. - // The factor 0.3 has been confirmed with experiments. - long nCJKExtLeading = static_cast<long>(0.30 * (rxFontMetric->GetAscent() + rxFontMetric->GetDescent())); - nCJKExtLeading -= rxFontMetric->GetExternalLeading(); - rxFontMetric->SetExternalLeading( (nCJKExtLeading > 0) ? nCJKExtLeading : 0 ); - - rxFontMetric->SetAscent( rxFontMetric->GetAscent() + nHalfTmpExtLeading ); - rxFontMetric->SetDescent( rxFontMetric->GetDescent() + nOtherHalfTmpExtLeading ); - } + + const std::vector<uint8_t> rHhea(aHheaRawData.get(), aHheaRawData.get() + aHheaRawData.size()); + const std::vector<uint8_t> rOS2(aOS2RawData.get(), aOS2RawData.get() + aOS2RawData.size()); + rxFontMetric->ImplCalcLineSpacing(rHhea, rOS2, aOutlineMetric.otmEMSquare); rxFontMetric->SetMinKashida( GetMinKashidaWidth() ); } |