summaryrefslogtreecommitdiffstats
path: root/vcl/source/font/fontmetric.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/font/fontmetric.cxx')
-rw-r--r--vcl/source/font/fontmetric.cxx563
1 files changed, 563 insertions, 0 deletions
diff --git a/vcl/source/font/fontmetric.cxx b/vcl/source/font/fontmetric.cxx
new file mode 100644
index 0000000000..115b3da6fb
--- /dev/null
+++ b/vcl/source/font/fontmetric.cxx
@@ -0,0 +1,563 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#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 <font/FontSelectPattern.hxx>
+#include <font/PhysicalFontFace.hxx>
+#include <font/LogicalFontInstance.hxx>
+#include <font/FontMetricData.hxx>
+#include <sft.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <hb-ot.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::rtl;
+using namespace ::utl;
+
+FontMetric::FontMetric()
+: mnAscent( 0 ),
+ mnDescent( 0 ),
+ mnIntLeading( 0 ),
+ mnExtLeading( 0 ),
+ mnLineHeight( 0 ),
+ mnSlant( 0 ),
+ mnBulletOffset( 0 ),
+ mnHangingBaseline( 0 ),
+ mbFullstopCentered( false )
+{}
+
+FontMetric::FontMetric( const FontMetric& rFontMetric ) = default;
+
+FontMetric::FontMetric(vcl::font::PhysicalFontFace const& rFace)
+ : FontMetric()
+{
+ SetFamilyName(rFace.GetFamilyName());
+ SetStyleName(rFace.GetStyleName());
+ SetCharSet(rFace.IsMicrosoftSymbolEncoded() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
+ SetFamily(rFace.GetFamilyType());
+ SetPitch(rFace.GetPitch());
+ SetWeight(rFace.GetWeight());
+ SetItalic(rFace.GetItalic());
+ SetAlignment(TextAlign::ALIGN_TOP);
+ SetWidthType(rFace.GetWidthType());
+ SetQuality(rFace.GetQuality() );
+}
+
+FontMetric::~FontMetric()
+{
+}
+
+FontMetric& FontMetric::operator=(const FontMetric& rFontMetric) = default;
+
+FontMetric& FontMetric::operator=(FontMetric&& rFontMetric) = default;
+
+bool FontMetric::EqualNoBase( const FontMetric& r ) const
+{
+ if (mbFullstopCentered != r.mbFullstopCentered)
+ return false;
+ if( mnAscent != r.mnAscent )
+ return false;
+ if( mnDescent != r.mnDescent )
+ return false;
+ if( mnIntLeading != r.mnIntLeading )
+ return false;
+ if( mnExtLeading != r.mnExtLeading )
+ return false;
+ if( mnSlant != r.mnSlant )
+ return false;
+
+ return true;
+}
+
+bool FontMetric::operator==( const FontMetric& r ) const
+{
+ if( Font::operator!=(r) )
+ return false;
+ return EqualNoBase(r);
+}
+
+bool FontMetric::EqualIgnoreColor( const FontMetric& r ) const
+{
+ if( !Font::EqualIgnoreColor(r) )
+ return false;
+ return EqualNoBase(r);
+}
+
+size_t FontMetric::GetHashValueNoBase() const
+{
+ size_t hash = 0;
+ o3tl::hash_combine( hash, mbFullstopCentered );
+ o3tl::hash_combine( hash, mnAscent );
+ o3tl::hash_combine( hash, mnDescent );
+ o3tl::hash_combine( hash, mnIntLeading );
+ o3tl::hash_combine( hash, mnExtLeading );
+ o3tl::hash_combine( hash, mnSlant );
+ return hash;
+}
+
+size_t FontMetric::GetHashValueIgnoreColor() const
+{
+ size_t hash = GetHashValueNoBase();
+ o3tl::hash_combine( hash, Font::GetHashValueIgnoreColor());
+ return hash;
+}
+
+FontMetricData::FontMetricData( const vcl::font::FontSelectPattern& rFontSelData )
+ : FontAttributes( rFontSelData )
+ , mnHeight ( rFontSelData.mnHeight )
+ , mnWidth ( rFontSelData.mnWidth )
+ , mnOrientation( static_cast<short>(rFontSelData.mnOrientation) )
+ , mnAscent( 0 )
+ , mnDescent( 0 )
+ , mnIntLeading( 0 )
+ , mnExtLeading( 0 )
+ , mnSlant( 0 )
+ , mnMinKashida( 0 )
+ , mnHangingBaseline( 0 )
+ , mbFullstopCentered( false )
+ , mnBulletOffset( 0 )
+ , mnUnderlineSize( 0 )
+ , mnUnderlineOffset( 0 )
+ , mnBUnderlineSize( 0 )
+ , mnBUnderlineOffset( 0 )
+ , mnDUnderlineSize( 0 )
+ , mnDUnderlineOffset1( 0 )
+ , mnDUnderlineOffset2( 0 )
+ , mnWUnderlineSize( 0 )
+ , mnWUnderlineOffset( 0 )
+ , mnAboveUnderlineSize( 0 )
+ , mnAboveUnderlineOffset( 0 )
+ , mnAboveBUnderlineSize( 0 )
+ , mnAboveBUnderlineOffset( 0 )
+ , mnAboveDUnderlineSize( 0 )
+ , mnAboveDUnderlineOffset1( 0 )
+ , mnAboveDUnderlineOffset2( 0 )
+ , mnAboveWUnderlineSize( 0 )
+ , mnAboveWUnderlineOffset( 0 )
+ , mnStrikeoutSize( 0 )
+ , mnStrikeoutOffset( 0 )
+ , mnBStrikeoutSize( 0 )
+ , mnBStrikeoutOffset( 0 )
+ , mnDStrikeoutSize( 0 )
+ , mnDStrikeoutOffset1( 0 )
+ , mnDStrikeoutOffset2( 0 )
+{
+ // initialize the used font name
+ sal_Int32 nTokenPos = 0;
+ SetFamilyName( OUString(GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos )) );
+ SetStyleName( rFontSelData.GetStyleName() );
+}
+
+bool FontMetricData::ShouldNotUseUnderlineMetrics() const
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return false;
+
+ css::uno::Sequence<OUString> rNoUnderlineMetricsList(
+ officecfg::Office::Common::Misc::FontsDontUseUnderlineMetrics::get());
+ if (comphelper::findValue(rNoUnderlineMetricsList, GetFamilyName()) != -1)
+ {
+ SAL_INFO("vcl.gdi.fontmetric", "Not using underline metrics for: " << GetFamilyName());
+ return true;
+ }
+ return false;
+}
+
+bool FontMetricData::ImplInitTextLineSizeHarfBuzz(LogicalFontInstance* pFont)
+{
+ if (ShouldNotUseUnderlineMetrics())
+ return false;
+
+ auto* pHbFont = pFont->GetHbFont();
+
+ hb_position_t nUnderlineSize;
+ if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_UNDERLINE_SIZE, &nUnderlineSize))
+ return false;
+ hb_position_t nUnderlineOffset;
+ if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_UNDERLINE_OFFSET, &nUnderlineOffset))
+ return false;
+ hb_position_t nStrikeoutSize;
+ if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, &nStrikeoutSize))
+ return false;
+ hb_position_t nStrikeoutOffset;
+ if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, &nStrikeoutOffset))
+ return false;
+
+ double fScale = 0;
+ pFont->GetScale(nullptr, &fScale);
+
+ double nOffset = -nUnderlineOffset * fScale;
+ double nSize = nUnderlineSize * fScale;
+ double nSize2 = nSize / 2.;
+ double nBSize = nSize * 2.;
+ double n2Size = nBSize / 3.;
+
+ mnUnderlineSize = std::ceil(nSize);
+ mnUnderlineOffset = std::ceil(nOffset);
+
+ mnBUnderlineSize = std::ceil(nBSize);
+ mnBUnderlineOffset = std::ceil(nOffset - nSize2);
+
+ mnDUnderlineSize = std::ceil(n2Size);
+ mnDUnderlineOffset1 = mnBUnderlineOffset;
+ mnDUnderlineOffset2 = mnBUnderlineOffset + mnDUnderlineSize * 2;
+
+ mnWUnderlineSize = mnBUnderlineSize;
+ mnWUnderlineOffset = std::ceil(nOffset + nSize);
+
+ nOffset = -nStrikeoutOffset * fScale;
+ nSize = nStrikeoutSize * fScale;
+ nSize2 = nSize / 2.;
+ nBSize = nSize * 2.;
+ n2Size = nBSize / 3.;
+
+ mnStrikeoutSize = std::ceil(nSize);
+ mnStrikeoutOffset = std::ceil(nOffset);
+
+ mnBStrikeoutSize = std::ceil(nBSize);
+ mnBStrikeoutOffset = std::round(nOffset - nSize2);
+
+ mnDStrikeoutSize = std::ceil(n2Size);
+ mnDStrikeoutOffset1 = mnBStrikeoutOffset;
+ mnDStrikeoutOffset2 = mnBStrikeoutOffset + mnDStrikeoutSize * 2;
+
+ return true;
+}
+
+void FontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
+{
+ mnBulletOffset = ( pDev->GetTextWidth( OUString( u' ' ) ) - pDev->GetTextWidth( OUString( u'\x00b7' ) ) ) >> 1 ;
+
+ if (ImplInitTextLineSizeHarfBuzz(const_cast<LogicalFontInstance*>(pDev->GetFontInstance())))
+ return;
+
+ tools::Long nDescent = mnDescent;
+ if ( nDescent <= 0 )
+ {
+ nDescent = mnAscent / 10;
+ if ( !nDescent )
+ nDescent = 1;
+ }
+
+ // #i55341# for some fonts it is not a good idea to calculate
+ // their text line metrics from the real font descent
+ // => work around this problem just for these fonts
+ if( 3*nDescent > mnAscent )
+ nDescent = mnAscent / 3;
+
+ tools::Long nLineHeight = ((nDescent*25)+50) / 100;
+ if ( !nLineHeight )
+ nLineHeight = 1;
+ tools::Long nLineHeight2 = nLineHeight / 2;
+ if ( !nLineHeight2 )
+ nLineHeight2 = 1;
+
+ tools::Long nBLineHeight = ((nDescent*50)+50) / 100;
+ if ( nBLineHeight == nLineHeight )
+ nBLineHeight++;
+ tools::Long nBLineHeight2 = nBLineHeight/2;
+ if ( !nBLineHeight2 )
+ nBLineHeight2 = 1;
+
+ tools::Long n2LineHeight = ((nDescent*16)+50) / 100;
+ if ( !n2LineHeight )
+ n2LineHeight = 1;
+ tools::Long n2LineDY = n2LineHeight;
+ /* #117909#
+ * add some pixels to minimum double line distance on higher resolution devices
+ */
+ tools::Long nMin2LineDY = 1 + pDev->GetDPIY()/150;
+ if ( n2LineDY < nMin2LineDY )
+ n2LineDY = nMin2LineDY;
+ tools::Long n2LineDY2 = n2LineDY/2;
+ if ( !n2LineDY2 )
+ n2LineDY2 = 1;
+
+ const vcl::Font& rFont ( pDev->GetFont() );
+ bool bCJKVertical = MsLangId::isCJK(rFont.GetLanguage()) && rFont.IsVertical();
+ tools::Long nUnderlineOffset = bCJKVertical ? mnDescent : (mnDescent/2 + 1);
+ tools::Long nStrikeoutOffset = rFont.IsVertical() ? -((mnAscent - mnDescent) / 2) : -((mnAscent - mnIntLeading) / 3);
+
+ mnUnderlineSize = nLineHeight;
+ mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
+
+ mnBUnderlineSize = nBLineHeight;
+ mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
+
+ mnDUnderlineSize = n2LineHeight;
+ mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
+ mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
+
+ tools::Long nWCalcSize = mnDescent;
+ if ( nWCalcSize < 6 )
+ {
+ if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
+ mnWUnderlineSize = nWCalcSize;
+ else
+ mnWUnderlineSize = 3;
+ }
+ else
+ mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
+
+
+ // Don't assume that wavelines are never placed below the descent, because for most fonts the waveline
+ // is drawn into the text
+ mnWUnderlineOffset = nUnderlineOffset;
+
+ mnStrikeoutSize = nLineHeight;
+ mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
+
+ mnBStrikeoutSize = nBLineHeight;
+ mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
+
+ mnDStrikeoutSize = n2LineHeight;
+ mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
+ mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
+
+}
+
+
+void FontMetricData::ImplInitAboveTextLineSize( const OutputDevice* pDev )
+{
+ ImplInitTextLineSize(pDev);
+
+ tools::Long nIntLeading = mnIntLeading;
+ // TODO: assess usage of nLeading below (changed in extleading CWS)
+ // if no leading is available, we assume 15% of the ascent
+ if ( nIntLeading <= 0 )
+ {
+ nIntLeading = mnAscent*15/100;
+ if ( !nIntLeading )
+ nIntLeading = 1;
+ }
+
+ tools::Long nCeiling = -mnAscent;
+
+ mnAboveUnderlineSize = mnUnderlineSize;
+ mnAboveUnderlineOffset = nCeiling + (nIntLeading - mnUnderlineSize + 1) / 2;
+
+ mnAboveBUnderlineSize = mnBUnderlineSize;
+ mnAboveBUnderlineOffset = nCeiling + (nIntLeading - mnBUnderlineSize + 1) / 2;
+
+ mnAboveDUnderlineSize = mnDUnderlineSize;
+ mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*mnDUnderlineSize + 1) / 2;
+ mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + mnDUnderlineSize + 1) / 2;
+
+ mnAboveWUnderlineSize = mnWUnderlineSize;
+ mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
+}
+
+void FontMetricData::ImplInitFlags( const OutputDevice* pDev )
+{
+ const vcl::Font& rFont ( pDev->GetFont() );
+ bool bCentered = true;
+ if (MsLangId::isCJK(rFont.GetLanguage()))
+ {
+ tools::Rectangle aRect;
+ pDev->GetTextBoundRect( aRect, u"\x3001"_ustr ); // Fullwidth fullstop
+ const auto nH = rFont.GetFontSize().Height();
+ const auto nB = aRect.Left();
+ // Use 18.75% as a threshold to define a centered fullwidth fullstop.
+ // In general, nB/nH < 5% for most Japanese fonts.
+ bCentered = nB > (((nH >> 1)+nH)>>3);
+ }
+ SetFullstopCenteredFlag( bCentered );
+}
+
+bool FontMetricData::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(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());
+ if (comphelper::findValue(rWinMetricFontList, aFontIdentifier) != -1)
+ {
+ SAL_INFO("vcl.gdi.fontmetric", "Using win metrics for: " << aFontIdentifier);
+ return true;
+ }
+ return false;
+}
+
+// These are “private” HarfBuzz metrics tags, they are supported by not exposed
+// in the public header. They are safe to 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 FontMetricData::ImplCalcLineSpacing(LogicalFontInstance* pFontInstance)
+{
+ mnAscent = mnDescent = mnExtLeading = mnIntLeading = 0;
+ auto* pFace = pFontInstance->GetFontFace();
+ auto* pHbFont = pFontInstance->GetHbFont();
+
+ double fScale = 0;
+ pFontInstance->GetScale(nullptr, &fScale);
+ double fAscent = 0, fDescent = 0, fExtLeading = 0;
+
+ auto aFvar(pFace->GetRawFontData(HB_TAG('f', 'v', 'a', 'r')));
+ if (!aFvar.empty())
+ {
+ // 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;
+ }
+ }
+ else
+ {
+ // This is not a variable font, we try to choose 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))
+ {
+ // 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;
+ }
+ }
+
+ // 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))
+ {
+ 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);
+ // Font data are big endian.
+ aStream.SetEndian(SvStreamEndian::BIG);
+ 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;
+ }
+ }
+ }
+
+ mnAscent = round(fAscent);
+ mnDescent = round(fDescent);
+ mnExtLeading = round(fExtLeading);
+
+ if (mnAscent || mnDescent)
+ mnIntLeading = mnAscent + mnDescent - mnHeight;
+}
+
+void FontMetricData::ImplInitBaselines(LogicalFontInstance *pFontInstance)
+{
+ hb_font_t* pHbFont = pFontInstance->GetHbFont();
+ double fScale = 0;
+ pFontInstance->GetScale(nullptr, &fScale);
+ hb_position_t nBaseline = 0;
+
+ if (hb_ot_layout_get_baseline(pHbFont,
+ HB_OT_LAYOUT_BASELINE_TAG_HANGING,
+ HB_DIRECTION_INVALID,
+ HB_SCRIPT_UNKNOWN,
+ HB_TAG_NONE,
+ &nBaseline))
+ {
+ mnHangingBaseline = nBaseline * fScale;
+ }
+ else
+ {
+ mnHangingBaseline = 0;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */