Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  svxfont.cxx   Sprache: 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/glyphitemcache.hxx>
#include <vcl/metric.hxx>
#include <vcl/outdev.hxx>
#include <vcl/print.hxx>
#include <tools/debug.hxx>
#include <tools/gen.hxx>
#include <tools/poly.hxx>
#include <unotools/charclass.hxx>
#include <com/sun/star/i18n/KCharacterType.hpp>
#include <editeng/escapementitem.hxx>
#include <editeng/smallcaps.hxx>
#include <sal/log.hxx>
#include <limits>

static tools::Long GetTextArray( const OutputDevice* pOut, const OUString& rStr, KernArray* pDXAry,
                                 sal_Int32 nIndex, sal_Int32 nLen )

{
    const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOut, rStr, nIndex, nLen);
    return basegfx::fround<tools::Long>(
        pOut->GetTextArray(rStr, pDXAry, nIndex, nLen, true, nullptr, layoutGlyphs).nWidth);
}

SvxFont::SvxFont()
{
    nEsc = 0;
    nPropr = 100;
    eCaseMap = SvxCaseMap::NotMapped;
    SetLanguage(LANGUAGE_SYSTEM);
}

SvxFont::SvxFont( const vcl::Font &rFont )
    : Font( rFont )
{
    nEsc = 0;
    nPropr = 100;
    eCaseMap = SvxCaseMap::NotMapped;
    SetLanguage(LANGUAGE_SYSTEM);
}

SvxFont::SvxFont( const SvxFont &rFont )
    : Font( rFont )
{
    nEsc  = rFont.GetEscapement();
    nPropr = rFont.GetPropr();
    eCaseMap = rFont.GetCaseMap();
    SetLanguage(rFont.GetLanguage());
}

void SvxFont::SetNonAutoEscapement(short nNewEsc, const OutputDevice* pOutDev)
{
    nEsc = nNewEsc;
    if ( abs(nEsc) == DFLT_ESC_AUTO_SUPER )
    {
        double fAutoAscent = .8;
        double fAutoDescent = .2;
        if ( pOutDev )
        {
            const FontMetric aFontMetric = pOutDev->GetFontMetric();
            double fFontHeight = aFontMetric.GetAscent() + aFontMetric.GetDescent();
            if ( fFontHeight )
            {
                fAutoAscent = aFontMetric.GetAscent() / fFontHeight;
                fAutoDescent = aFontMetric.GetDescent() / fFontHeight;
            }
        }

        if ( nEsc == DFLT_ESC_AUTO_SUPER )
            nEsc = fAutoAscent * (100 - nPropr);
        else //DFLT_ESC_AUTO_SUB
            nEsc = fAutoDescent * -(100 - nPropr);
    }

    if ( nEsc > MAX_ESC_POS )
        nEsc = MAX_ESC_POS;
    else if  ( nEsc < -MAX_ESC_POS )
        nEsc = -MAX_ESC_POS;
}

