sw/source/core/inc/fntcache.hxx     |    3 +++
 sw/source/core/inc/swfont.hxx       |    4 ++++
 sw/source/core/text/inftxt.hxx      |    7 +++++++
 sw/source/core/text/itrform2.cxx    |    3 +++
 sw/source/core/text/itrpaint.cxx    |    2 +-
 sw/source/core/text/itrtxt.cxx      |    9 ++++++++-
 sw/source/core/text/porlin.cxx      |    1 +
 sw/source/core/text/porlin.hxx      |    5 +++++
 sw/source/core/txtnode/fntcache.cxx |   17 +++++++++++++++++
 sw/source/core/txtnode/swfont.cxx   |    6 ++++++
 10 files changed, 55 insertions(+), 2 deletions(-)

New commits:
commit fb8eb0ad9c3a5957a6e131490a7a8c97e5353ba2
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Sun May 1 14:07:01 2022 +0800
Commit:     Mark Hung <mark...@gmail.com>
CommitDate: Fri May 13 01:32:22 2022 +0200

    tdf#104930 aligning CTL text with hanging baseline.
    
    1. SwTextSizeInfo::GetHangingBaseline() calls SwFont::GetHangingBaseline() 
to obtain the hanging baseline value. Only CTL script handled, it always return 
0 for other two scripts. Eventually Outdev::GetFontMetric() and 
TextMetric::GetHangingBaseline() are called to obtain the hanging baseline 
value from vcl.
    
    2. SwTextFormatter::CalcAscent() sets the baseline value for the portion 
via SwTextSizeInfo::GetHangingBaseline().
    
    3. SwTextFormatter::InsertPortion() sets the maximum baseline value for the 
whole line.
    
    4. SwTextCursor::AdjustBaseLine() calculates the new baseline in case 
hanging baseline is available.
    
    Change-Id: I1aae7a34dfc953227b7873fc8e3af5cc7e2fbbff
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133668
    Tested-by: Jenkins
    Reviewed-by: Mark Hung <mark...@gmail.com>

diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx
index 4f58be568951..bea6663e1420 100644
--- a/sw/source/core/inc/fntcache.hxx
+++ b/sw/source/core/inc/fntcache.hxx
@@ -74,6 +74,8 @@ class SwFntObj final : public SwCacheObj
     sal_uInt16 m_nScrHeight;
     sal_uInt16 m_nPrtHeight;
     sal_uInt16 m_nPropWidth;
+    sal_uInt16 m_nScrHangingBaseline;
+    sal_uInt16 m_nPrtHangingBaseline;
     sal_uInt16 m_nZoom;
     bool m_bSymbol : 1;
     bool m_bPaintBlank : 1;
@@ -97,6 +99,7 @@ public:
     sal_uInt16 GetFontAscent( const SwViewShell *pSh, const OutputDevice& rOut 
);
     sal_uInt16 GetFontHeight( const SwViewShell *pSh, const OutputDevice& rOut 
);
     sal_uInt16 GetFontLeading( const SwViewShell *pSh, const OutputDevice& 
rOut );
+    sal_uInt16 GetFontHangingBaseline( const SwViewShell *pSh, const 
OutputDevice& rOut );
 
     void GuessLeading( const SwViewShell& rSh, const FontMetric& rMet );
 
diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx
index 40a4c2e8d66c..38936574a471 100644
--- a/sw/source/core/inc/swfont.hxx
+++ b/sw/source/core/inc/swfont.hxx
@@ -72,6 +72,7 @@ class SwSubFont final : public SvxFont
     bool IsSymbol( SwViewShell const *pSh );
     sal_uInt16 GetAscent( SwViewShell const *pSh, const OutputDevice& rOut );
     sal_uInt16 GetHeight( SwViewShell const *pSh, const OutputDevice& rOut );
+    sal_uInt16 GetHangingBaseline( SwViewShell const *pSh, const OutputDevice& 
rOut );
     Size GetTextSize_( SwDrawTextInfo& rInf );
     Size GetCapitalSize( SwDrawTextInfo& rInf );
     void DrawText_( SwDrawTextInfo &rInf, const bool bGrey );
@@ -328,6 +329,9 @@ public:
     sal_uInt16 GetHeight( SwViewShell const *pSh, const OutputDevice& rOut )
         { return m_aSub[m_nActual].GetHeight( pSh, rOut ); }
 
+    sal_uInt16 GetHangingBaseline( SwViewShell const *pSh, const OutputDevice& 
rOut )
+        { return m_nActual == SwFontScript::CTL ? 
m_aSub[m_nActual].GetHangingBaseline( pSh, rOut ) : 0; }
+
     void Invalidate()
         { m_bFontChg = m_bOrgChg = true; }
 
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index 7c7bf57afa56..1621b4f35a8f 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -267,6 +267,7 @@ public:
                             vcl::text::TextLayoutCache const*) const;
 
     sal_uInt16 GetAscent() const;
