780 lines
26 KiB
C++
780 lines
26 KiB
C++
/* -*- 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 <editeng/svxfont.hxx>
|
|
|
|
#include <vcl/outdev.hxx>
|
|
#include <com/sun/star/i18n/CharType.hpp>
|
|
#include <com/sun/star/i18n/WordType.hpp>
|
|
#include <com/sun/star/i18n/XBreakIterator.hpp>
|
|
|
|
#include <fntcache.hxx>
|
|
#include <swfont.hxx>
|
|
#include <breakit.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <scriptinfo.hxx>
|
|
#include <fntcap.hxx>
|
|
|
|
using namespace ::com::sun::star::i18n;
|
|
|
|
namespace {
|
|
|
|
// The information encapsulated in SwCapitalInfo is required
|
|
// by the ::Do functions. They contain the information about
|
|
// the original string, whereas rDo.GetInf() contains information
|
|
// about the display string.
|
|
class SwCapitalInfo
|
|
{
|
|
public:
|
|
explicit SwCapitalInfo( const OUString& rOrigText ) :
|
|
rString( rOrigText ), nIdx( 0 ), nLen( 0 ) {};
|
|
const OUString& rString;
|
|
TextFrameIndex nIdx;
|
|
TextFrameIndex nLen;
|
|
};
|
|
|
|
}
|
|
|
|
// rFnt: required for CalcCaseMap
|
|
// rOrigString: The original string
|
|
// nOfst: Position of the substring in rOrigString
|
|
// nLen: Length if the substring in rOrigString
|
|
// nIdx: Refers to a position in the display string and should be mapped
|
|
// to a position in rOrigString
|
|
TextFrameIndex sw_CalcCaseMap(const SwFont& rFnt,
|
|
const OUString& rOrigString,
|
|
TextFrameIndex const nOfst,
|
|
TextFrameIndex const nLen,
|
|
TextFrameIndex const nIdx)
|
|
{
|
|
int j = 0;
|
|
const TextFrameIndex nEnd = nOfst + nLen;
|
|
OSL_ENSURE( sal_Int32(nEnd) <= rOrigString.getLength(), "sw_CalcCaseMap: Wrong parameters" );
|
|
|
|
// special case for title case:
|
|
const bool bTitle = SvxCaseMap::Capitalize == rFnt.GetCaseMap();
|
|
for (TextFrameIndex i = nOfst; i < nEnd; ++i)
|
|
{
|
|
OUString aTmp(rOrigString.copy(sal_Int32(i), 1));
|
|
|
|
if ( !bTitle ||
|
|
g_pBreakIt->GetBreakIter()->isBeginWord(
|
|
rOrigString, sal_Int32(i),
|
|
g_pBreakIt->GetLocale( rFnt.GetLanguage() ),
|
|
WordType::ANYWORD_IGNOREWHITESPACES ) )
|
|
aTmp = rFnt.GetActualFont().CalcCaseMap( aTmp );
|
|
|
|
j += aTmp.getLength();
|
|
|
|
if (TextFrameIndex(j) > nIdx)
|
|
return i;
|
|
}
|
|
|
|
return nOfst + nLen;
|
|
}
|
|
|
|
class SwDoCapitals
|
|
{
|
|
protected:
|
|
SwDrawTextInfo &m_rInf;
|
|
SwCapitalInfo* m_pCapInf; // refers to additional information
|
|
// required by the ::Do function
|
|
explicit SwDoCapitals ( SwDrawTextInfo &rInfo ) : m_rInf( rInfo ), m_pCapInf( nullptr ) { }
|
|
~SwDoCapitals() {}
|
|
public:
|
|
virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) = 0;
|
|
virtual void Do() = 0;
|
|
OutputDevice& GetOut() { return m_rInf.GetOut(); }
|
|
SwDrawTextInfo& GetInf() { return m_rInf; }
|
|
SwCapitalInfo* GetCapInf() const { return m_pCapInf; }
|
|
void SetCapInf( SwCapitalInfo& rNew ) { m_pCapInf = &rNew; }
|
|
};
|
|
|
|
namespace {
|
|
|
|
class SwDoGetCapitalSize : public SwDoCapitals
|
|
{
|
|
protected:
|
|
Size m_aTextSize;
|
|
|
|
public:
|
|
explicit SwDoGetCapitalSize( SwDrawTextInfo &rInfo ) : SwDoCapitals ( rInfo ) { }
|
|
virtual ~SwDoGetCapitalSize() {}
|
|
virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
|
|
virtual void Do() override;
|
|
const Size& GetSize() const { return m_aTextSize; }
|
|
};
|
|
|
|
}
|
|
|
|
void SwDoGetCapitalSize::Init( SwFntObj *, SwFntObj * )
|
|
{
|
|
m_aTextSize.setHeight(0);
|
|
m_aTextSize.setWidth(0);
|
|
}
|
|
|
|
void SwDoGetCapitalSize::Do()
|
|
{
|
|
m_aTextSize.AdjustWidth(m_rInf.GetSize().Width());
|
|
if( m_rInf.GetUpper() )
|
|
m_aTextSize.setHeight(m_rInf.GetSize().Height());
|
|
}
|
|
|
|
Size SwSubFont::GetCapitalSize( SwDrawTextInfo& rInf )
|
|
{
|
|
// Start:
|
|
const tools::Long nOldKern = rInf.GetKern();
|
|
rInf.SetKern( CheckKerning() );
|
|
rInf.SetPos( Point() );
|
|
rInf.SetSpace( 0 );
|
|
rInf.SetDrawSpace( false );
|
|
SwDoGetCapitalSize aDo( rInf );
|
|
DoOnCapitals( aDo );
|
|
Size aTextSize( aDo.GetSize() );
|
|
|
|
// End:
|
|
if( !aTextSize.Height() )
|
|
{
|
|
SV_STAT( nGetTextSize );
|
|
aTextSize.setHeight( short ( rInf.GetpOut()->GetTextHeight() ) );
|
|
}
|
|
rInf.SetKern( nOldKern );
|
|
return aTextSize;
|
|
}
|
|
|
|
namespace {
|
|
|
|
class SwDoGetCapitalBreak : public SwDoCapitals
|
|
{
|
|
protected:
|
|
tools::Long m_nTextWidth;
|
|
TextFrameIndex m_nBreak;
|
|
|
|
public:
|
|
SwDoGetCapitalBreak(SwDrawTextInfo& rInfo, tools::Long const nWidth)
|
|
: SwDoCapitals(rInfo)
|
|
, m_nTextWidth(nWidth)
|
|
, m_nBreak(-1)
|
|
{ }
|
|
virtual ~SwDoGetCapitalBreak() {}
|
|
virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
|
|
virtual void Do() override;
|
|
TextFrameIndex getBreak() const { return m_nBreak; }
|
|
};
|
|
|
|
}
|
|
|
|
void SwDoGetCapitalBreak::Init( SwFntObj *, SwFntObj * )
|
|
{
|
|
}
|
|
|
|
void SwDoGetCapitalBreak::Do()
|
|
{
|
|
if (!m_nTextWidth)
|
|
return;
|
|
|
|
if (m_rInf.GetSize().Width() < m_nTextWidth)
|
|
m_nTextWidth -= m_rInf.GetSize().Width();
|
|
else
|
|
{
|
|
TextFrameIndex nEnd = m_rInf.GetEnd();
|
|
m_nBreak = TextFrameIndex(GetOut().GetTextBreak(m_rInf.GetText(), m_nTextWidth,
|
|
sal_Int32(m_rInf.GetIdx()),
|
|
sal_Int32(m_rInf.GetLen()), m_rInf.GetKern()));
|
|
|
|
if (m_nBreak > nEnd || m_nBreak < TextFrameIndex(0))
|
|
m_nBreak = nEnd;
|
|
|
|
// m_nBreak may be relative to the display string. It has to be
|
|
// calculated relative to the original string:
|
|
if ( GetCapInf() )
|
|
{
|
|
if ( GetCapInf()->nLen != m_rInf.GetLen() )
|
|
m_nBreak = sw_CalcCaseMap( *m_rInf.GetFont(),
|
|
GetCapInf()->rString,
|
|
GetCapInf()->nIdx,
|
|
GetCapInf()->nLen, m_nBreak );
|
|
else
|
|
m_nBreak = m_nBreak + GetCapInf()->nIdx;
|
|
}
|
|
|
|
m_nTextWidth = 0;
|
|
}
|
|
}
|
|
|
|
TextFrameIndex SwFont::GetCapitalBreak( SwViewShell const * pSh, const OutputDevice* pOut,
|
|
const SwScriptInfo* pScript, const OUString& rText, tools::Long const nTextWidth,
|
|
TextFrameIndex const nIdx, TextFrameIndex const nLen)
|
|
{
|
|
// Start:
|
|
Point aPos( 0, 0 );
|
|
SwDrawTextInfo aInfo(pSh, *const_cast<OutputDevice*>(pOut), pScript, rText, nIdx, nLen,
|
|
/*layout context*/ std::nullopt, 0, false);
|
|
aInfo.SetPos( aPos );
|
|
aInfo.SetSpace( 0 );
|
|
aInfo.SetWrong( nullptr );
|
|
aInfo.SetGrammarCheck( nullptr );
|
|
aInfo.SetSmartTags( nullptr );
|
|
aInfo.SetDrawSpace( false );
|
|
aInfo.SetKern( CheckKerning() );
|
|
aInfo.SetKanaComp( pScript ? 0 : 100 );
|
|
aInfo.SetFont( this );
|
|
|
|
SwDoGetCapitalBreak aDo(aInfo, nTextWidth);
|
|
DoOnCapitals( aDo );
|
|
return aDo.getBreak();
|
|
}
|
|
|
|
namespace {
|
|
|
|
class SwDoDrawCapital : public SwDoCapitals
|
|
{
|
|
protected:
|
|
SwFntObj* m_pUpperFnt;
|
|
SwFntObj* m_pLowerFnt;
|
|
|
|
public:
|
|
explicit SwDoDrawCapital(SwDrawTextInfo& rInfo)
|
|
: SwDoCapitals(rInfo)
|
|
, m_pUpperFnt(nullptr)
|
|
, m_pLowerFnt(nullptr)
|
|
{ }
|
|
virtual ~SwDoDrawCapital() {}
|
|
virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
|
|
virtual void Do() override;
|
|
void DrawSpace( Point &rPos );
|
|
};
|
|
|
|
}
|
|
|
|
void SwDoDrawCapital::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
|
|
{
|
|
m_pUpperFnt = pUpperFont;
|
|
m_pLowerFnt = pLowerFont;
|
|
}
|
|
|
|
void SwDoDrawCapital::Do()
|
|
{
|
|
SV_STAT( nDrawText );
|
|
const sal_uInt16 nOrgWidth = m_rInf.GetWidth();
|
|
m_rInf.SetWidth( sal_uInt16(m_rInf.GetSize().Width()) );
|
|
if ( m_rInf.GetUpper() )
|
|
m_pUpperFnt->DrawText(m_rInf);
|
|
else
|
|
{
|
|
bool bOldBullet = m_rInf.GetBullet();
|
|
m_rInf.SetBullet( false );
|
|
m_pLowerFnt->DrawText(m_rInf);
|
|
m_rInf.SetBullet( bOldBullet );
|
|
}
|
|
|
|
OSL_ENSURE(m_pUpperFnt, "No upper font, dying soon!");
|
|
m_rInf.Shift(m_pUpperFnt->GetFont().GetOrientation());
|
|
m_rInf.SetWidth( nOrgWidth );
|
|
}
|
|
|
|
void SwDoDrawCapital::DrawSpace( Point &rPos )
|
|
{
|
|
tools::Long nDiff = m_rInf.GetPos().X() - rPos.X();
|
|
|
|
Point aPos( rPos );
|
|
const bool bSwitchL2R = m_rInf.GetFrame()->IsRightToLeft() &&
|
|
! m_rInf.IsIgnoreFrameRTL();
|
|
|
|
if ( bSwitchL2R )
|
|
m_rInf.GetFrame()->SwitchLTRtoRTL( aPos );
|
|
|
|
const vcl::text::ComplexTextLayoutFlags nMode = m_rInf.GetpOut()->GetLayoutMode();
|
|
const bool bBidiPor = ( bSwitchL2R !=
|
|
( vcl::text::ComplexTextLayoutFlags::Default != ( vcl::text::ComplexTextLayoutFlags::BiDiRtl & nMode ) ) );
|
|
|
|
if ( bBidiPor )
|
|
nDiff = -nDiff;
|
|
|
|
if ( m_rInf.GetFrame()->IsVertical() )
|
|
m_rInf.GetFrame()->SwitchHorizontalToVertical( aPos );
|
|
|
|
if ( nDiff )
|
|
{
|
|
m_rInf.ApplyAutoColor();
|
|
GetOut().DrawStretchText( aPos, nDiff,
|
|
u" "_ustr, 0, 2 );
|
|
}
|
|
rPos.setX( m_rInf.GetPos().X() + m_rInf.GetWidth() );
|
|
}
|
|
|
|
void SwSubFont::DrawCapital( SwDrawTextInfo &rInf )
|
|
{
|
|
// Precondition: rInf.GetPos() has already been calculated
|
|
|
|
rInf.SetDrawSpace( GetUnderline() != LINESTYLE_NONE ||
|
|
GetOverline() != LINESTYLE_NONE ||
|
|
GetStrikeout() != STRIKEOUT_NONE );
|
|
SwDoDrawCapital aDo( rInf );
|
|
DoOnCapitals( aDo );
|
|
}
|
|
|
|
namespace {
|
|
|
|
class SwDoCapitalCursorOfst : public SwDoCapitals
|
|
{
|
|
protected:
|
|
SwFntObj* m_pUpperFnt;
|
|
SwFntObj* m_pLowerFnt;
|
|
TextFrameIndex m_nCursor;
|
|
sal_uInt16 m_nOfst;
|
|
|
|
public:
|
|
SwDoCapitalCursorOfst(SwDrawTextInfo& rInfo, const sal_uInt16 nOfs)
|
|
: SwDoCapitals(rInfo)
|
|
, m_pUpperFnt(nullptr)
|
|
, m_pLowerFnt(nullptr)
|
|
, m_nCursor(0)
|
|
, m_nOfst(nOfs)
|
|
{ }
|
|
virtual ~SwDoCapitalCursorOfst() {}
|
|
virtual void Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont ) override;
|
|
virtual void Do() override;
|
|
|
|
TextFrameIndex GetCursor() const { return m_nCursor; }
|
|
};
|
|
|
|
}
|
|
|
|
void SwDoCapitalCursorOfst::Init( SwFntObj *pUpperFont, SwFntObj *pLowerFont )
|
|
{
|
|
m_pUpperFnt = pUpperFont;
|
|
m_pLowerFnt = pLowerFont;
|
|
}
|
|
|
|
void SwDoCapitalCursorOfst::Do()
|
|
{
|
|
if (!m_nOfst)
|
|
return;
|
|
|
|
if (static_cast<tools::Long>(m_nOfst) > m_rInf.GetSize().Width())
|
|
{
|
|
m_nOfst -= m_rInf.GetSize().Width();
|
|
m_nCursor = m_nCursor + m_rInf.GetLen();
|
|
}
|
|
else
|
|
{
|
|
SwDrawTextInfo aDrawInf(m_rInf.GetShell(), *m_rInf.GetpOut(), m_rInf.GetScriptInfo(),
|
|
m_rInf.GetText(), m_rInf.GetIdx(), m_rInf.GetLen(),
|
|
/*layout context*/ std::nullopt, 0, false);
|
|
aDrawInf.SetOffset(m_nOfst);
|
|
aDrawInf.SetKern( m_rInf.GetKern() );
|
|
aDrawInf.SetKanaComp( m_rInf.GetKanaComp() );
|
|
aDrawInf.SetFrame( m_rInf.GetFrame() );
|
|
aDrawInf.SetFont( m_rInf.GetFont() );
|
|
|
|
if ( m_rInf.GetUpper() )
|
|
{
|
|
aDrawInf.SetSpace( 0 );
|
|
m_nCursor = m_nCursor + m_pUpperFnt->GetModelPositionForViewPoint(aDrawInf);
|
|
}
|
|
else
|
|
{
|
|
aDrawInf.SetSpace( m_rInf.GetSpace() );
|
|
m_nCursor = m_nCursor + m_pLowerFnt->GetModelPositionForViewPoint(aDrawInf);
|
|
}
|
|
m_nOfst = 0;
|
|
}
|
|
}
|
|
|
|
TextFrameIndex SwSubFont::GetCapitalCursorOfst( SwDrawTextInfo& rInf )
|
|
{
|
|
const tools::Long nOldKern = rInf.GetKern();
|
|
rInf.SetKern( CheckKerning() );
|
|
SwDoCapitalCursorOfst aDo( rInf, rInf.GetOffset() );
|
|
rInf.SetPos( Point() );
|
|
rInf.SetDrawSpace( false );
|
|
DoOnCapitals( aDo );
|
|
rInf.SetKern( nOldKern );
|
|
return aDo.GetCursor();
|
|
}
|
|
|
|
namespace {
|
|
|
|
class SwDoDrawStretchCapital : public SwDoDrawCapital
|
|
{
|
|
const TextFrameIndex m_nStrLen;
|
|
const sal_uInt16 m_nCapWidth;
|
|
const sal_uInt16 m_nOrgWidth;
|
|
|
|
public:
|
|
virtual void Do() override;
|
|
|
|
SwDoDrawStretchCapital(SwDrawTextInfo& rInfo, const sal_uInt16 nCapitalWidth)
|
|
: SwDoDrawCapital(rInfo)
|
|
, m_nStrLen(rInfo.GetLen())
|
|
, m_nCapWidth(nCapitalWidth)
|
|
, m_nOrgWidth(rInfo.GetWidth())
|
|
{ }
|
|
};
|
|
|
|
}
|
|
|
|
void SwDoDrawStretchCapital::Do()
|
|
{
|
|
SV_STAT( nDrawStretchText );
|
|
tools::Long nPartWidth = m_rInf.GetSize().Width();
|
|
|
|
if( m_rInf.GetLen() )
|
|
{
|
|
// small caps and kerning
|
|
tools::Long nDiff = tools::Long(m_nOrgWidth) - tools::Long(m_nCapWidth);
|
|
if( nDiff )
|
|
{
|
|
nDiff *= sal_Int32(m_rInf.GetLen());
|
|
nDiff /= sal_Int32(m_nStrLen);
|
|
nDiff += nPartWidth;
|
|
if( 0 < nDiff )
|
|
nPartWidth = nDiff;
|
|
}
|
|
|
|
m_rInf.ApplyAutoColor();
|
|
|
|
Point aPos( m_rInf.GetPos() );
|
|
const bool bSwitchL2R = m_rInf.GetFrame()->IsRightToLeft() &&
|
|
! m_rInf.IsIgnoreFrameRTL();
|
|
|
|
if ( bSwitchL2R )
|
|
m_rInf.GetFrame()->SwitchLTRtoRTL( aPos );
|
|
|
|
if ( m_rInf.GetFrame()->IsVertical() )
|
|
m_rInf.GetFrame()->SwitchHorizontalToVertical( aPos );
|
|
|
|
// Optimise:
|
|
if (TextFrameIndex(1) >= m_rInf.GetLen())
|
|
GetOut().DrawText(aPos, m_rInf.GetText(), sal_Int32(m_rInf.GetIdx()),
|
|
sal_Int32(m_rInf.GetLen()));
|
|
else
|
|
GetOut().DrawStretchText(aPos, nPartWidth, m_rInf.GetText(),
|
|
sal_Int32(m_rInf.GetIdx()), sal_Int32(m_rInf.GetLen()));
|
|
}
|
|
const_cast<Point&>(m_rInf.GetPos()).AdjustX(nPartWidth );
|
|
}
|
|
|
|
void SwSubFont::DrawStretchCapital( SwDrawTextInfo &rInf )
|
|
{
|
|
// Precondition: rInf.GetPos() has already been calculated
|
|
|
|
if (rInf.GetLen() == TextFrameIndex(COMPLETE_STRING))
|
|
rInf.SetLen(TextFrameIndex(rInf.GetText().getLength()));
|
|
|
|
const Point aOldPos = rInf.GetPos();
|
|
const sal_uInt16 nCapWidth = o3tl::narrowing<sal_uInt16>( GetCapitalSize( rInf ).Width() );
|
|
rInf.SetPos(aOldPos);
|
|
|
|
rInf.SetDrawSpace( GetUnderline() != LINESTYLE_NONE ||
|
|
GetOverline() != LINESTYLE_NONE ||
|
|
GetStrikeout() != STRIKEOUT_NONE );
|
|
SwDoDrawStretchCapital aDo( rInf, nCapWidth );
|
|
DoOnCapitals( aDo );
|
|
}
|
|
|
|
void SwSubFont::DoOnCapitals( SwDoCapitals &rDo )
|
|
{
|
|
OSL_ENSURE( pLastFont, "SwFont::DoOnCapitals: No LastFont?!" );
|
|
|
|
tools::Long nKana = 0;
|
|
const OUString aText( CalcCaseMap( rDo.GetInf().GetText() ) );
|
|
TextFrameIndex nMaxPos = std::min(
|
|
TextFrameIndex(rDo.GetInf().GetText().getLength()) - rDo.GetInf().GetIdx(),
|
|
rDo.GetInf().GetLen() );
|
|
rDo.GetInf().SetLen( nMaxPos );
|
|
|
|
const OUString oldText = rDo.GetInf().GetText();
|
|
rDo.GetInf().SetText( aText );
|
|
TextFrameIndex nPos = rDo.GetInf().GetIdx();
|
|
TextFrameIndex nOldPos = nPos;
|
|
nMaxPos = nMaxPos + nPos;
|
|
|
|
// Look if the length of the original text and the ToUpper-converted
|
|
// text is different. If yes, do special handling.
|
|
SwCapitalInfo aCapInf(oldText);
|
|
bool bCaseMapLengthDiffers(aText.getLength() != oldText.getLength());
|
|
if ( bCaseMapLengthDiffers )
|
|
rDo.SetCapInf( aCapInf );
|
|
|
|
SwFntObj *pOldLast = pLastFont;
|
|
std::optional<SwFntAccess> oBigFontAccess;
|
|
SwFntObj *pBigFont;
|
|
std::optional<SwFntAccess> oSpaceFontAccess;
|
|
SwFntObj *pSpaceFont = nullptr;
|
|
|
|
const void* nFontCacheId2 = nullptr;
|
|
sal_uInt16 nIndex2 = 0;
|
|
SwSubFont aFont( *this );
|
|
Point aStartPos( rDo.GetInf().GetPos() );
|
|
|
|
const bool bTextLines = aFont.GetUnderline() != LINESTYLE_NONE
|
|
|| aFont.GetOverline() != LINESTYLE_NONE
|
|
|| aFont.GetStrikeout() != STRIKEOUT_NONE;
|
|
const bool bWordWise = bTextLines && aFont.IsWordLineMode() &&
|
|
rDo.GetInf().GetDrawSpace();
|
|
const tools::Long nTmpKern = rDo.GetInf().GetKern();
|
|
|
|
if ( bTextLines )
|
|
{
|
|
if ( bWordWise )
|
|
{
|
|
aFont.SetWordLineMode( false );
|
|
oSpaceFontAccess.emplace( nFontCacheId2, nIndex2, &aFont,
|
|
rDo.GetInf().GetShell() );
|
|
pSpaceFont = oSpaceFontAccess->Get();
|
|
}
|
|
else
|
|
pSpaceFont = pLastFont;
|
|
|
|
// Construct a font for the capitals:
|
|
aFont.SetUnderline( LINESTYLE_NONE );
|
|
aFont.SetOverline( LINESTYLE_NONE );
|
|
aFont.SetStrikeout( STRIKEOUT_NONE );
|
|
nFontCacheId2 = nullptr;
|
|
nIndex2 = 0;
|
|
oBigFontAccess.emplace( nFontCacheId2, nIndex2, &aFont,
|
|
rDo.GetInf().GetShell() );
|
|
pBigFont = oBigFontAccess->Get();
|
|
}
|
|
else
|
|
pBigFont = pLastFont;
|
|
|
|
// Older LO versions had 66 as the small caps percentage size, later changed to 80,
|
|
// therefore a backwards compatibility option is kept (otherwise layout is changed).
|
|
// NOTE: There are more uses of SMALL_CAPS_PERCENTAGE in editeng, but it seems they
|
|
// do not matter for Writer (and if they did it'd be pretty ugly to propagate
|
|
// the option there).
|
|
int smallCapsPercentage = m_bSmallCapsPercentage66 ? 66 : SMALL_CAPS_PERCENTAGE;
|
|
aFont.SetProportion( (aFont.GetPropr() * smallCapsPercentage ) / 100 );
|
|
nFontCacheId2 = nullptr;
|
|
nIndex2 = 0;
|
|
std::optional<SwFntAccess> oSmallFontAccess( std::in_place, nFontCacheId2, nIndex2, &aFont,
|
|
rDo.GetInf().GetShell() );
|
|
SwFntObj *pSmallFont = oSmallFontAccess->Get();
|
|
|
|
rDo.Init( pBigFont, pSmallFont );
|
|
OutputDevice* pOutSize = pSmallFont->GetPrt();
|
|
if( !pOutSize )
|
|
pOutSize = &rDo.GetOut();
|
|
OutputDevice* pOldOut = &rDo.GetOut();
|
|
|
|
const LanguageType eLng = LANGUAGE_DONTKNOW == GetLanguage()
|
|
? LANGUAGE_SYSTEM : GetLanguage();
|
|
|
|
if( nPos < nMaxPos )
|
|
{
|
|
nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->endOfCharBlock(
|
|
oldText, sal_Int32(nPos),
|
|
g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
|
|
if (nPos < TextFrameIndex(0))
|
|
nPos = nOldPos;
|
|
else if( nPos > nMaxPos )
|
|
nPos = nMaxPos;
|
|
}
|
|
|
|
while( nOldPos < nMaxPos )
|
|
{
|
|
|
|
// The lower ones...
|
|
if( nOldPos != nPos )
|
|
{
|
|
SV_STAT( nGetTextSize );
|
|
pLastFont = pSmallFont;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
|
|
|
|
// #107816#, #i14820#
|
|
if( bCaseMapLengthDiffers )
|
|
{
|
|
// Build an own 'changed' string for the given part of the
|
|
// source string and use it. That new string may differ in length
|
|
// from the source string.
|
|
const OUString aNewText = CalcCaseMap(
|
|
oldText.copy(sal_Int32(nOldPos), sal_Int32(nPos-nOldPos)));
|
|
aCapInf.nIdx = nOldPos;
|
|
aCapInf.nLen = nPos - nOldPos;
|
|
rDo.GetInf().SetTextIdxLen(aNewText, TextFrameIndex(0), TextFrameIndex(aNewText.getLength()));
|
|
}
|
|
else
|
|
{
|
|
rDo.GetInf().SetIdxLen(nOldPos, nPos - nOldPos);
|
|
}
|
|
|
|
rDo.GetInf().SetUpper( false );
|
|
rDo.GetInf().SetOut( *pOutSize );
|
|
Size aPartSize = pSmallFont->GetTextSize( rDo.GetInf() );
|
|
nKana += rDo.GetInf().GetKanaDiff();
|
|
rDo.GetInf().SetOut( *pOldOut );
|
|
if( nTmpKern && nPos < nMaxPos )
|
|
aPartSize.AdjustWidth(nTmpKern );
|
|
rDo.GetInf().SetSize( aPartSize );
|
|
rDo.Do();
|
|
nOldPos = nPos;
|
|
}
|
|
nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->nextCharBlock(
|
|
oldText, sal_Int32(nPos),
|
|
g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
|
|
if (nPos < TextFrameIndex(0) || nPos > nMaxPos)
|
|
nPos = nMaxPos;
|
|
OSL_ENSURE( nPos, "nextCharBlock not implemented?" );
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
if( !nPos )
|
|
nPos = nMaxPos;
|
|
#endif
|
|
// The upper ones...
|
|
if( nOldPos != nPos )
|
|
{
|
|
const tools::Long nSpaceAdd = rDo.GetInf().GetSpace() / SPACING_PRECISION_FACTOR;
|
|
|
|
do
|
|
{
|
|
rDo.GetInf().SetUpper( true );
|
|
pLastFont = pBigFont;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
|
|
TextFrameIndex nTmp;
|
|
if( bWordWise )
|
|
{
|
|
nTmp = nOldPos;
|
|
while (nTmp < nPos && CH_BLANK == oldText[sal_Int32(nTmp)])
|
|
++nTmp;
|
|
if( nOldPos < nTmp )
|
|
{
|
|
pLastFont = pSpaceFont;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(),
|
|
rDo.GetOut() );
|
|
static_cast<SwDoDrawCapital&>(rDo).DrawSpace( aStartPos );
|
|
pLastFont = pBigFont;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(),
|
|
rDo.GetOut() );
|
|
|
|
// #107816#, #i14820#
|
|
if( bCaseMapLengthDiffers )
|
|
{
|
|
// Build an own 'changed' string for the given part of the
|
|
// source string and use it. That new string may differ in length
|
|
// from the source string.
|
|
const OUString aNewText = CalcCaseMap(
|
|
oldText.copy(sal_Int32(nOldPos), sal_Int32(nTmp-nOldPos)));
|
|
aCapInf.nIdx = nOldPos;
|
|
aCapInf.nLen = nTmp - nOldPos;
|
|
rDo.GetInf().SetIdx(TextFrameIndex(0));
|
|
rDo.GetInf().SetLen(TextFrameIndex(aNewText.getLength()));
|
|
rDo.GetInf().SetText( aNewText );
|
|
}
|
|
else
|
|
{
|
|
rDo.GetInf().SetIdx( nOldPos );
|
|
rDo.GetInf().SetLen( nTmp - nOldPos );
|
|
}
|
|
|
|
rDo.GetInf().SetOut( *pOutSize );
|
|
Size aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
|
|
nKana += rDo.GetInf().GetKanaDiff();
|
|
rDo.GetInf().SetOut( *pOldOut );
|
|
if( nSpaceAdd )
|
|
aPartSize.AdjustWidth(nSpaceAdd * sal_Int32(nTmp - nOldPos));
|
|
if( nTmpKern && nPos < nMaxPos )
|
|
aPartSize.AdjustWidth(nTmpKern );
|
|
rDo.GetInf().SetSize( aPartSize );
|
|
rDo.Do();
|
|
aStartPos = rDo.GetInf().GetPos();
|
|
nOldPos = nTmp;
|
|
}
|
|
|
|
while (nTmp < nPos && CH_BLANK != oldText[sal_Int32(nTmp)])
|
|
++nTmp;
|
|
}
|
|
else
|
|
nTmp = nPos;
|
|
if( nTmp > nOldPos )
|
|
{
|
|
// #107816#, #i14820#
|
|
if( bCaseMapLengthDiffers )
|
|
{
|
|
// Build an own 'changed' string for the given part of the
|
|
// source string and use it. That new string may differ in length
|
|
// from the source string.
|
|
const OUString aNewText = CalcCaseMap(
|
|
oldText.copy(sal_Int32(nOldPos), sal_Int32(nTmp-nOldPos)));
|
|
aCapInf.nIdx = nOldPos;
|
|
aCapInf.nLen = nTmp - nOldPos;
|
|
rDo.GetInf().SetTextIdxLen( aNewText, TextFrameIndex(0), TextFrameIndex(aNewText.getLength()));
|
|
}
|
|
else
|
|
{
|
|
rDo.GetInf().SetIdxLen( nOldPos, nTmp - nOldPos );
|
|
}
|
|
|
|
rDo.GetInf().SetOut( *pOutSize );
|
|
Size aPartSize = pBigFont->GetTextSize( rDo.GetInf() );
|
|
nKana += rDo.GetInf().GetKanaDiff();
|
|
rDo.GetInf().SetOut( *pOldOut );
|
|
if( !bWordWise && rDo.GetInf().GetSpace() )
|
|
{
|
|
for (TextFrameIndex nI = nOldPos; nI < nPos; ++nI)
|
|
{
|
|
if (CH_BLANK == oldText[sal_Int32(nI)])
|
|
aPartSize.AdjustWidth(nSpaceAdd );
|
|
}
|
|
}
|
|
if( nTmpKern && nPos < nMaxPos )
|
|
aPartSize.AdjustWidth(nTmpKern );
|
|
rDo.GetInf().SetSize( aPartSize );
|
|
rDo.Do();
|
|
nOldPos = nTmp;
|
|
}
|
|
} while( nOldPos != nPos );
|
|
}
|
|
nPos = TextFrameIndex(g_pBreakIt->GetBreakIter()->endOfCharBlock(
|
|
oldText, sal_Int32(nPos),
|
|
g_pBreakIt->GetLocale( eLng ), CharType::LOWERCASE_LETTER));
|
|
if (nPos < TextFrameIndex(0) || nPos > nMaxPos)
|
|
nPos = nMaxPos;
|
|
OSL_ENSURE( nPos, "endOfCharBlock not implemented?" );
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
if( !nPos )
|
|
nPos = nMaxPos;
|
|
#endif
|
|
}
|
|
|
|
// clean up:
|
|
if( pBigFont != pOldLast )
|
|
oBigFontAccess.reset();
|
|
|
|
if( bTextLines )
|
|
{
|
|
if( rDo.GetInf().GetDrawSpace() )
|
|
{
|
|
pLastFont = pSpaceFont;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
|
|
static_cast<SwDoDrawCapital&>( rDo ).DrawSpace( aStartPos );
|
|
}
|
|
if ( bWordWise )
|
|
oSpaceFontAccess.reset();
|
|
}
|
|
pLastFont = pOldLast;
|
|
pLastFont->SetDevFont( rDo.GetInf().GetShell(), rDo.GetOut() );
|
|
|
|
oSmallFontAccess.reset();
|
|
rDo.GetInf().SetText(oldText);
|
|
rDo.GetInf().SetKanaDiff( nKana );
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|