tools::Polygon SvxFont::DrawArrow( OutputDevice &rOut, const tools::Rectangle& rRect,
    const Size& rSize, const Color& rCol, bool bLeftOrTop, bool bVertical )
{
    tools::Polygon aPoly;
    Point aTmp;
    Point aNxt;
    if (bVertical)
    {
        tools::Long nLeft = ((rRect.Left() + rRect.Right()) / 2) - (rSize.Height() / 2);
        tools::Long nRight = ((rRect.Left() + rRect.Right()) / 2) + (rSize.Height() / 2);
        tools::Long nMid = (rRect.Left() + rRect.Right()) / 2;
        tools::Long nTop = ((rRect.Top() + rRect.Bottom()) / 2) - (rSize.Height() / 2);
        tools::Long nBottom = nTop + rSize.Height();
        if (nTop < rRect.Top())
        {
            if (bLeftOrTop)
            {
                nTop = rRect.Top();
                nBottom = rRect.Bottom();
            }
            else
            {
                nTop = rRect.Bottom();
                nBottom = rRect.Bottom() - (rSize.Height() / 2);
            }
        }
        aTmp.setX(nRight);
        aTmp.setY(nBottom);
        aNxt.setX(nMid);
        aNxt.setY(nTop);
        aPoly.Insert(0, aTmp);
        aPoly.Insert(0, aNxt);
        aTmp.setX(nLeft);
        aPoly.Insert(0, aTmp);
    }
    else
    {
        tools::Long nLeft = (rRect.Left() + rRect.Right() - rSize.Width()) / 2;
        tools::Long nRight = nLeft + rSize.Width();
        tools::Long nMid = (rRect.Top() + rRect.Bottom()) / 2;
        tools::Long nTop = nMid - rSize.Height() / 2;
        tools::Long nBottom = nTop + rSize.Height();
        if (nLeft < rRect.Left())
        {
            nLeft = rRect.Left();
            nRight = rRect.Right();
        }
        aTmp.setX(bLeftOrTop ? nLeft : nRight);
        aTmp.setY(nMid);
        aNxt.setX(bLeftOrTop ? nRight : nLeft);
        aNxt.setY(nTop);
        aPoly.Insert(0, aTmp);
        aPoly.Insert(0, aNxt);
        aNxt.setY(nBottom);
        aPoly.Insert(0, aNxt);
    }
    Color aOldLineColor = rOut.GetLineColor();
    Color aOldFillColor = rOut.GetFillColor();
    rOut.SetFillColor( rCol );
    rOut.SetLineColor( COL_BLACK );
    rOut.DrawPolygon( aPoly );
    rOut.DrawLine( aTmp, aNxt );
    rOut.SetLineColor( aOldLineColor );
    rOut.SetFillColor( aOldFillColor );
    return aPoly;
}

OUString SvxFont::CalcCaseMap(const OUString &rTxt) const
{
    if (!IsCaseMap() || rTxt.isEmpty())
        return rTxt;
    OUString aTxt(rTxt);
    // I still have to get the language
    const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
                             ? LANGUAGE_SYSTEM : GetLanguage();

    CharClass aCharClass(( LanguageTag(eLang) ));

    switch( eCaseMap )
    {
        case SvxCaseMap::SmallCaps:
        case SvxCaseMap::Uppercase:
        {
            aTxt = aCharClass.uppercase( aTxt );
            break;
        }

        case SvxCaseMap::Lowercase:
        {
            aTxt = aCharClass.lowercase( aTxt );
            break;
        }
        case SvxCaseMap::Capitalize:
        {
            // Every beginning of a word is capitalized,  the rest of the word
            // is taken over as is.
            // Bug: if the attribute starts in the middle of the word.
            bool bBlank = true;

            for (sal_Int32 i = 0; i < aTxt.getLength(); ++i)
            {
                if( aTxt[i] == ' ' || aTxt[i] == '\t')
                    bBlank = true;
                else
                {
                    if (bBlank)
                    {
                        OUString sTitle(aCharClass.uppercase(OUString(aTxt[i])));
                        aTxt = aTxt.replaceAt(i, 1, sTitle);
                    }
                    bBlank = false;
                }
            }
            break;
        }
        default:
        {
            SAL_WARN( "editeng""SvxFont::CaseMapTxt: unknown casemap");
            break;
        }
    }
    return aTxt;
}

void SvxDoCapitals::DoSpace( const bool /*bDraw*/ ) { }

void SvxDoCapitals::SetSpace() { }

/*************************************************************************
 *                  SvxFont::DoOnCapitals() const
 * Decomposes the String into uppercase and lowercase letters and then
 * calls the method SvxDoCapitals::Do( ).
 *************************************************************************/


