Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/text/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 32 kB image not shown  

Quelle  itrpaint.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 <hintids.hxx>
#include <viewopt.hxx>
#include <tools/multisel.hxx>
#include <editeng/udlnitem.hxx>
#include <pagefrm.hxx>
#include <tgrditem.hxx>

#include <EnhancedPDFExportHelper.hxx>
#include <IDocumentSettingAccess.hxx>

#include <viewsh.hxx>
#include "itrpaint.hxx"
#include <txtfrm.hxx>
#include <swfont.hxx>
#include "txtpaint.hxx"
#include "porfld.hxx"
#include "porfly.hxx"
#include "portab.hxx"
#include <txatbase.hxx>
#include <charfmt.hxx>
#include "redlnitr.hxx"
#include "porrst.hxx"
#include "pormulti.hxx"
#include <doc.hxx>
#include <fmturl.hxx>

// Returns, if we have an underline breaking situation
// Adding some more conditions here means you also have to change them
// in SwTextPainter::CheckSpecialUnderline
bool IsUnderlineBreak( const SwLinePortion& rPor, const SwFont& rFnt )
{
    return LINESTYLE_NONE == rFnt.GetUnderline() ||
           rPor.IsFlyPortion() || rPor.IsFlyCntPortion() ||
           rPor.IsBreakPortion() || rPor.IsMarginPortion() ||
           rPor.IsHolePortion() ||
          ( rPor.IsMultiPortion() && ! static_cast<const SwMultiPortion&>(rPor).IsBidi() ) ||
           rFnt.GetEscapement() < 0 || rFnt.IsWordLineMode() ||
           SvxCaseMap::SmallCaps == rFnt.GetCaseMap();
}

static Color GetUnderColor( const SwFont *pFont )
{
    return pFont->GetUnderColor() == COL_AUTO ?
        pFont->GetColor() : pFont->GetUnderColor();
}

void SwTextPainter::CtorInitTextPainter( SwTextFrame *pNewFrame, SwTextPaintInfo *pNewInf )
{
    CtorInitTextCursor( pNewFrame, pNewInf );
    m_pInf = pNewInf;
    SwFont *pMyFnt = GetFnt();
    GetInfo().SetFont( pMyFnt );
    m_bPaintDrop = false;
}

SwLinePortion *SwTextPainter::CalcPaintOfst(const SwRect &rPaint, bool& rbSkippedNumPortions)
{
    SwLinePortion *pPor = m_pCurr->GetFirstPortion();
    GetInfo().SetPaintOfst( 0 );
    SwTwips nPaintOfst = rPaint.Left();

    // nPaintOfst was exactly set to the end, therefore <=
    // nPaintOfst is document global, therefore add up nLeftMar
    // const sal_uInt16 nLeftMar = sal_uInt16(GetLeftMargin());
    // 8310: paint of LineBreaks in empty lines.
    if( nPaintOfst && m_pCurr->Width() )
    {
        SwLinePortion *pLast = nullptr;
        // 7529 and 4757: not <= nPaintOfst
        while( pPor && GetInfo().X() + pPor->Width() + (pPor->Height()/2)
                       < nPaintOfst )
        {
            if( pPor->InSpaceGrp() && GetInfo().GetSpaceAdd() )
            {
                tools::Long nTmp = GetInfo().X() +pPor->Width() +
                    pPor->CalcSpacing( GetInfo().GetSpaceAdd(), GetInfo() );
                if( nTmp + (pPor->Height()/2) >= nPaintOfst )
                    break;
                GetInfo().X( nTmp );
                GetInfo().SetIdx( GetInfo().GetIdx() + pPor->GetLen() );
            }
            else
                pPor->Move( GetInfo() );
            if (pPor->InNumberGrp()
                && !static_cast<SwNumberPortion const*>(pPor)->HasFollow())
            {
                rbSkippedNumPortions = true// all numbering portions were skipped?
            }
            pLast = pPor;
            pPor = pPor->GetNextPortion();
        }

        // 7529: if PostIts return also pLast.
        if( pLast && !pLast->Width() && pLast->IsPostItsPortion() )
        {
            pPor = pLast;
            GetInfo().SetIdx( GetInfo().GetIdx() - pPor->GetLen() );
        }
    }
    return pPor;
}

