/* -*- 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 .
*/
/** * Calculates if a drop caps portion intersects with a fly * The width and height of the drop caps portion are passed as arguments, * the position is calculated from the values in rInf
*/ staticbool lcl_IsDropFlyInter(const SwTextFormatInfo& rInf, SwTwips nWidth, sal_uInt16 nHeight)
{ const SwTextFly& rTextFly = rInf.GetTextFly(); if( rTextFly.IsOn() )
{
SwRect aRect( rInf.GetTextFrame()->getFrameArea().Pos(), Size( nWidth, nHeight) );
aRect.Pos() += rInf.GetTextFrame()->getFramePrintArea().Pos();
aRect.Pos().AdjustX(rInf.X() );
aRect.Pos().setY( rInf.Y() );
aRect = rTextFly.GetFrame( aRect ); return aRect.HasArea();
}
/** * If a dropcap is found the return value is true otherwise false. The * drop cap sizes passed back by reference are font height, drop height * and drop descent.
*/ bool SwTextNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDescent) const
{
rFontHeight = 0;
rDropHeight = 0;
rDropDescent =0;
// Return (0,0) if there is no drop cap at this paragraph if( 1 >= rDrop.GetLines() ||
( !rDrop.GetChars() && !rDrop.GetWholeWord() ) )
{ returnfalse;
}
// get text frame
SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this); for( SwTextFrame* pLastFrame = aIter.First(); pLastFrame; pLastFrame = aIter.Next() )
{ // Only (master-) text frames can have a drop cap. if (!pLastFrame->IsFollow() &&
pLastFrame->GetTextNodeForFirstText() == this)
{
if ( !pLastFrame->IsEmpty() )
{ const SwParaPortion* pPara = pLastFrame->GetPara();
OSL_ENSURE( pPara, "GetDropSize could not find the ParaPortion, I'll guess the drop cap size" );
void SwDropPortion::PaintDrop( const SwTextPaintInfo &rInf ) const
{ // normal output is being done during the normal painting if( ! m_nDropHeight || ! m_pPart || m_nLines == 1 ) return;
// set the lying values const SwTwips nOldHeight = Height(); const SwTwips nOldWidth = Width(); const SwTwips nOldAscent = GetAscent(); const SwTwips nOldPosY = rInf.Y(); const SwTwips nOldPosX = rInf.X(); const SwParaPortion *pPara = rInf.GetParaPortion(); const Point aOutPos( nOldPosX, nOldPosY - pPara->GetAscent()
- pPara->GetRealHeight() + pPara->Height() ); // make good for retouching
// Set baseline const_cast<SwTextPaintInfo&>(rInf).Y( aOutPos.Y() + m_nDropHeight );
// Always adapt Clipregion to us, never set it off using the existing ClipRect // as that could be set for the line
SwRect aClipRect; if ( rInf.OnWin() )
{
aClipRect = SwRect( aOutPos, SvLSize() );
aClipRect.Intersection( rInf.GetPaintRect() );
}
SwSaveClip aClip( const_cast<OutputDevice*>(rInf.GetOut()) );
aClip.ChgClip( aClipRect, rInf.GetTextFrame() );
// Just do, what we always do ...
PaintText( rInf );
// save old values const_cast<SwDropPortion*>(this)->Height( nOldHeight ); const_cast<SwDropPortion*>(this)->Width( nOldWidth ); const_cast<SwDropPortion*>(this)->SetAscent( nOldAscent ); const_cast<SwTextPaintInfo&>(rInf).Y( nOldPosY );
}
void SwDropPortion::Paint( const SwTextPaintInfo &rInf ) const
{ // normal output is being done here if( !(! m_nDropHeight || ! m_pPart || 1 == m_nLines) ) return;
// make sure that font is not rotated
std::unique_ptr<SwFont> pTmpFont; if ( rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() ) )
{
pTmpFont.reset(new SwFont( *rInf.GetFont() ));
pTmpFont->SetVertical( 0_deg10, rInf.GetTextFrame()->IsVertical() );
}
SwFontSave aFontSave( rInf, pTmpFont.get() ); // for text inside drop portions we let vcl handle the text directions
SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
aLayoutModeModifier.SetAuto();
while( GetCurr()->IsDummy() )
{ if ( !Next() ) break;
}
// If we have only one line we return 0 if( GetNext() || GetDropLines() == 1 )
{ for( ; nDropLns < nLines; nDropLns++ )
{ if ( GetCurr()->IsDummy() ) break; else
{
CalcAscentAndHeight( nAscent, nHeight );
nDropHght = nDropHght + nHeight;
m_bRegisterOn = bRegisterOld;
} if ( !Next() )
{
nDropLns++; break;
}
}
// We hit the line ascent when reaching the last line!
nDropHght = nDropHght - nHeight;
nDropHght = nDropHght + nAscent;
Top();
}
m_bRegisterOn = bRegisterOld;
SetDropDescent( nHeight - nAscent );
SetDropHeight( nDropHght );
SetDropLines( nDropLns ); // Find old position! while( pOldCurr != GetCurr() )
{ if( !Next() )
{
OSL_ENSURE( false, "SwTextFormatter::_CalcDropHeight: left Toulouse" ); break;
}
}
}
/** * We assume that the font height doesn't change and that at first there * are at least as many lines, as the DropCap-setting claims
*/ void SwTextFormatter::GuessDropHeight( const sal_uInt16 nLines )
{
OSL_ENSURE( nLines, "GuessDropHeight: Give me more Lines!" );
SwTwips nAscent = 0;
SwTwips nHeight = 0;
SetDropLines( nLines ); if ( GetDropLines() > 1 )
{
CalcRealHeight();
CalcAscentAndHeight( nAscent, nHeight );
}
SetDropDescent( nHeight - nAscent );
SetDropHeight( nHeight * nLines - GetDropDescent() );
}
// first or second round? if ( !( GetDropHeight() || IsOnceMore() ) )
{ if ( GetNext() )
CalcDropHeight( m_pDropFormat->GetLines() ); else
GuessDropHeight( m_pDropFormat->GetLines() );
}
// the DropPortion if( GetDropHeight() )
pDropPor = new SwDropPortion( GetDropLines(), GetDropHeight(),
GetDropDescent(), m_pDropFormat->GetDistance() ); else
pDropPor = new SwDropPortion( 0,0,0,m_pDropFormat->GetDistance() );
pDropPor->SetLen( nPorLen );
// If it was not possible to create a proper drop cap portion // due to avoiding endless loops. We return a drop cap portion // with an empty SwDropCapPart. For these portions the current // font is used. if ( GetDropLines() < 2 )
{
SetPaintDrop( true ); return pDropPor;
}
while ( nNextChg < nPorLen )
{ // check for attribute changes and if the portion has to split:
Seek( nNextChg );
// the font is deleted in the destructor of the drop portion part
SwFont* pTmpFnt = new SwFont( *rInf.GetFont() ); if ( pFormat )
{ const SwAttrSet& rSet = pFormat->GetAttrSet();
pTmpFnt->SetDiffFnt(&rSet, &m_pFrame->GetDoc().getIDocumentSettingAccess());
}
// we do not allow a vertical font for the drop portion
pTmpFnt->SetVertical( 0_deg10, rInf.GetTextFrame()->IsVertical() );
// we have to calculate a new font scaling factor if // 1. we did not find a scaling factor in the cache or // 2. we are not allowed to use the cache because the drop portion // consists of more than one part if( nTmpIdx >= DROP_CACHE_SIZE || ! bUseCache )
{
++m_nIndex;
m_nIndex %= DROP_CACHE_SIZE;
nTmpIdx = m_nIndex;
// we get the rectangle that covers all chars bool bHaveGlyphRect = pOut->GetTextBoundRect( aRect, rInf.GetText(), 0,
sal_Int32(nIdx), sal_Int32(pCurrPart->GetLen()))
&& ! aRect.IsEmpty();
if ( ! bHaveGlyphRect )
{ // getting glyph boundaries failed for some reason, // we take the window for calculating sizes if ( pWin )
{ if ( ! bWinUsed )
{
bWinUsed = true;
aOldMap = pWin->GetMapMode( );
pWin->SetMapMode( MapMode( MapUnit::MapTwip ) );
aOldFnt = pWin->GetFont();
}
pWin->SetFont( rFnt.GetActualFont() );
bHaveGlyphRect = pWin->GetTextBoundRect( aRect, rInf.GetText(), 0,
sal_Int32(nIdx), sal_Int32(pCurrPart->GetLen()))
&& ! aRect.IsEmpty();
} if (!bHaveGlyphRect)
{ // We do not have a window or our window could not // give us glyph boundaries.
aRect = tools::Rectangle( Point( 0, 0 ), Size( 0, nAscent ) );
}
}
// extend rectangle to the baseline to avoid of giant dashes, // quotation marks, bullet, asterisks etc. if ( bKeepBaseline && aRect.Top() < 0 )
{
aRect.SetBottom(0);
aRect.SetTop(aRect.Top() - nAscent/60);
}
// Now we (hopefully) have a bounding rectangle for the // glyphs of the current portion and the ascent of the current // font
// reset font size and proportion
rFnt.SetSize( aOldSize, rFnt.GetActual() );
rFnt.SetProportion( nOldProp );
// Modify the bounding rectangle with the borders // Robust: If the padding is so big as drop cap letter has no enough space than // remove all padding. if( rFnt.GetTopBorderSpace() + rFnt.GetBottomBorderSpace() >= nWishedHeight )
{
rFnt.SetTopBorderDist(0);
rFnt.SetBottomBorderDist(0);
rFnt.SetRightBorderDist(0);
rFnt.SetLeftBorderDist(0);
}
// did made any new calculations or did we use the cache? if ( -1 == nFactor )
{
nFactor = m_aFactor[ nTmpIdx ];
nDescent = m_aDescent[ nTmpIdx ];
} else
nDescent = -nDescent;
while ( pCurrPart )
{ // scale current font
SwFont& rFnt = pCurrPart->GetFont();
Size aNewSize( 0, ( nFactor * rFnt.GetHeight( rFnt.GetActual() ) ) / 1000 );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.