void SvxFont::DoOnCapitals(SvxDoCapitals &rDo) const
{
    const OUString &rTxt = rDo.GetTxt();
    const sal_Int32 nIdx = rDo.GetIdx();
    const sal_Int32 nLen = rDo.GetLen();

    const OUString aTxt( CalcCaseMap( rTxt ) );
    const sal_Int32 nTxtLen = std::min( rTxt.getLength(), nLen );
    sal_Int32 nPos = 0;
    sal_Int32 nOldPos = nPos;

    // Test if string length differ between original and CaseMapped
    bool bCaseMapLengthDiffers(aTxt.getLength() != rTxt.getLength());

    const LanguageType eLang = LANGUAGE_DONTKNOW == GetLanguage()
                             ? LANGUAGE_SYSTEM : GetLanguage();

    CharClass   aCharClass(( LanguageTag(eLang) ));
    OUString    aCharString;

    while( nPos < nTxtLen )
    {
        // first in turn are the uppercase letters

        // There are characters that are both upper- and lower-case L (eg blank)
        // Such ambiguities lead to chaos, this is why these characters are
        // allocated to the lowercase characters!

        while( nPos < nTxtLen )
        {
            aCharString = rTxt.copy( nPos + nIdx, 1 );
            sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
            if ( nCharacterType & css::i18n::KCharacterType::LOWER )
                break;
            if ( ! ( nCharacterType & css::i18n::KCharacterType::UPPER ) )
                break;
            ++nPos;
        }
        if( nOldPos != nPos )
        {
            if(bCaseMapLengthDiffers)
            {
                // If strings differ work preparing the necessary snippet to address that
                // potential difference
                const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos-nOldPos);
                OUString aNewText = CalcCaseMap(aSnippet);

                rDo.Do( aNewText, 0, aNewText.getLength(), true );
            }
            else
            {
                rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, true );
            }

            nOldPos = nPos;
        }
        // Now the lowercase are processed (without blanks)
        while( nPos < nTxtLen )
        {
            sal_uInt32  nCharacterType = aCharClass.getCharacterType( aCharString, 0 );
            if ( nCharacterType & css::i18n::KCharacterType::UPPER )
                break;
            if ( aCharString == " " )
                break;
            if( ++nPos < nTxtLen )
                aCharString = rTxt.copy( nPos + nIdx, 1 );
        }
        if( nOldPos != nPos )
        {
            if(bCaseMapLengthDiffers)
            {
                // If strings differ work preparing the necessary snippet to address that
                // potential difference
                const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
                OUString aNewText = CalcCaseMap(aSnippet);

                rDo.Do( aNewText, 0, aNewText.getLength(), false );
            }
            else
            {
                rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, false );
            }

            nOldPos = nPos;
        }
        // Now the blanks are<processed
        while( nPos < nTxtLen && aCharString == " " && ++nPos < nTxtLen )
            aCharString = rTxt.copy( nPos + nIdx, 1 );

        if( nOldPos != nPos )
        {
            rDo.DoSpace( false );

            if(bCaseMapLengthDiffers)
            {
                // If strings differ work preparing the necessary snippet to address that
                // potential difference
                const OUString aSnippet = rTxt.copy(nIdx + nOldPos, nPos - nOldPos);
                OUString aNewText = CalcCaseMap(aSnippet);

                rDo.Do( aNewText, 0, aNewText.getLength(), false );
            }
            else
            {
                rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, false );
            }

            nOldPos = nPos;
            rDo.SetSpace();
        }
    }
    rDo.DoSpace( true );
}


void SvxFont::SetPhysFont(OutputDevice& rOut) const
{
    const vcl::Font& rCurrentFont = rOut.GetFont();
    if ( nPropr == 100 )
    {
        if ( !rCurrentFont.IsSameInstance( *this ) )
            rOut.SetFont( *this );
    }
    else
    {
        Font aNewFont( *this );
        Size aSize( aNewFont.GetFontSize() );
        aNewFont.SetFontSize( Size( aSize.Width() * nPropr / 100,
                                    aSize.Height() * nPropr / 100 ) );
        if ( !rCurrentFont.IsSameInstance( aNewFont ) )
            rOut.SetFont( aNewFont );
    }
}

