editeng/source/items/svxfont.cxx             |   28 ++++++++++++------------
 include/editeng/svxfont.hxx                  |    6 -----
 include/vcl/font.hxx                         |    3 ++
 include/vcl/rendercontext/SalLayoutFlags.hxx |    3 +-
 vcl/inc/impfont.hxx                          |    1 
 vcl/source/font/font.cxx                     |   31 ++++++++++++++++++++++++++-
 vcl/source/gdi/CommonSalLayout.cxx           |    6 ++++-
 vcl/source/outdev/text.cxx                   |    3 ++
 vcl/source/text/ImplLayoutArgs.cxx           |    1 
 9 files changed, 59 insertions(+), 23 deletions(-)

New commits:
commit b9f0caad5d9e628f82d5148dfc7d2436d32817e2
Author:     Khaled Hosny <kha...@aliftype.com>
AuthorDate: Tue Aug 23 04:13:28 2022 +0200
Commit:     خالد حسني <kha...@aliftype.com>
CommitDate: Tue Aug 23 09:24:52 2022 +0200

    tdf#66819: Disable ligatures with character spacing
    
    When character spacing is not zero, optional ligatures should be
    disabled (e.g. this what CSS requires and what browsers implement:
    https://drafts.csswg.org/css-text/#letter-spacing-property).
    
    This disables both “liga” and “clig” OpenType features because they are
    optional features and are enabled by default, it does not disable “rlig”
    because it is for orthographically-required ligatures, nor “dlig” or
    “hlig” because they are disabled by default.
    
    The character spacing values (confusingly called kerning in the source
    code) are moved from SvxFont to vcl::Font so it can’t be accessed in
    OutputDevice and pass the relevant flag to SalLayout.
    
    Change-Id: Ieacc875df3896ad7a63ae8d116f4c6ff7265b9a5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138711
    Tested-by: Jenkins
    Reviewed-by: خالد حسني <kha...@aliftype.com>

diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx
index ac360873824a..868b830c63cc 100644
--- a/editeng/source/items/svxfont.cxx
+++ b/editeng/source/items/svxfont.cxx
@@ -42,7 +42,7 @@ static tools::Long GetTextArray( const OutputDevice* pOut, 
const OUString& rStr,
 
 SvxFont::SvxFont()
 {
-    nKern = nEsc = 0;
+    nEsc = 0;
     nPropr = 100;
     eCaseMap = SvxCaseMap::NotMapped;
     SetLanguage(LANGUAGE_SYSTEM);
@@ -51,7 +51,7 @@ SvxFont::SvxFont()
 SvxFont::SvxFont( const vcl::Font &rFont )
     : Font( rFont )
 {
-    nKern = nEsc = 0;
+    nEsc = 0;
     nPropr = 100;
     eCaseMap = SvxCaseMap::NotMapped;
     SetLanguage(LANGUAGE_SYSTEM);
@@ -60,7 +60,6 @@ SvxFont::SvxFont( const vcl::Font &rFont )
 SvxFont::SvxFont( const SvxFont &rFont )
     : Font( rFont )
 {
-    nKern = rFont.GetFixKerning();
     nEsc  = rFont.GetEscapement();
     nPropr = rFont.GetPropr();
     eCaseMap = rFont.GetCaseMap();
@@ -409,7 +408,7 @@ vcl::Font SvxFont::ChgPhysFont(OutputDevice& rOut) const
 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const OUString &rTxt,
                          const sal_Int32 nIdx, const sal_Int32 nLen ) const
 {
-    if ( !IsCaseMap() && !IsKern() )
+    if ( !IsCaseMap() && !IsFixKerning() )
         return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ),
                      pOut->GetTextHeight() );
 
@@ -439,8 +438,9 @@ Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, 
const OUString &rTxt,
         aTxtSize.setWidth(nWidth);
     }
 
-    if( IsKern() && ( nLen > 1 ) )
+    if( IsFixKerning() && ( nLen > 1 ) )
     {
+        auto nKern = GetFixKerning();
         std::vector<sal_Int32> aDXArray(nLen);
         GetTextArray(pOut, rTxt, &aDXArray, nIdx, nLen);
         tools::Long nOldValue = aDXArray[0];
@@ -461,7 +461,7 @@ Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, 
const OUString &rTxt,
 
 Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut )
 {
-    if ( !IsCaseMap() && !IsKern() )
+    if ( !IsCaseMap() && !IsFixKerning() )
         return Size( pOut->GetTextWidth( "" ), pOut->GetTextHeight() );
 
     Size aTxtSize;
@@ -477,14 +477,14 @@ Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut )
 Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const OUString &rTxt,
                          const sal_Int32 nIdx, const sal_Int32 nLen, 
std::vector<sal_Int32>* pDXArray ) const
 {
-    if ( !IsCaseMap() && !IsKern() )
+    if ( !IsCaseMap() && !IsFixKerning() )
         return Size( GetTextArray( pOut, rTxt, pDXArray, nIdx, nLen ),
                      pOut->GetTextHeight() );
 
     std::vector<sal_Int32>  aDXArray;
 
     // We always need pDXArray to count the number of kern spaces
-    if (!pDXArray && IsKern() && nLen > 1)
+    if (!pDXArray && IsFixKerning() && nLen > 1)
     {
         pDXArray = &aDXArray;
         aDXArray.reserve(nLen);
@@ -498,8 +498,9 @@ Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, 
const OUString &rTxt,
         aTxtSize.setWidth( GetTextArray( pOut, CalcCaseMap( rTxt ),
                            pDXArray, nIdx, nLen ) );
 
-    if( IsKern() && ( nLen > 1 ) )
+    if( IsFixKerning() && ( nLen > 1 ) )
     {
+        auto nKern = GetFixKerning();
         tools::Long nOldValue = (*pDXArray)[0];
         tools::Long nSpaceSum = nKern;
         (*pDXArray)[0] += nSpaceSum;
@@ -560,7 +561,7 @@ void SvxFont::QuickDrawText( OutputDevice *pOut,
 {
 
     // Font has to be selected in OutputDevice...
-    if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() )
+    if ( !IsCaseMap() && !IsCapital() && !IsFixKerning() && !IsEsc() )
     {
         DrawTextArray( pOut, rPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen );
         return;
@@ -587,7 +588,7 @@ void SvxFont::QuickDrawText( OutputDevice *pOut,
     }
     else
     {
-        if ( IsKern() && pDXArray.empty() )
+        if ( IsFixKerning() && pDXArray.empty() )
         {
             Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );
 
@@ -687,7 +688,6 @@ SvxFont& SvxFont::operator=( const SvxFont& rFont )
     eCaseMap = rFont.eCaseMap;
     nEsc = rFont.nEsc;
     nPropr = rFont.nPropr;
-    nKern = rFont.nKern;
     return *this;
 }
 
@@ -744,7 +744,7 @@ Size SvxFont::GetCapitalSize( const OutputDevice *pOut, 
const OUString &rTxt,
                              const sal_Int32 nIdx, const sal_Int32 nLen) const
 {
     // Start:
-    SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, nIdx, 
nLen, nKern );
+    SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, nIdx, 
nLen, GetFixKerning() );
     DoOnCapitals( aDo );
     Size aTxtSize( aDo.GetSize() );
 
@@ -856,7 +856,7 @@ void SvxFont::DrawCapital( OutputDevice *pOut,
                const Point &rPos, const OUString &rTxt,
                const sal_Int32 nIdx, const sal_Int32 nLen ) const
 {
-    SvxDoDrawCapital aDo( const_cast<SvxFont 
*>(this),pOut,rTxt,nIdx,nLen,rPos,nKern );
+    SvxDoDrawCapital aDo( const_cast<SvxFont 
*>(this),pOut,rTxt,nIdx,nLen,rPos,GetFixKerning() );
     DoOnCapitals( aDo );
 }
 
diff --git a/include/editeng/svxfont.hxx b/include/editeng/svxfont.hxx
index ac4ec390128a..f4810ba25640 100644
--- a/include/editeng/svxfont.hxx
+++ b/include/editeng/svxfont.hxx
@@ -41,7 +41,6 @@ class EDITENG_DLLPUBLIC SvxFont : public vcl::Font
     SvxCaseMap   eCaseMap;      // Text Markup
     short nEsc;                 // Degree of Superscript/Subscript
     sal_uInt8  nPropr;          // Degree of reduction of the font height
-    short nKern;                // Kerning in Pt
 
 public:
     SvxFont();
@@ -59,17 +58,12 @@ public:
     void SetProprRel( const sal_uInt8 nNewPropr )
         { SetPropr( static_cast<sal_uInt8>( 
static_cast<tools::Long>(nNewPropr) * static_cast<tools::Long>(nPropr) / 100 ) 
); }
 
-    // Kerning
-    short GetFixKerning() const { return nKern; }
-    void  SetFixKerning( const short nNewKern ) { nKern = nNewKern; }
-
     SvxCaseMap GetCaseMap() const { return eCaseMap; }
     void    SetCaseMap( const SvxCaseMap eNew ) { eCaseMap = eNew; }
 
     // Is-Methods:
     bool IsCaseMap() const { return SvxCaseMap::NotMapped != eCaseMap; }
     bool IsCapital() const { return SvxCaseMap::SmallCaps == eCaseMap; }
-    bool IsKern() const { return 0 != nKern; }
     bool IsEsc() const { return 0 != nEsc; }
 
     // Consider Upper case, Lower case letters etc.
diff --git a/include/vcl/font.hxx b/include/vcl/font.hxx
index b371990ba11c..222f7d962774 100644
--- a/include/vcl/font.hxx
+++ b/include/vcl/font.hxx
@@ -133,6 +133,9 @@ public:
     void                SetKerning( FontKerning nKerning );
     FontKerning         GetKerning() const;
     bool                IsKerning() const;
+    void                SetFixKerning(const short nSpacing);
+    short               GetFixKerning() const;
+    bool                IsFixKerning() const;
 
     void                SetOutline( bool bOutline );
     bool                IsOutline() const;
diff --git a/include/vcl/rendercontext/SalLayoutFlags.hxx 
b/include/vcl/rendercontext/SalLayoutFlags.hxx
index e8c5901d8528..576a4abd8fbd 100644
--- a/include/vcl/rendercontext/SalLayoutFlags.hxx
+++ b/include/vcl/rendercontext/SalLayoutFlags.hxx
@@ -30,12 +30,13 @@ enum class SalLayoutFlags
     DisableKerning = 0x0010,
     KerningAsian = 0x0020,
     Vertical = 0x0040,
+    DisableLigatures = 0x0200,
     ForFallback = 0x2000,
     GlyphItemsOnly = 0x4000,
 };
 namespace o3tl
 {
-template <> struct typed_flags<SalLayoutFlags> : 
is_typed_flags<SalLayoutFlags, 0x6077>
+template <> struct typed_flags<SalLayoutFlags> : 
is_typed_flags<SalLayoutFlags, 0x6277>
 {
 };
 }
diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx
index a63e2a27d1c2..450e227b34ad 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -119,6 +119,7 @@ private:
     FontRelief          meRelief;
     FontEmphasisMark    meEmphasisMark;
     FontKerning         meKerning;
+    short               mnSpacing;
     Size                maAverageFontSize;
     rtl_TextEncoding    meCharSet;
 
diff --git a/vcl/source/font/font.cxx b/vcl/source/font/font.cxx
index 941fe3d6fc0a..90cdba4163db 100644
--- a/vcl/source/font/font.cxx
+++ b/vcl/source/font/font.cxx
@@ -247,6 +247,22 @@ bool Font::IsKerning() const
     return mpImplFont->meKerning != FontKerning::NONE;
 }
 
+void Font::SetFixKerning( short nSpacing )
+{
+    if (const_cast<const ImplType&>(mpImplFont)->mnSpacing != nSpacing)
+        mpImplFont->mnSpacing = nSpacing;
+}
+
+short Font::GetFixKerning() const
+{
+    return mpImplFont->mnSpacing;
+}
+
+bool Font::IsFixKerning() const
+{
+    return mpImplFont->mnSpacing != 0;
+}
+
 void Font::SetWeight( FontWeight eWeight )
 {
     if (const_cast<const ImplType&>(mpImplFont)->GetWeightNoAsk() != eWeight)
@@ -539,6 +555,12 @@ SvStream& ReadImplFont( SvStream& rIStm, ImplFont& 
rImplFont, tools::Long& rnNor
         rnNormedFontScaling = nNormedFontScaling;
     }
 
+    if( aCompat.GetVersion() >= 5 )
+    {
+        rIStm.ReadInt16( nTmps16 );
+        rImplFont.mnSpacing = nTmps16;
+    }
+
     // Relief
     // CJKContextLanguage
 
@@ -548,7 +570,8 @@ SvStream& ReadImplFont( SvStream& rIStm, ImplFont& 
rImplFont, tools::Long& rnNor
 SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont, 
tools::Long nNormedFontScaling )
 {
     // tdf#127471 increase to version 4
-    VersionCompatWrite aCompat( rOStm, 4 );
+    // tdf#66819 increase to version 5
+    VersionCompatWrite aCompat( rOStm, 5 );
 
     TypeSerializer aSerializer(rOStm);
     rOStm.WriteUniOrByteString( rImplFont.GetFamilyName(), 
rOStm.GetStreamCharSet() );
@@ -584,6 +607,8 @@ SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& 
rImplFont, tools::Long
     // new in version 4, NormedFontScaling
     rOStm.WriteInt32(nNormedFontScaling);
 
+    // new in version 5
+    rOStm.WriteInt16( rImplFont.mnSpacing );
     return rOStm;
 }
 
@@ -961,6 +986,7 @@ ImplFont::ImplFont() :
     meRelief( FontRelief::NONE ),
     meEmphasisMark( FontEmphasisMark::NONE ),
     meKerning( FontKerning::FontSpecific ),
+    mnSpacing( 0 ),
     meCharSet( RTL_TEXTENCODING_DONTKNOW ),
     maLanguageTag( LANGUAGE_DONTKNOW ),
     maCJKLanguageTag( LANGUAGE_DONTKNOW ),
@@ -993,6 +1019,7 @@ ImplFont::ImplFont( const ImplFont& rImplFont ) :
     meRelief( rImplFont.meRelief ),
     meEmphasisMark( rImplFont.meEmphasisMark ),
     meKerning( rImplFont.meKerning ),
+    mnSpacing( rImplFont.mnSpacing ),
     maAverageFontSize( rImplFont.maAverageFontSize ),
     meCharSet( rImplFont.meCharSet ),
     maLanguageTag( rImplFont.maLanguageTag ),
@@ -1056,6 +1083,7 @@ bool ImplFont::EqualIgnoreColor( const ImplFont& rOther ) 
const
     ||  (mbOutline      != rOther.mbOutline)
     ||  (mbShadow       != rOther.mbShadow)
     ||  (meKerning      != rOther.meKerning)
+    ||  (mnSpacing      != rOther.mnSpacing)
     ||  (mbTransparent  != rOther.mbTransparent) )
         return false;
 
@@ -1100,6 +1128,7 @@ size_t ImplFont::GetHashValueIgnoreColor() const
     o3tl::hash_combine( hash, mbOutline );
     o3tl::hash_combine( hash, mbShadow );
     o3tl::hash_combine( hash, meKerning );
+    o3tl::hash_combine( hash, mnSpacing );
     o3tl::hash_combine( hash, mbTransparent );
 
     return hash;
diff --git a/vcl/source/gdi/CommonSalLayout.cxx 
b/vcl/source/gdi/CommonSalLayout.cxx
index 73b7e58ae43d..81f495afe981 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -318,10 +318,14 @@ bool 
GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay
         maFeatures.push_back({ HB_TAG('k','e','r','n'), 0, 0, 
static_cast<unsigned int>(-1) });
     }
 
-    if (rFontSelData.GetPitch() == PITCH_FIXED)
+    if (rArgs.mnFlags & SalLayoutFlags::DisableLigatures)
     {
         SAL_INFO("vcl.harfbuzz", "Disabling ligatures for font: " << 
rFontSelData.maTargetName);
+
+        // Both of these are optional ligatures, enabled by default but not for
+        // orthographically-required ligatures.
         maFeatures.push_back({ HB_TAG('l','i','g','a'), 0, 0, 
static_cast<unsigned int>(-1) });
+        maFeatures.push_back({ HB_TAG('c','l','i','g'), 0, 0, 
static_cast<unsigned int>(-1) });
     }
 
     ParseFeatures(rFontSelData.maTargetName);
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index d2c8855a2543..823362c6c071 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -1177,6 +1177,9 @@ vcl::text::ImplLayoutArgs 
OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
         nLayoutFlags |= SalLayoutFlags::KerningAsian;
     if( maFont.IsVertical() )
         nLayoutFlags |= SalLayoutFlags::Vertical;
+    if( maFont.IsFixKerning() ||
+        ( mpFontInstance && mpFontInstance->GetFontSelectPattern().GetPitch() 
== PITCH_FIXED ) )
+        nLayoutFlags |= SalLayoutFlags::DisableLigatures;
 
     if( meTextLanguage ) //TODO: (mnTextLayoutMode & 
vcl::text::ComplexTextLayoutFlags::SubstituteDigits)
     {
diff --git a/vcl/source/text/ImplLayoutArgs.cxx 
b/vcl/source/text/ImplLayoutArgs.cxx
index 943de7d2eb75..e837ca411014 100644
--- a/vcl/source/text/ImplLayoutArgs.cxx
+++ b/vcl/source/text/ImplLayoutArgs.cxx
@@ -269,6 +269,7 @@ std::ostream& operator<<(std::ostream& s, 
vcl::text::ImplLayoutArgs const& rArgs
         TEST(DisableKerning);
         TEST(KerningAsian);
         TEST(Vertical);
+        TEST(DisableLigatures);
         TEST(ForFallback);
 #undef TEST
         s << "}";

Reply via email to