+    sal_uInt16 GetHangingBaseline() const;
 
     TextFrameIndex GetIdx() const { return m_nIdx; }
     void SetIdx(const TextFrameIndex nNew) { m_nIdx = nNew; }
@@ -715,6 +716,12 @@ inline sal_uInt16 SwTextSizeInfo::GetTextHeight() const
     return const_cast<SwFont*>(GetFont())->GetHeight( m_pVsh, *GetOut() );
 }
 
+inline sal_uInt16 SwTextSizeInfo::GetHangingBaseline() const
+{
+    assert(GetOut());
+    return const_cast<SwFont*>(GetFont())->GetHangingBaseline( m_pVsh, 
*GetOut() );
+}
+
 inline SwPosSize SwTextSizeInfo::GetTextSize( const OUString &rText ) const
 {
     return GetTextSize(m_pOut, nullptr, rText, TextFrameIndex(0), 
TextFrameIndex(rText.getLength()));
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 52d13e690481..e7bcde5983b8 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -341,6 +341,8 @@ void SwTextFormatter::InsertPortion( SwTextFormatInfo &rInf,
             m_pCurr->Height( pPor->Height(), pPor->IsTextPortion() );
         if( m_pCurr->GetAscent() < pPor->GetAscent() )
             m_pCurr->SetAscent( pPor->GetAscent() );
+        if( m_pCurr->GetHangingBaseline() < pPor->GetHangingBaseline() )
+            m_pCurr->SetHangingBaseline( pPor->GetHangingBaseline() );
 
         if 
(GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::MS_WORD_COMP_MIN_LINE_HEIGHT_BY_FLY))
         {
@@ -831,6 +833,7 @@ void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, 
SwLinePortion *pPor )
         if( bChg || bFirstPor || !pPor->GetAscent()
             || !rInf.GetLast()->InTextGrp() )
         {
+            pPor->SetHangingBaseline( rInf.GetHangingBaseline() );
             pPor->SetAscent( rInf.GetAscent()  );
             pPor->Height( rInf.GetTextHeight() );
             bCalc = true;
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index 7f783e40428f..3935630192dd 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -243,7 +243,7 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, 
SwSaveClip &rClip,
     SwTextGridItem const*const 
pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
     const bool bAdjustBaseLine =
         GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
-        ( nullptr != pGrid );
+        ( nullptr != pGrid ) || m_pCurr->GetHangingBaseline();
     const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
     if ( ! bAdjustBaseLine )
         GetInfo().Y( nLineBaseLine );
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx
index 8fb8334a83fa..53e084b03736 100644
--- a/sw/source/core/text/itrtxt.cxx
+++ b/sw/source/core/text/itrtxt.cxx
@@ -289,7 +289,14 @@ SwTwips SwTextCursor::AdjustBaseLine( const SwLineLayout& 
rLine,
                 [[fallthrough]];
             case SvxParaVertAlignItem::Align::Baseline :
                 // base line
-                nOfst = nOfst + rLine.GetAscent();
+                if (pPor && pPor->GetHangingBaseline())
+                {
+                    nOfst += rLine.GetAscent()          // Romn baseline of 
the line.
+                        - rLine.GetHangingBaseline()    // Hanging baseline of 
the line.
+                        + pPor->GetHangingBaseline();   // Romn baseline of 
the portion.
+                }
+                else
+                    nOfst = nOfst + rLine.GetAscent();
                 break;
         }
     }
diff --git a/sw/source/core/text/porlin.cxx b/sw/source/core/text/porlin.cxx
index d7b3a1a41e5b..d2e95e88249a 100644
--- a/sw/source/core/text/porlin.cxx
+++ b/sw/source/core/text/porlin.cxx
@@ -67,6 +67,7 @@ SwLinePortion::SwLinePortion( ) :
     mpNextPortion( nullptr ),
     mnLineLength( 0 ),
     mnAscent( 0 ),
+    mnHangingBaseline( 0 ),
     mnWhichPor( PortionType::NONE ),
     m_bJoinBorderWithPrev(false),
     m_bJoinBorderWithNext(false)
diff --git a/sw/source/core/text/porlin.hxx b/sw/source/core/text/porlin.hxx
index fb820f9bc577..3cd1d9fff942 100644
--- a/sw/source/core/text/porlin.hxx
+++ b/sw/source/core/text/porlin.hxx
@@ -56,6 +56,7 @@ protected:
     // Count of chars and spaces on the line
     TextFrameIndex mnLineLength;
     SwTwips mnAscent;      // Maximum ascender
+    SwTwips mnHangingBaseline;
 
     SwLinePortion();
 private:
@@ -82,6 +83,8 @@ public:
     SwTwips PrtWidth() const { return Width(); }
     void AddPrtWidth( const SwTwips nNew ) { Width( Width() + nNew ); }
     void SubPrtWidth( const SwTwips nNew ) { Width( Width() - nNew ); }
+    SwTwips GetHangingBaseline() const { return mnHangingBaseline; }
+    void SetHangingBaseline( const SwTwips nNewBaseline ) { mnHangingBaseline 
= nNewBaseline; }
 
     // Insert methods
     virtual SwLinePortion *Insert( SwLinePortion *pPortion );
@@ -184,6 +187,7 @@ inline SwLinePortion &SwLinePortion::operator=(const 
SwLinePortion &rPortion)
     *static_cast<SwPosSize*>(this) = rPortion;
     mnLineLength = rPortion.mnLineLength;
     mnAscent = rPortion.mnAscent;
+    mnHangingBaseline = rPortion.mnHangingBaseline;
     mnWhichPor = rPortion.mnWhichPor;
     m_bJoinBorderWithPrev = rPortion.m_bJoinBorderWithPrev;
     m_bJoinBorderWithNext = rPortion.m_bJoinBorderWithNext;
@@ -195,6 +199,7 @@ inline SwLinePortion::SwLinePortion(const SwLinePortion 
&rPortion) :
     mpNextPortion( nullptr ),
     mnLineLength( rPortion.mnLineLength ),
     mnAscent( rPortion.mnAscent ),
+    mnHangingBaseline( rPortion.mnHangingBaseline ),
     mnWhichPor( rPortion.mnWhichPor ),
     m_bJoinBorderWithPrev( rPortion.m_bJoinBorderWithPrev ),
     m_bJoinBorderWithNext( rPortion.m_bJoinBorderWithNext )
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 5623a35e1677..b3fe68906821 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -290,6 +290,7 @@ sal_uInt16 SwFntObj::GetFontAscent( const SwViewShell *pSh, 
const OutputDevice&
             const_cast<OutputDevice&>(rRefDev).SetFont( *m_pPrtFont );
             const FontMetric aOutMet( rRefDev.GetFontMetric() );
             m_nPrtAscent = o3tl::narrowing<sal_uInt16>(aOutMet.GetAscent());
+            m_nPrtHangingBaseline = 
o3tl::narrowing<sal_uInt16>(aOutMet.GetHangingBaseline());
             const_cast<OutputDevice&>(rRefDev).SetFont( aOldFnt );
         }
 
@@ -397,6 +398,21 @@ sal_uInt16 SwFntObj::GetFontLeading( const SwViewShell 
*pSh, const OutputDevice&
     return nRet;
 }
 
+sal_uInt16 SwFntObj::GetFontHangingBaseline( const SwViewShell* pSh, const 
OutputDevice& rOut )
+{
+    sal_uInt16 nRet = 0;
+    const OutputDevice& rRefDev = pSh ? pSh->GetRefDev() : rOut;
+
+    GetFontAscent(pSh, rOut);
+
+    if ( pSh && lcl_IsFontAdjustNecessary( rOut, rRefDev ) )
+        nRet = m_nScrHangingBaseline;
+    else
+        nRet = m_nPrtHangingBaseline;
+
+    return nRet;
+}
+
 //  pOut is the output device, not the reference device
 void SwFntObj::CreateScrFont( const SwViewShell& rSh, const OutputDevice& rOut 
)
 {
@@ -465,6 +481,7 @@ void SwFntObj::CreateScrFont( const SwViewShell& rSh, const 
OutputDevice& rOut )
     }
 
     m_nScrAscent = 
o3tl::narrowing<sal_uInt16>(pOut->GetFontMetric().GetAscent());
+    m_nScrHangingBaseline =  
o3tl::narrowing<sal_uInt16>(pOut->GetFontMetric().GetHangingBaseline());
     if ( USHRT_MAX == m_nScrHeight )
         m_nScrHeight = o3tl::narrowing<sal_uInt16>(pOut->GetTextHeight());
 
diff --git a/sw/source/core/txtnode/swfont.cxx 
b/sw/source/core/txtnode/swfont.cxx
index eb08f33696cc..30cd44851081 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -965,6 +965,12 @@ sal_uInt16 SwSubFont::GetHeight( SwViewShell const *pSh, 
const OutputDevice& rOu
     return nHeight; // + nLeading;
 }
 
+sal_uInt16 SwSubFont::GetHangingBaseline( SwViewShell const *pSh, const 
OutputDevice& rOut )
+{
+    SwFntAccess aFntAccess( m_nFontCacheId, m_nFontIndex, this, pSh );
+    return aFntAccess.Get()->GetFontHangingBaseline( pSh, rOut );
+}
+
 Size SwSubFont::GetTextSize_( SwDrawTextInfo& rInf )
 {
     // Robust: the font is supposed to be set already, but better safe than

Reply via email to