vcl::Font SvxFont::ChgPhysFont(OutputDevice& rOut) const
{
    vcl::Font aOldFont(rOut.GetFont());
    SetPhysFont(rOut);
    return aOldFont;
}

Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const OUString &rTxt,
                         const sal_Int32 nIdx, const sal_Int32 nLen ) const
{
    if ( !IsCaseMap() && !IsFixKerning() )
        return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ),
                     pOut->GetTextHeight() );

    Size aTxtSize;
    aTxtSize.setHeight( pOut->GetTextHeight() );
    if ( !IsCaseMap() )
        aTxtSize.setWidth( pOut->GetTextWidth( rTxt, nIdx, nLen ) );
    else
    {
        const OUString aNewText = CalcCaseMap(rTxt);
        bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());
        sal_Int32 nWidth(0);

        if(bCaseMapLengthDiffers)
        {
            // If strings differ work preparing the necessary snippet to address that
            // potential difference
            const OUString aSnippet = rTxt.copy(nIdx, nLen);
            OUString _aNewText = CalcCaseMap(aSnippet);
            nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.getLength() );
        }
        else
        {
            nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen );
        }

        aTxtSize.setWidth(nWidth);
    }

    if( IsFixKerning() && ( nLen > 1 ) )
    {
        auto nKern = GetFixKerning();
        KernArray aDXArray;
        GetTextArray(pOut, rTxt, &aDXArray, nIdx, nLen);
        tools::Long nOldValue = aDXArray[0];
        sal_Int32 nSpaceCount = 0;
        for(sal_Int32 i = 1; i < nLen; ++i)
        {
            if (aDXArray[i] != nOldValue)
            {
                nOldValue = aDXArray[i];
                ++nSpaceCount;
            }
        }
        aTxtSize.AdjustWidth( nSpaceCount * tools::Long( nKern ) );
    }

    return aTxtSize;
}

Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut )
{
    if ( !IsCaseMap() && !IsFixKerning() )
        return Size( pOut->GetTextWidth( u""_ustr ), pOut->GetTextHeight() );

    Size aTxtSize;
    aTxtSize.setHeight( pOut->GetTextHeight() );
    if ( !IsCaseMap() )
        aTxtSize.setWidth( pOut->GetTextWidth( u""_ustr ) );
    else
        aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( u""_ustr ) ) );

    return aTxtSize;
}

Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const OUString &rTxt,
                         const sal_Int32 nIdx, const sal_Int32 nLen, KernArray* pDXArray, bool bStacked ) const
{
    if ( !IsCaseMap() && !IsFixKerning() )
    {
        SAL_INFO( "editeng.quicktextsize""SvxFont::QuickGetTextSize before GetTextArray(): Case map: " << IsCaseMap() << " Fix kerning: " << IsFixKerning());
        Size aTxtSize( GetTextArray( pOut, rTxt, pDXArray, nIdx, nLen ),
                     pOut->GetTextHeight() );
        SAL_INFO( "editeng.quicktextsize""SvxFont::QuickGetTextSize after GetTextArray(): Text length: " << nLen << " Text size: " << aTxtSize.Width() << "x" << aTxtSize.Height());
        return aTxtSize;
    }

    KernArray aDXArray;

    // We always need pDXArray to count the number of kern spaces
    if (!pDXArray && IsFixKerning() && nLen > 1)
    {
        pDXArray = &aDXArray;
        aDXArray.reserve(nLen);
    }

    Size aTxtSize;
    aTxtSize.setHeight( pOut->GetTextHeight() );
    SAL_INFO( "editeng.quicktextsize""SvxFont::QuickGetTextSize before GetTextArray(): Case map: " << IsCaseMap() << " Fix kerning: " << IsFixKerning());
    if ( !IsCaseMap() )
        aTxtSize.setWidth( GetTextArray( pOut, rTxt, pDXArray, nIdx, nLen ) );
    else
    {
        if (IsCapital() && !rTxt.isEmpty())
            aTxtSize = GetCapitalSize(pOut, rTxt, pDXArray, nIdx, nLen);
        else
            aTxtSize.setWidth( GetTextArray( pOut, CalcCaseMap( rTxt ),
                               pDXArray, nIdx, nLen ) );
    }
    SAL_INFO( "editeng.quicktextsize""SvxFont::QuickGetTextSize after GetTextArray(): Text length: " << nLen << " Text size: " << aTxtSize.Width() << "x" << aTxtSize.Height());

    if( IsFixKerning() && ( nLen > 1 ) && !bStacked)
    {
        short nKern = GetFixKerning();
        double nOldValue = (*pDXArray)[0];
        tools::Long nSpaceSum = nKern;
        (*pDXArray)[0] += nSpaceSum;

        for ( sal_Int32 i = 1; i < nLen; i++ )
        {
            if ( (*pDXArray)[i] != nOldValue )
            {
                nOldValue = (*pDXArray)[i];
                nSpaceSum += nKern;
            }
            (*pDXArray)[i] += nSpaceSum;
        }

        // The last one is a nKern too big:
        nOldValue = (*pDXArray)[nLen - 1];
        double nNewValue = nOldValue - nKern;
        for ( sal_Int32 i = nLen - 1; i >= 0 && (*pDXArray)[i] == nOldValue; --i)
            (*pDXArray)[i] = nNewValue;

        aTxtSize.AdjustWidth(nSpaceSum - nKern);
    }

    return aTxtSize;
}