// There are two possibilities to output transparent font:
// 1) DrawRect on the whole line and DrawText afterwards
//    (objectively fast, subjectively slow)
// 2) For every portion a DrawRect with subsequent DrawText is done
//    (objectively slow, subjectively fast)
// Since the user usually judges subjectively the second method is set as default.
void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
    const bool bUnderSized,
    ::std::optional<SwTaggedPDFHelper> & roTaggedLabel,
    ::std::optional<SwTaggedPDFHelper> & roTaggedParagraph,
    bool const isPDFTaggingEnabled)
{
    // maybe catch-up adjustment
    GetAdjusted();
    AddExtraBlankWidth();
    GetInfo().SetpSpaceAdd( m_pCurr->GetpLLSpaceAdd() );
    GetInfo().ResetSpaceIdx();
    GetInfo().SetKanaComp( m_pCurr->GetpKanaComp() );
    GetInfo().ResetKanaIdx();
    // The size of the frame
    GetInfo().SetIdx( GetStart() );
    GetInfo().SetPos( GetTopLeft() );

    const bool bDrawInWindow = GetInfo().OnWin();

    // 6882: blank lines can't be optimized by removing them if Formatting Marks are shown
    const bool bEndPor = GetInfo().GetOpt().IsParagraph() && GetInfo().GetText().isEmpty();

    bool bSkippedNumPortions(false);
    SwLinePortion *pPor = bEndPor ? m_pCurr->GetFirstPortion() : CalcPaintOfst(rPaint, bSkippedNumPortions);

    if (bSkippedNumPortions // ugly but hard to check earlier in PaintSwFrame:
        && !GetInfo().GetTextFrame()->GetTextNodeForParaProps()->IsOutline())
    {   // there is a num portion but it is outside of the frame area and not painted
        assert(!roTaggedLabel);
        assert(!roTaggedParagraph);
        Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
        roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *GetInfo().GetOut());
    }

    SwTaggedPDFHelper::EndCurrentLink(*GetInfo().GetOut());

    // Optimization!
    SwTwips nMaxRight = std::min<SwTwips>( rPaint.Right(), Right() );
    const SwTwips nTmpLeft = GetInfo().X();
    //compatibility settings: allow tabstop text to exceed right margin
    const auto& iDSA = GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess();
    const bool bTabOverMargin = iDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
    const bool bTabOverSpacing = iDSA.get(DocumentSettingId::TAB_OVER_SPACING);
    if (bTabOverMargin || bTabOverSpacing)
    {
        SwLinePortion* pPorIter = pPor;
        while( pPorIter )
        {
            if( pPorIter->InTabGrp() )
            {
                const SwTabPortion* pTabPor = static_cast<SwTabPortion*>(pPorIter);
                const SwTwips nTabPos = nTmpLeft + pTabPor->GetTabPos();
                if( nMaxRight < nTabPos )
                {
                    nMaxRight = rPaint.Right();
                    break;
                }
            }
            pPorIter = pPorIter->GetNextPortion();
        }
    }
    if( !bEndPor && nTmpLeft >= nMaxRight )
        return;

    // DropCaps!
    // 7538: of course for the printer, too
    if( !m_bPaintDrop )
    {
        // 8084: Optimization, less painting
        // AMA: By 8084 7538 has been revived
        // bDrawInWindow removed, so that DropCaps also can be printed
        m_bPaintDrop = pPor == m_pCurr->GetFirstPortion()
                     && GetDropLines() >= GetLineNr();
    }

    SwTwips nTmpHeight, nTmpAscent;
    CalcAscentAndHeight( nTmpAscent, nTmpHeight );

    // bClip decides if there's a need to clip
    // The whole thing must be done before retouching

    bool bClip = ( bDrawInWindow || bUnderSized ) && !rClip.IsChg();
    if( bClip && pPor )
    {
        // If TopLeft or BottomLeft of the line are outside, the we must clip.
        // The check for Right() is done in the output loop ...

        if( GetInfo().GetPos().X() < rPaint.Left() ||
            GetInfo().GetPos().Y() < rPaint.Top() ||
            GetInfo().GetPos().Y() + nTmpHeight > rPaint.Top() + rPaint.Height() )
        {
            bClip = false;
            rClip.ChgClip(rPaint, m_pFrame, m_pCurr->GetExtraAscent(), m_pCurr->GetExtraDescent());
        }
#if OSL_DEBUG_LEVEL > 1
        static bool bClipAlways = false;
        if( bClip && bClipAlways )
        {   bClip = false;
            rClip.ChgClip( rPaint );
        }
#endif
    }

    // Alignment
    OutputDevice* pOut = GetInfo().GetOut();
    Point aPnt1( nTmpLeft, GetInfo().GetPos().Y() );
    if ( aPnt1.X() < rPaint.Left() )
        aPnt1.setX( rPaint.Left() );
    if ( aPnt1.Y() < rPaint.Top() )
        aPnt1.setY( rPaint.Top() );
    Point aPnt2( GetInfo().GetPos().X() + nMaxRight - GetInfo().X(),
                 GetInfo().GetPos().Y() + nTmpHeight );
    if ( aPnt2.X() > rPaint.Right() )
        aPnt2.setX( rPaint.Right() );
    if ( aPnt2.Y() > rPaint.Bottom() )
        aPnt2.setY( rPaint.Bottom() );

    const SwRect aLineRect( aPnt1, aPnt2 );

    if( m_pCurr->IsClipping() )
    {
        const SwTextFrame& rFrame = *GetInfo().GetTextFrame();
        // tdf#117448 at small fixed line height, enlarge clipping area in table cells
        // to show previously clipped text content on the area of paragraph margins
        if ( rFrame.IsInTab() )
            rClip.ChgClip(aLineRect, m_pFrame, rFrame.GetTopMargin(), rFrame.GetBottomMargin());
        else
            rClip.ChgClip( aLineRect, m_pFrame );
        bClip = false;
    }

    if( !pPor && !bEndPor )
        return;

    // Baseline output also if non-TextPortion (compare TabPor with Fill)
    // if no special vertical alignment is used,
    // we calculate Y value for the whole line
    SwTextGridItem const*const pGrid(GetGridItem(GetTextFrame()->FindPageFrame()));
    const bool bAdjustBaseLine =
        GetLineInfo().HasSpecialAlign( GetTextFrame()->IsVertical() ) ||
        ( nullptr != pGrid ) || m_pCurr->GetHangingBaseline();
    const SwTwips nLineBaseLine = GetInfo().GetPos().Y() + nTmpAscent;
    if ( ! bAdjustBaseLine )
        GetInfo().Y( nLineBaseLine );

    // 7529: Pre-paint post-its
    if( GetInfo().OnWin() && pPor && !pPor->Width() )
    {
        SeekAndChg( GetInfo() );

        if( bAdjustBaseLine )
        {
            const SwTwips nOldY = GetInfo().Y();

            GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, nullptr,
                GetInfo().GetFont()->GetHeight( GetInfo().GetVsh(), *pOut ),
                GetInfo().GetFont()->GetAscent( GetInfo().GetVsh(), *pOut )
            ) );

            pPor->PrePaint( GetInfo(), pPor );
            GetInfo().Y( nOldY );
        }
        else
            pPor->PrePaint( GetInfo(), pPor );
    }

    // 7923: EndPortions output chars, too, that's why we change the font
    if( bEndPor )
        SeekStartAndChg( GetInfo() );

    const bool bRest = m_pCurr->IsRest();
    bool bFirst = true;

    SwArrowPortion *pArrow = nullptr;
    // Reference portion for the paragraph end portion
    SwLinePortion* pEndTempl = m_pCurr->GetFirstPortion();

    while( pPor )
    {
        bool bSeeked = true;
        GetInfo().SetLen( pPor->GetLen() );

        const SwTwips nOldY = GetInfo().Y();

        if ( bAdjustBaseLine )
        {
            GetInfo().Y( GetInfo().GetPos().Y() + AdjustBaseLine( *m_pCurr, pPor ) );

            // we store the last portion, because a possible paragraph
            // end character has the same font as this portion
            // (only in special vertical alignment case, otherwise the first
            // portion of the line is used)
            if ( pPor->Width() && pPor->InTextGrp() )
                pEndTempl = pPor;
        }

        // set redlining for line break symbol
        if ( pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() && GetRedln() )
        {
            SeekAndChg( GetInfo() );
            if ( m_pCurr->GetRedlineEndType() != RedlineType::None )
                static_cast<SwBreakPortion&>(*pPor).SetRedline( m_pCurr->GetRedlineEndType() );
        }

        // A special case are GluePortions which output blanks.

        // 6168: Avoid that the rest of a FieldPortion gets the attributes of the
        // next portion with SeekAndChgBefore():
        if( bRest && pPor->InFieldGrp() && !pPor->GetLen() )
            SeekAndChgBefore( GetInfo() );
        else if ( pPor->IsQuoVadisPortion() )
        {
            // A remark on QuoVadis/ErgoSum:
            // We use the Font set for the Paragraph for these portions.
            // Thus, we initialize:
            TextFrameIndex nOffset = GetInfo().GetIdx();
            SeekStartAndChg( GetInfo(), true );
            if( GetRedln() && m_pCurr->HasRedline() )
            {
                std::pair<SwTextNode const*, sal_Int32> const pos(
                        GetTextFrame()->MapViewToModel(nOffset));
                GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
            }
        }
        else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
            SeekAndChg( GetInfo() );
        else if ( !bFirst && pPor->IsBreakPortion() && GetInfo().GetOpt().IsParagraph() )
        {
            // Paragraph symbols should have the same font as the paragraph in front of them,
            // except for the case that there's redlining in the paragraph
            if( GetRedln() )
                SeekAndChg( GetInfo() );
            else
                SeekAndChgBefore( GetInfo() );
        }
        else
            bSeeked = false;

        // bRest = false;

        // If the end of the portion juts out, it is clipped.
        // A safety distance of half the height is added, so that
        // TTF-"f" isn't overlapping into the page margin.
        if( bClip &&
            GetInfo().X() + pPor->Width() + ( pPor->Height() / 2 ) > nMaxRight )
        {
            bClip = false;
            rClip.ChgClip(rPaint, m_pFrame, m_pCurr->GetExtraAscent(), m_pCurr->GetExtraDescent());
        }

        // Portions, which lay "below" the text like post-its
        SwLinePortion *pNext = pPor->GetNextPortion();
        if( GetInfo().OnWin() && pNext && !pNext->Width() )
        {
            // Fix 11289: Fields were omitted here because of Last!=Owner during
            // loading Brief.sdw. Now the fields are allowed again,
            // by bSeeked Last!=Owner is being avoided.
            if ( !bSeeked )
                SeekAndChg( GetInfo() );
            pNext->PrePaint( GetInfo(), pPor );
        }

        // We calculate a separate font for underlining.
        CheckSpecialUnderline( pPor, bAdjustBaseLine ? nOldY : 0 );
        SwUnderlineFont* pUnderLineFnt = GetInfo().GetUnderFnt();
        if ( pUnderLineFnt )
        {
            const Point aTmpPoint( GetInfo().X(),
                                   bAdjustBaseLine ?
                                   pUnderLineFnt->GetPos().Y() :
                                   nLineBaseLine );
            pUnderLineFnt->SetPos( aTmpPoint );
        }

        // in extended input mode we do not want a common underline font.
        SwUnderlineFont* pOldUnderLineFnt = nullptr;
        if ( GetRedln() && GetRedln()->ExtOn() )
        {
            pOldUnderLineFnt = GetInfo().GetUnderFnt();
            GetInfo().SetUnderFnt( nullptr );
        }

        // multiple numbering portions are possible :(
        if ((pPor->InNumberGrp() // also footnote label
                // weird special case, bullet with soft hyphen
             || (pPor->InHyphGrp() && pNext && pNext->InNumberGrp()))
            && !GetInfo().GetTextFrame()->GetTextNodeForParaProps()->IsOutline()
            && !roTaggedLabel) // note: CalcPaintOfst may skip some portions
        {
            assert(isPDFTaggingEnabled);
            Por_Info aPorInfo(*pPor, *this, 1); // open Lbl
            roTaggedLabel.emplace(nullptr, nullptr, &aPorInfo, *pOut);
        }

        {
            // #i16816# tagged pdf support
            Por_Info aPorInfo(*pPor, *this, 0);
            SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, &aPorInfo, *pOut );

            if( pPor->IsMultiPortion() )
                PaintMultiPortion( rPaint, static_cast<SwMultiPortion&>(*pPor) );
            else
                pPor->Paint( GetInfo() );
        }

        // lazy open LBody and paragraph tag after num portions have been painted to Lbl
        if (pPor->InNumberGrp() // also footnote label
            // note: numbering portion may be split if it has multiple scripts
            && !static_cast<SwNumberPortion const*>(pPor)->HasFollow()) // so wait for the last one
        {
            if (!GetInfo().GetTextFrame()->GetTextNodeForParaProps()->IsOutline())
            {
                assert(roTaggedLabel);
                roTaggedLabel.reset(); // close Lbl
                assert(!roTaggedParagraph);
                Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
                roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *pOut);
            }
            else
            {
                assert(!roTaggedLabel);
            }
        }

        // reset underline font
        if ( pOldUnderLineFnt )
            GetInfo().SetUnderFnt( pOldUnderLineFnt );

        // reset (for special vertical alignment)
        GetInfo().Y( nOldY );

        if (GetFnt()->IsURL() && pPor->InTextGrp())
            GetInfo().NotifyURL(*pPor);
        else if (pPor->IsFlyCntPortion())
        {
            if (auto* pFlyContentPortion = dynamic_cast<sw::FlyContentPortion*>(pPor))
            {
                if (auto* pFlyFrame = pFlyContentPortion->GetFlyFrame())
                {
                    if (auto* pFormat = pFlyFrame->GetFormat())
                    {
                        auto& url = pFormat->GetURL();
                        if (!url.GetURL().isEmpty()) // TODO: url.GetMap() ?
                            GetInfo().NotifyURL(*pPor);
                    }
                }
            }
        }

        bFirst &= !pPor->GetLen();
        if( pNext || !pPor->IsMarginPortion() )
            pPor->Move( GetInfo() );
        if( pPor->IsArrowPortion() && GetInfo().OnWin() && !pArrow )
            pArrow = static_cast<SwArrowPortion*>(pPor);

        pPor = bDrawInWindow || GetInfo().X() <= nMaxRight ||
               // #i16816# tagged pdf support
               ( GetInfo().GetVsh() &&
                 GetInfo().GetVsh()->GetViewOptions()->IsPDFExport() &&
                 pNext && pNext->IsHolePortion() ) ?
               pNext :
               nullptr;
        if (!pPor && isPDFTaggingEnabled && (roTaggedLabel || !roTaggedParagraph))
        {   // check if the end of the list label is off-screen
            auto FindEndOfNumbering = [&](SwLinePortion const* pP) {
                while (pP)
                {
                    if (pP->InNumberGrp()
                        && !static_cast<SwNumberPortion const*>(pP)->HasFollow())
                    {
                        if (roTaggedLabel)
                        {
                            roTaggedLabel.reset();
                        } // else, if the numbering isn't visible at all, no Lbl
                        if (!GetInfo().GetTextFrame()->GetTextNodeForParaProps()->IsOutline())
                        {
                            Frame_Info aFrameInfo(*m_pFrame, false); // open LBody
                            roTaggedParagraph.emplace(nullptr, &aFrameInfo, nullptr, *GetInfo().GetOut());
                        }
                        return true;
                    }
                    pP = pP->GetNextPortion();
                }
                return false;
            };
            if (!FindEndOfNumbering(pNext)) // check rest of current line
            {
                // check lines that will be cut off
                if (rPaint.Bottom() < Y() + GetLineHeight())
                {
                    for (SwLineLayout const* pLine = GetNext(); pLine; pLine = pLine->GetNext())
                    {
                        if (FindEndOfNumbering(pLine->GetFirstPortion()))
                        {
                            break;
                        }
                    }
                }
            }
        }
    }

    // delete underline font
    delete GetInfo().GetUnderFnt();
    GetInfo().SetUnderFnt( nullptr );

    // paint remaining stuff, e.g. the line ending symbols, pilcrow (¶) and the line break
    if( bDrawInWindow )
    {
        // If special vertical alignment is enabled, GetInfo().Y() is the
        // top of the current line. Therefore is has to be adjusted for
        // the painting of the remaining stuff. We first store the old value.
        const SwTwips nOldY = GetInfo().Y();

        if( !GetNextLine() &&
            GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() &&
            GetInfo().GetOpt().IsParagraph() && !GetTextFrame()->GetFollow() &&
            GetInfo().GetIdx() >= TextFrameIndex(GetInfo().GetText().getLength()))
        {
            bool bHasRedlineEnd( GetRedln() && m_pCurr->HasRedlineEnd() );
            RedlineType eRedlineEnd = bHasRedlineEnd ? m_pCurr->GetRedlineEndType() : RedlineType::None;
            if( bHasRedlineEnd )
            {
                TextFrameIndex nOffset = GetInfo().GetIdx();
                SeekStartAndChg( GetInfo(), true );
                std::pair<SwTextNode const*, sal_Int32> const pos(
                        GetTextFrame()->MapViewToModel(nOffset));
                GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
            }
            const SwTmpEndPortion aEnd( *pEndTempl,
                           bHasRedlineEnd && eRedlineEnd != RedlineType::Delete ? m_pFont->GetUnderline() : LINESTYLE_NONE,
                           bHasRedlineEnd && eRedlineEnd == RedlineType::Delete ? m_pFont->GetStrikeout() : STRIKEOUT_NONE,
                           bHasRedlineEnd ? m_pFont->GetColor() : COL_AUTO );
            GetFnt()->ChgPhysFnt( GetInfo().GetVsh(), *pOut );

            if ( bAdjustBaseLine )
                GetInfo().Y( GetInfo().GetPos().Y()
                           + AdjustBaseLine( *m_pCurr, &aEnd ) );
            GetInfo().X( GetInfo().X() +
                // tdf#163042 In the case of shrunk lines with a single portion, adjust
                // the line width (if needed, i.e. if the shrunk line doesn't end in a space)
                // to show the terminating pilcrow at the correct position, and not before that
                ( ( !( pEndTempl->GetNextPortion() && pEndTempl->GetNextPortion()->IsHolePortion() ) &&
                    std::abs( m_pCurr->Width() - m_pCurr->GetFirstPortion()->Width() ) <= 1 && m_pCurr->ExtraShrunkWidth() > 0 )
                        ? m_pCurr->ExtraShrunkWidth() - m_pCurr->Width() : 0 ) +
                    ( GetCurr()->IsHanging() ? GetCurr()->GetHangingMargin() : 0 ) );
            aEnd.Paint( GetInfo() );
            GetInfo().Y( nOldY );
        }
        if( GetInfo().GetVsh() && !GetInfo().GetVsh()->IsPreview() )
        {
            const bool bNextUndersized =
                ( GetTextFrame()->GetNext() &&
                  0 == GetTextFrame()->GetNext()->getFramePrintArea().Height() &&
                  GetTextFrame()->GetNext()->IsTextFrame() &&
                  static_cast<SwTextFrame*>(GetTextFrame()->GetNext())->IsUndersized() ) ;

            if( bUnderSized || bNextUndersized )
            {
                if ( bAdjustBaseLine )
                    GetInfo().Y( GetInfo().GetPos().Y() + m_pCurr->GetAscent() );

                // Left arrow (text overflowing)
                if( pArrow )
                    GetInfo().DrawRedArrow( *pArrow );

                // GetInfo().Y() must be current baseline
                SwTwips nDiff = GetInfo().Y() + nTmpHeight - nTmpAscent - GetTextFrame()->getFrameArea().Bottom();
                if( ( nDiff > 0 &&
                      (GetEnd() < TextFrameIndex(GetInfo().GetText().getLength()) ||
                        ( nDiff > nTmpHeight/2 && GetPrevLine() ) ) ) ||
                    (nDiff >= 0 && bNextUndersized) )

                {
                    // Right arrow (text overflowing)
                    SwArrowPortion aArrow( GetInfo() );
                    GetInfo().DrawRedArrow( aArrow );
                }

                GetInfo().Y( nOldY );
            }
        }
    }

    if( m_pCurr->IsClipping() )
        rClip.ChgClip( rPaint, m_pFrame );
}

void SwTextPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
                                          tools::Long nAdjustBaseLine )
{
    // Check if common underline should not be continued
    if ( IsUnderlineBreak( *pPor, *m_pFont ) )
    {
        // delete underline font
        delete GetInfo().GetUnderFnt();
        GetInfo().SetUnderFnt( nullptr );
        return;
    }
    // Reuse calculated underline font as much as possible.
    if (GetInfo().GetUnderFnt() &&
        GetInfo().GetIdx() + pPor->GetLen() <= GetInfo().GetUnderFnt()->GetEnd() + TextFrameIndex(1))
    {
        SwFont &rFont = GetInfo().GetUnderFnt()->GetFont();
        const Color aColor = GetUnderColor( GetInfo().GetFont() );
        if ( GetUnderColor( &rFont ) != aColor )
            rFont.SetColor( aColor );
        return;
    }

    // If current underline matches the common underline font, we continue
    // to use the common underline font.
    // Bug 120769:Color of underline display wrongly
    if ( GetInfo().GetUnderFnt() &&
        GetInfo().GetUnderFnt()->GetFont().GetUnderline() == GetFnt()->GetUnderline() &&
        GetInfo().GetFont() && GetInfo().GetFont()->GetUnderColor() != COL_AUTO )
        return;
    //Bug 120769(End)

    OSL_ENSURE( GetFnt() && LINESTYLE_NONE != GetFnt()->GetUnderline(),
            "CheckSpecialUnderline without underlined font" );
    MultiSelection aUnderMulti( Range( 0, GetInfo().GetText().getLength() ) );
    const SwFont* pParaFnt = GetAttrHandler().GetFont();
    if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
        aUnderMulti.SelectAll();

    if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
    {
        // first, add the paragraph properties to MultiSelection - if there are
        // Hints too, they will override the positions if they're added later
        sal_Int32 nTmp(0);
        for (auto const& e : pMerged->extents)
        {
            if (const SvxUnderlineItem* pItem = e.pNode->GetSwAttrSet().GetItemIfSet(
                        RES_CHRATR_UNDERLINE))
            {
                const bool bUnderSelect(m_pFont->GetUnderline() ==
                    pItem->GetLineStyle());
                aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
                        bUnderSelect);
            }
            nTmp += e.nEnd - e.nStart;
        }
    }

    SwTextNode const* pNode(nullptr);
    sw::MergedAttrIter iter(*GetTextFrame());
    for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
         pTextAttr = iter.NextAttr(&pNode))
    {
        SvxUnderlineItem const*const pItem =
            CharFormat::GetItem(*pTextAttr, RES_CHRATR_UNDERLINE);

        if (pItem)
        {
            TextFrameIndex const nStart(
                GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
            TextFrameIndex const nEnd(
                GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
            if (nEnd > nStart)
            {
                const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
                aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
                        bUnderSelect);
            }
        }
    }

    const TextFrameIndex nIndx = GetInfo().GetIdx();
    TextFrameIndex nUnderEnd(0);
    const size_t nCnt = aUnderMulti.GetRangeCount();

    // find the underline range the current portion is contained in
    for( size_t i = 0; i < nCnt; ++i )
    {
        const Range& rRange = aUnderMulti.GetRange( i );
        if (nUnderEnd == TextFrameIndex(rRange.Min()))
            nUnderEnd = TextFrameIndex(rRange.Max());
        else if (nIndx >= TextFrameIndex(rRange.Min()))
        {
            nUnderEnd = TextFrameIndex(rRange.Max());
        }
        else
            break;
    }

    if ( GetEnd() && GetEnd() <= nUnderEnd )
        nUnderEnd = GetEnd() - TextFrameIndex(1);

    // calculate the new common underline font
    SwFont* pUnderlineFnt = nullptr;
    Point aCommonBaseLine;

    // check, if underlining is not isolated
    if (nIndx + GetInfo().GetLen() < nUnderEnd + TextFrameIndex(1))
    {
        // here starts the algorithm for calculating the underline font
        SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
        SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
                         rScriptInfo, GetTextFrame());

        TextFrameIndex nTmpIdx = nIndx;
        sal_uLong nSumWidth = 0;
        sal_uLong nSumHeight = 0;
        sal_uLong nBold = 0;
        sal_uInt16 nMaxBaseLineOfst = 0;
        int nNumberOfPortions = 0;

        while (nTmpIdx <= nUnderEnd && pPor)
        {
            if ( pPor->IsFlyPortion() || pPor->IsFlyCntPortion() ||
                pPor->IsBreakPortion() || pPor->IsMarginPortion() ||
                pPor->IsHolePortion() ||
                ( pPor->IsMultiPortion() && ! static_cast<const SwMultiPortion*>(pPor)->IsBidi() ) )
                break;

            aIter.Seek( nTmpIdx );
            if ( aIter.GetFnt()->GetEscapement() < 0 || m_pFont->IsWordLineMode() ||
                 SvxCaseMap::SmallCaps == m_pFont->GetCaseMap() )
                break;

            if ( !aIter.GetFnt()->GetEscapement() )
            {
                nSumWidth += pPor->Width();
                const sal_uLong nFontHeight = aIter.GetFnt()->GetHeight();

                // If we do not have a common baseline we take the baseline
                // and the font of the lowest portion.
                if ( nAdjustBaseLine )
                {
                    const sal_uInt16 nTmpBaseLineOfst = AdjustBaseLine( *m_pCurr, pPor );
                    if ( nMaxBaseLineOfst < nTmpBaseLineOfst )
                    {
                        nMaxBaseLineOfst = nTmpBaseLineOfst;
                        nSumHeight = nFontHeight;
                    }
                }
                // in horizontal layout we build a weighted sum of the heights
                else
                    nSumHeight += pPor->Width() * nFontHeight;

                if ( WEIGHT_NORMAL != aIter.GetFnt()->GetWeight() )
                    nBold += pPor->Width();
            }

            ++nNumberOfPortions;

            nTmpIdx += pPor->GetLen();
            pPor = pPor->GetNextPortion();
        }

        // resulting height
        if ( nNumberOfPortions > 1 && nSumWidth )
        {
            const sal_uLong nNewFontHeight = nAdjustBaseLine ?
                                         nSumHeight :
                                         nSumHeight / nSumWidth;

            pUnderlineFnt = new SwFont( *GetInfo().GetFont() );

            // font height
            const SwFontScript nActual = pUnderlineFnt->GetActual();
            pUnderlineFnt->SetSize( Size( pUnderlineFnt->GetSize( nActual ).Width(),
                                          nNewFontHeight ), nActual );

            // font weight
            if ( 2 * nBold > nSumWidth )
                pUnderlineFnt->SetWeight( WEIGHT_BOLD, nActual );
            else
                pUnderlineFnt->SetWeight( WEIGHT_NORMAL, nActual );

            // common base line
            aCommonBaseLine.setY( nAdjustBaseLine + nMaxBaseLineOfst );
        }
    }

    // an escaped redlined portion should also have a special underlining
    if( ! pUnderlineFnt && m_pFont->GetEscapement() > 0 && GetRedln() &&
        GetRedln()->ChkSpecialUnderline() )
        pUnderlineFnt = new SwFont( *m_pFont );

    delete GetInfo().GetUnderFnt();

    if ( pUnderlineFnt )
    {
        pUnderlineFnt->SetProportion( 100 );
        pUnderlineFnt->SetEscapement( 0 );
        pUnderlineFnt->SetStrikeout( STRIKEOUT_NONE );
        pUnderlineFnt->SetOverline( LINESTYLE_NONE );
        const Color aFillColor( COL_TRANSPARENT );
        pUnderlineFnt->SetFillColor( aFillColor );

        GetInfo().SetUnderFnt( new SwUnderlineFont( *pUnderlineFnt, nUnderEnd,
                                                     aCommonBaseLine ) );
    }
    else
        // I'm sorry, we do not have a special underlining font for you.
        GetInfo().SetUnderFnt( nullptr );
}

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

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

¤ Dauer der Verarbeitung: 0.12 Sekunden  ¤

*© 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.