diff options
author | Mark Hung <marklh9@gmail.com> | 2018-01-20 23:35:44 +0800 |
---|---|---|
committer | Mark Hung <marklh9@gmail.com> | 2018-01-21 08:43:14 +0100 |
commit | d1bc14b318c9a412a761d243085da0895a1aed4a (patch) | |
tree | ea4dbeaf9c053974e690dc8b856fb4b66638ffe5 | |
parent | 121f6f3c79ea2dceb7cc3d61a56f5a56a1cb0d0d (diff) |
tdf#35301 Formatting ruby text on right side.
* BuildMultiPortion(): preserve room for the ruby text by
increasing the width of the last portion of the base text.
This allows the ruby portion to be selected with the base
text so that they seemd like attached to each other.
* CalcSize(): we need to be careful because the width and
height of the base text line is swapped.
* PaintMultiPortion(): render the base text on top of the
preserved room mentioned above, by shifting the position
back.
* SwRubyPortion(): RubyPortion::RIGHT is designed for
horizontal writing mode only. In vertical writing
mode it fallback to RubyPortion::ABOVE.
Change-Id: I5291e32221b6b2fc1c3e152b3a5defe857428163
Reviewed-on: https://gerrit.libreoffice.org/48244
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Mark Hung <marklh9@gmail.com>
-rw-r--r-- | sw/source/core/text/itrform2.cxx | 17 | ||||
-rw-r--r-- | sw/source/core/text/pormulti.cxx | 79 | ||||
-rw-r--r-- | sw/source/core/text/pormulti.hxx | 19 |
3 files changed, 70 insertions, 45 deletions
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 1346390589cc..fbaa66dedc7b 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -1252,24 +1252,9 @@ SwLinePortion *SwTextFormatter::NewPortion( SwTextFormatInfo &rInf ) pTmp = new SwBidiPortion( nEnd, pCreate->nLevel ); else if ( SwMultiCreatorId::Ruby == pCreate->nId ) { - Seek( rInf.GetIdx() ); - bool bRubyTop = false; - bool* pRubyPos = nullptr; - - if ( rInf.SnapToGrid() ) - { - SwTextGridItem const*const pGrid( - GetGridItem(GetTextFrame()->FindPageFrame())); - if ( pGrid ) - { - bRubyTop = ! pGrid->GetRubyTextBelow(); - pRubyPos = &bRubyTop; - } - } - pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(), *GetTextFrame()->GetTextNode()->getIDocumentSettingAccess(), - nEnd, 0, pRubyPos ); + nEnd, 0, rInf ); } else if( SwMultiCreatorId::Rotate == pCreate->nId ) pTmp = new SwRotatedPortion( *pCreate, nEnd, diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx index b35760f763ba..03f7e8592625 100644 --- a/sw/source/core/text/pormulti.cxx +++ b/sw/source/core/text/pormulti.cxx @@ -92,7 +92,17 @@ void SwMultiPortion::CalcSize( SwTextFormatter& rLine, SwTextFormatInfo &rInf ) } else SetAscent( GetAscent() + pLay->GetAscent() ); - Height( Height() + pLay->Height() ); + + // Increase the line height, except for ruby text on the right. + if ( !IsRuby() || !OnRight() || pLay == &GetRoot() ) + Height( Height() + pLay->Height() ); + else + { + // We already added the width after building the portion, + // so no need to add it twice. + break; + } + if( Width() < pLay->Width() ) Width( pLay->Width() ); pLay = pLay->GetNext(); @@ -538,7 +548,7 @@ SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, sal_Int32 nEnd ) : nAdjustment( rRuby.GetAdjustment() ) { SetDirection( rRuby.GetDirection() ); - SetTop( rRuby.OnTop() ); + SetRubyPosition( rRuby.GetRubyPosition() ); SetRuby(); } @@ -547,7 +557,7 @@ SwRubyPortion::SwRubyPortion( const SwRubyPortion& rRuby, sal_Int32 nEnd ) : SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt, const IDocumentSettingAccess& rIDocumentSettingAccess, sal_Int32 nEnd, sal_Int32 nOffs, - const bool* pForceRubyPos ) + const SwTextSizeInfo &rInf ) : SwMultiPortion( nEnd ) { SetRuby(); @@ -557,11 +567,22 @@ SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt, nAdjustment = rRuby.GetAdjustment(); nRubyOffset = nOffs; - // in grid mode we force the ruby text to the upper or lower line - if ( pForceRubyPos ) - SetTop( *pForceRubyPos ); - else - SetTop( ! rRuby.GetPosition() ); + const SwTextFrame *pFrame = rInf.GetTextFrame(); + RubyPosition ePos = static_cast<RubyPosition>( rRuby.GetPosition() ); + + // RIGHT is designed for horizontal writing mode only. + if ( ePos == RubyPosition::RIGHT && pFrame->IsVertical() ) + ePos = RubyPosition::ABOVE; + + // In grid mode we force the ruby text to the upper or lower line + if ( rInf.SnapToGrid() ) + { + SwTextGridItem const*const pGrid( GetGridItem(pFrame->FindPageFrame()) ); + if ( pGrid ) + ePos = pGrid->GetRubyTextBelow() ? RubyPosition::BELOW : RubyPosition::ABOVE; + } + + SetRubyPosition( ePos ); const SwCharFormat *const pFormat = static_txtattr_cast<SwTextRuby const*>(rCreate.pAttr)->GetCharFormat(); @@ -573,7 +594,7 @@ SwRubyPortion::SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt, pRubyFont->SetDiffFnt( &rSet, &rIDocumentSettingAccess ); // we do not allow a vertical font for the ruby text - pRubyFont->SetVertical( rFnt.GetOrientation() ); + pRubyFont->SetVertical( rFnt.GetOrientation() , OnRight() ); } else pRubyFont = nullptr; @@ -1393,6 +1414,9 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, OSL_ENSURE( nullptr == GetInfo().GetUnderFnt() || rMulti.IsBidi(), " Only BiDi portions are allowed to use the common underlining font" ); + if ( rMulti.IsRuby() ) + GetInfo().SetRuby( rMulti.OnTop() ); + do { if ( bHasGrid && pGrid->IsSquaredMode() ) @@ -1431,6 +1455,13 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, else GetInfo().X( nOfst + AdjustBaseLine( *pLay, pPor ) ); } + else if ( rMulti.IsRuby() && rMulti.OnRight() && GetInfo().IsRuby() ) + { + SwTwips nLineDiff = std::max(( rMulti.GetRoot().Height() - pPor->Width() ) / 2, 0 ); + GetInfo().Y( nOfst + nLineDiff ); + // Draw the ruby text on top of the preserved space. + GetInfo().X( GetInfo().X() - pPor->Height() ); + } else GetInfo().Y( nOfst + AdjustBaseLine( *pLay, pPor ) ); @@ -1535,6 +1566,11 @@ void SwTextPainter::PaintMultiPortion( const SwRect &rPaint, { nOfst += rMulti.GetRoot().Height(); } + } + else if ( rMulti.IsRuby() && rMulti.OnRight() ) + { + GetInfo().SetDirection( DIR_TOP2BOTTOM ); + GetInfo().SetRuby( true ); } else { GetInfo().X( nTmpX ); @@ -1840,6 +1876,15 @@ bool SwTextFormatter::BuildMultiPortion( SwTextFormatInfo &rInf, BuildPortions( aTmp ); + if ( rMulti.OnRight() ) + { + // The ruby text on the right is vertical. + // The width and the height are swapped. + SwTwips nHeight = rMulti.GetRoot().GetNext()->GetPortion()->Height(); + // Keep room for the ruby text. + rMulti.GetRoot().FindLastPortion()->AddPrtWidth( nHeight ); + } + aTmp.SetSnapToGrid( bOldGridModeAllowed ); rMulti.CalcSize( *this, aInf ); @@ -2191,24 +2236,10 @@ SwLinePortion* SwTextFormatter::MakeRestPortion( const SwLineLayout* pLine, pTmp = new SwBidiPortion( nMultiPos, pCreate->nLevel ); else if( pHelpMulti->IsRuby() ) { - bool bRubyTop; - bool* pRubyPos = nullptr; - - if ( GetInfo().SnapToGrid() ) - { - SwTextGridItem const*const pGrid( - GetGridItem(m_pFrame->FindPageFrame())); - if ( pGrid ) - { - bRubyTop = ! pGrid->GetRubyTextBelow(); - pRubyPos = &bRubyTop; - } - } - pTmp = new SwRubyPortion( *pCreate, *GetInfo().GetFont(), *m_pFrame->GetTextNode()->getIDocumentSettingAccess(), nMultiPos, static_cast<const SwRubyPortion*>(pHelpMulti)->GetRubyOffset(), - pRubyPos ); + GetInfo() ); } else if( pHelpMulti->HasRotation() ) pTmp = new SwRotatedPortion( nMultiPos, pHelpMulti->GetDirection() ); diff --git a/sw/source/core/text/pormulti.hxx b/sw/source/core/text/pormulti.hxx index 2061c035c6e7..62cb236f5bb8 100644 --- a/sw/source/core/text/pormulti.hxx +++ b/sw/source/core/text/pormulti.hxx @@ -43,6 +43,13 @@ enum class SwMultiCreatorId Double, Ruby, Rotate, Bidi }; +enum class RubyPosition : sal_uInt16 +{ + ABOVE = 0, + BELOW = 1, + RIGHT = 2 +}; + struct SwMultiCreator { const SwTextAttr* pAttr; @@ -80,10 +87,10 @@ class SwMultiPortion : public SwLinePortion bool bDouble :1; // Double line bool bRuby :1; // Phonetics bool bBidi :1; - bool bTop :1; // Phonetic position bool bFormatted :1; // Already formatted bool bFollowField :1; // Field follow inside bool bFlyInContent:1; // Fly as character inside + RubyPosition eRubyPosition; // Phonetic position sal_uInt8 nDirection:2; // Direction (0/90/180/270 degrees) protected: explicit SwMultiPortion(sal_Int32 nEnd) @@ -92,10 +99,10 @@ protected: , bDouble(false) , bRuby(false) , bBidi(false) - , bTop(false) , bFormatted(false) , bFollowField(false) , bFlyInContent(false) + , eRubyPosition( RubyPosition::ABOVE ) , nDirection(0) { SetWhichPor(POR_MULTI); @@ -104,7 +111,7 @@ protected: void SetDouble() { bDouble = true; } void SetRuby() { bRuby = true; } void SetBidi() { bBidi = true; } - void SetTop( bool bNew ) { bTop = bNew; } + void SetRubyPosition( RubyPosition eNew ) { eRubyPosition = eNew; } void SetTab1( bool bNew ) { bTab1 = bNew; } void SetTab2( bool bNew ) { bTab2 = bNew; } void SetDirection( sal_uInt8 nNew ) { nDirection = nNew; } @@ -125,7 +132,9 @@ public: bool IsDouble() const { return bDouble; } bool IsRuby() const { return bRuby; } bool IsBidi() const { return bBidi; } - bool OnTop() const { return bTop; } + bool OnTop() const { return eRubyPosition == RubyPosition::ABOVE; } + bool OnRight() const { return eRubyPosition == RubyPosition::RIGHT; } + RubyPosition GetRubyPosition() const { return eRubyPosition; } void ActualizeTabulator(); virtual void Paint( const SwTextPaintInfo &rInf ) const override; @@ -188,7 +197,7 @@ public: SwRubyPortion( const SwMultiCreator& rCreate, const SwFont& rFnt, const IDocumentSettingAccess& rIDocumentSettingAccess, sal_Int32 nEnd, sal_Int32 nOffs, - const bool* pForceRubyPos ); + const SwTextSizeInfo &rInf ); void CalcRubyOffset(); void Adjust( SwTextFormatInfo &rInf ) |