Size SvxFont::GetTextSize(const OutputDevice& rOut, const OUString &rTxt,
                          const sal_Int32 nIdx, const sal_Int32 nLen) const
{
    sal_Int32 nTmp = nLen;
    if ( nTmp == SAL_MAX_INT32 )   // already initialized?
        nTmp = rTxt.getLength();
    Font aOldFont( ChgPhysFont(const_cast<OutputDevice&>(rOut)));
    Size aTxtSize;
    if( IsCapital() && !rTxt.isEmpty() )
    {
        aTxtSize = GetCapitalSize(&rOut, rTxt, nullptr, nIdx, nTmp);
    }
    else aTxtSize = GetPhysTxtSize(&rOut,rTxt,nIdx,nTmp);
    const_cast<OutputDevice&>(rOut).SetFont(aOldFont);
    return aTxtSize;
}

static void DrawTextArray( OutputDevice* pOut, const Point& rStartPt, const OUString&&nbsp;rStr,
                           KernArraySpan pDXAry,
                           std::span<const sal_Bool> pKashidaAry,
                           sal_Int32 nIndex, sal_Int32 nLen )
{
    const SalLayoutGlyphs* layoutGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOut, rStr, nIndex, nLen);
    pOut->DrawTextArray(rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, SalLayoutFlags::NONE, layoutGlyphs);
}

void SvxFont::QuickDrawText( OutputDevice *pOut,
    const Point &rPos, const OUString &rTxt,
    const sal_Int32 nIdx, const sal_Int32 nLen,
    KernArraySpan pDXArray,
    std::span<const sal_Bool> pKashidaArray) const
{

    // Font has to be selected in OutputDevice...
    if ( !IsCaseMap() && !IsCapital() && !IsFixKerning() && !IsEsc() )
    {
        DrawTextArray( pOut, rPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen );
        return;
    }

    Point aPos( rPos );

    if ( nEsc )
    {
        tools::Long nDiff = GetFontSize().Height();
        nDiff *= nEsc;
        nDiff /= 100;

        if ( !IsVertical() )
            aPos.AdjustY( -nDiff );
        else
            aPos.AdjustX(nDiff );
    }

    if( IsCapital() )
    {
        DrawCapital( pOut, aPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen );
    }
    else
    {
        if ( IsFixKerning() && pDXArray.empty() )
        {
            Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen );

            if ( !IsCaseMap() )
                pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen );
            else
                pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen );
        }
        else
        {
            if ( !IsCaseMap() )
                DrawTextArray( pOut, aPos, rTxt, pDXArray, pKashidaArray, nIdx, nLen );
            else
                DrawTextArray( pOut, aPos, CalcCaseMap( rTxt ), pDXArray, pKashidaArray, nIdx, nLen );
        }
    }
}


void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter,
                        const Point &rPos, const OUString &rTxt,
                        const sal_Int32 nIdx, const sal_Int32 nLen ) const
{
    if ( !nLen || rTxt.isEmpty() )
        return;
    sal_Int32 nTmp = nLen;

    if ( nTmp == SAL_MAX_INT32 )   // already initialized?
        nTmp = rTxt.getLength();
    Point aPos( rPos );

    if ( nEsc )
    {
        short nTmpEsc;
        if( DFLT_ESC_AUTO_SUPER == nEsc )
        {
            nTmpEsc = .8 * (100 - nPropr);
            assert (nTmpEsc == DFLT_ESC_SUPER && "I'm sure this formula needs to be changed, but how to confirm that???");
            nTmpEsc = DFLT_ESC_SUPER;
        }
        else if( DFLT_ESC_AUTO_SUB == nEsc )
        {
            nTmpEsc = .2 * -(100 - nPropr);
            assert (nTmpEsc == -20 && "I'm sure this formula needs to be changed, but how to confirm that???");
            nTmpEsc = -20;
        }
        else
            nTmpEsc = nEsc;
        Size aSize = GetFontSize();
        aPos.AdjustY( -(( nTmpEsc * aSize.Height() ) / 100) );
    }
    Font aOldFont( ChgPhysFont(*pOut) );
    Font aOldPrnFont( ChgPhysFont(*pPrinter) );

    if ( IsCapital() )
        DrawCapital( pOut, aPos, rTxt, {}, {}, nIdx, nTmp );
    else
    {
        Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp );

        if ( !IsCaseMap() )
            pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp );
        else
        {
            const OUString aNewText = CalcCaseMap(rTxt);
            bool bCaseMapLengthDiffers(aNewText.getLength() != rTxt.getLength());

            if(bCaseMapLengthDiffers)
            {
                // If strings differ work preparing the necessary snippet to address that
                // potential difference
                const OUString aSnippet(rTxt.copy( nIdx, nTmp));
                OUString _aNewText = CalcCaseMap(aSnippet);

                pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.getLength() );
            }
            else
            {
                pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp );
            }
        }
    }
    pOut->SetFont(aOldFont);
    pPrinter->SetFont( aOldPrnFont );
}


SvxFont& SvxFont::operator=( const vcl::Font& rFont )
{
    Font::operator=( rFont );
    return *this;
}

SvxFont& SvxFont::operator=( const SvxFont& rFont )
{
    Font::operator=( rFont );
    eCaseMap = rFont.eCaseMap;
    nEsc = rFont.nEsc;
    nPropr = rFont.nPropr;
    return *this;
}

bool SvxFont::SvxFontSubsetEquals(const SvxFont& rFont) const
{
    return nEsc == rFont.GetEscapement() && nPropr == rFont.GetPropr()
        && eCaseMap == rFont.GetCaseMap();
}

namespace {

class SvxDoGetCapitalSize : public SvxDoCapitals
{
protected:
    VclPtr<OutputDevice> pOut;
    SvxFont*    pFont;
    Size        aTxtSize;
    short       nKern;
    KernArray*  pDXAry;
public:
      SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut,
                           const OUString &_rTxt, KernArray* _pDXAry, const sal_Int32 _nIdx,
                           const sal_Int32 _nLen, const short _nKrn )
            : SvxDoCapitals( _rTxt, _nIdx, _nLen ),
              pOut( const_cast<OutputDevice*>(_pOut) ),
              pFont( _pFnt ),
              nKern( _nKrn ),
              pDXAry( _pDXAry )
    {
        if (pDXAry)
        {
            pDXAry->clear();
            pDXAry->reserve(_nLen);
        }
    }

    virtual void Doconst OUString &rTxt, const sal_Int32 nIdx,
                     const sal_Int32 nLen, const bool bUpper ) override;

    const Size &GetSize() const { return aTxtSize; };
};

}

void SvxDoGetCapitalSize::Doconst OUString &_rTxt, const sal_Int32 _nIdx,
                              const sal_Int32 _nLen, const bool bUpper )
{
    Size aPartSize;
    sal_uInt8 nProp(0);
    if ( !bUpper )
    {
        nProp = pFont->GetPropr();
        pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
        pFont->SetPhysFont( *pOut );
    }

    if (pDXAry)
    {
        KernArray aKernArray;
        aPartSize.setWidth(basegfx::fround<tools::Long>(
            pOut->GetTextArray(_rTxt, &aKernArray, _nIdx, _nLen).nWidth));
        double nStart = pDXAry->empty() ? 0 : pDXAry->back();
        size_t nSrcLen = aKernArray.size();
        pDXAry->reserve(pDXAry->size() + nSrcLen);
        for (size_t i = 0; i < nSrcLen; ++i)
            (*pDXAry).push_back(aKernArray[i] + nStart);
    }
    else
    {
        aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) );
    }

    aPartSize.setHeight( pOut->GetTextHeight() );

    if ( !bUpper )
    {
        aTxtSize.setHeight( aPartSize.Height() );
        pFont->SetPropr( nProp );
        pFont->SetPhysFont( *pOut );
    }

    aTxtSize.AdjustWidth(aPartSize.Width() );
    aTxtSize.AdjustWidth( _nLen * tools::Long( nKern ) );
}

Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const OUString &rTxt, KernArray* pDXAry,
                             const sal_Int32 nIdx, const sal_Int32 nLen) const
{
    // Start:
    SvxDoGetCapitalSize aDo( const_cast<SvxFont *>(this), pOut, rTxt, pDXAry, nIdx, nLen, GetFixKerning() );
    DoOnCapitals( aDo );
    Size aTxtSize( aDo.GetSize() );

    // End:
    if( !aTxtSize.Height() )
    {
        aTxtSize.setWidth( 0 );
        aTxtSize.setHeight( pOut->GetTextHeight() );
    }
    return aTxtSize;
}

namespace {

class SvxDoDrawCapital : public SvxDoCapitals
{
protected:
    VclPtr<OutputDevice> pOut;
    SvxFont *pFont;
    Point aPos;
    Point aSpacePos;
    short nKern;
    KernArraySpan pDXArray;
    std::span<const sal_Bool> pKashidaArray;
public:
    SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const OUString &_rTxt,
                      KernArraySpan _pDXArray,
                      std::span<const sal_Bool> _pKashidaArray,
                      const sal_Int32 _nIdx, const sal_Int32 _nLen,
                      const Point &rPos, const short nKrn )
        : SvxDoCapitals( _rTxt, _nIdx, _nLen ),
          pOut( _pOut ),
          pFont( pFnt ),
          aPos( rPos ),
          aSpacePos( rPos ),
          nKern( nKrn ),
          pDXArray(_pDXArray),
          pKashidaArray(_pKashidaArray)
        { }
    virtual void DoSpace( const bool bDraw ) override;
    virtual void SetSpace() override;
    virtual void Doconst OUString &rTxt, const sal_Int32 nIdx,
                     const sal_Int32 nLen, const bool bUpper ) override;
};

}

void SvxDoDrawCapital::DoSpace( const bool bDraw )
{
    if ( !(bDraw || pFont->IsWordLineMode()) )
        return;

    sal_Int32 nDiff = static_cast<sal_Int32>(aPos.X() - aSpacePos.X());
    if ( nDiff )
    {
        bool bWordWise = pFont->IsWordLineMode();
        bool bTrans = pFont->IsTransparent();
        pFont->SetWordLineMode( false );
        pFont->SetTransparent( true );
        pFont->SetPhysFont(*pOut);
        pOut->DrawStretchText( aSpacePos, nDiff, u" "_ustr, 0, 2 );
        pFont->SetWordLineMode( bWordWise );
        pFont->SetTransparent( bTrans );
        pFont->SetPhysFont(*pOut);
    }
}

void SvxDoDrawCapital::SetSpace()
{
    if ( pFont->IsWordLineMode() )
        aSpacePos.setX( aPos.X() );
}

void SvxDoDrawCapital::Doconst OUString &_rTxt, const sal_Int32 nSpanIdx,
                           const sal_Int32 nSpanLen, const bool bUpper)
{
    sal_uInt8 nProp = 0;

    // Set the desired font
    FontLineStyle eUnder = pFont->GetUnderline();
    FontLineStyle eOver = pFont->GetOverline();
    FontStrikeout eStrike = pFont->GetStrikeout();
    pFont->SetUnderline( LINESTYLE_NONE );
    pFont->SetOverline( LINESTYLE_NONE );
    pFont->SetStrikeout( STRIKEOUT_NONE );
    if ( !bUpper )
    {
        nProp = pFont->GetPropr();
        pFont->SetProprRel( SMALL_CAPS_PERCENTAGE );
    }
    pFont->SetPhysFont(*pOut);

    if (pDXArray.empty())
    {
        auto nWidth = pOut->GetTextWidth(_rTxt, nSpanIdx, nSpanLen);
        if (nKern)
        {
            aPos.AdjustX(nKern/2);
            if (nSpanLen)
                nWidth += (nSpanLen * nKern);
        }
        pOut->DrawStretchText(aPos, nWidth-nKern, _rTxt, nSpanIdx, nSpanLen);
        // in this case we move aPos along to be the start of each subspan
        aPos.AdjustX(nWidth-(nKern/2) );
    }
    else
    {
        const sal_Int32 nStartOffset = nSpanIdx - nIdx;
        sal_Int32 nStartX = nStartOffset ? pDXArray[nStartOffset - 1] : 0;

        Point aStartPos(aPos.X() + nStartX, aPos.Y());

        KernArray aDXArray;
        aDXArray.resize(nSpanLen);
        for (sal_Int32 i = 0; i < nSpanLen; ++i)
            aDXArray[i] = pDXArray[nStartOffset + i] - nStartX;

        auto aKashidaArray = !pKashidaArray.empty() ?
            std::span<const sal_Bool>(pKashidaArray.data() + nStartOffset, nSpanLen) :
            std::span<const sal_Bool>();

        DrawTextArray(pOut, aStartPos, _rTxt, aDXArray, aKashidaArray, nSpanIdx, nSpanLen);
        // in this case we leave aPos at the start and use the DXArray to find the start
        // of each subspan
    }

    // Restore Font
    pFont->SetUnderline( eUnder );
    pFont->SetOverline( eOver );
    pFont->SetStrikeout( eStrike );
    if ( !bUpper )
        pFont->SetPropr( nProp );
    pFont->SetPhysFont(*pOut);
}

/*************************************************************************
 * SvxFont::DrawCapital() draws the uppercase letter.
 *************************************************************************/


void SvxFont::DrawCapital( OutputDevice *pOut,
               const Point &rPos, const OUString &rTxt,
               KernArraySpan pDXArray,
               std::span<const sal_Bool> pKashidaArray,
               const sal_Int32 nIdx, const sal_Int32 nLen ) const
{
    SvxDoDrawCapital aDo(const_cast<SvxFont *>(this), pOut,
                         rTxt, pDXArray, pKashidaArray,
                         nIdx, nLen, rPos, GetFixKerning());
    DoOnCapitals( aDo );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge