    /* -*- 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 <vcl/svapp.hxx>
    #include <vcl/outdev.hxx>

    #include <osl/thread.hxx>
    #include <salhelper/condition.hxx>
    #include <sfx2/docfile.hxx>
    #include <sfx2/lnkbase.hxx>
    #include <sfx2/objsh.hxx>
    #include <editeng/boxitem.hxx>
    #include <svx/svxids.hrc>
    #include <sfx2/linkmgr.hxx>
    #include <sfx2/event.hxx>
    #include <svtools/soerr.hxx>
    #include <fmtfsize.hxx>
    #include <fmtanchr.hxx>
    #include <frmatr.hxx>
    #include <frmfmt.hxx>
    #include <doc.hxx>
    #include <IDocumentLinksAdministration.hxx>
    #include <IDocumentLayoutAccess.hxx>
    #include <pam.hxx>
    #include <editsh.hxx>
    #include <swtable.hxx>
    #include <docary.hxx>
    #include <swevent.hxx>
    #include <swbaslnk.hxx>
    #include <swserv.hxx>
    #include <ndgrf.hxx>
    #include <ndole.hxx>
    #include <hints.hxx>
    #include <tabfrm.hxx>
    #include <cntfrm.hxx>
    #include <htmltbl.hxx>
    #include <calbck.hxx>
    #include <memory>

    using namespace com::sun::star;

    static bool SetGrfFlySize( const Size& rGrfSz, SwGrfNode* pGrfNd, const Size &rOrigGrfSize );

    static void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem )
    {
        //call first all not SwNoTextFrames, then the SwNoTextFrames.
        //              The reason is, that in the SwNoTextFrames the Graphic
        //              after a Paint will be swapped out! So all other "behind"
        //              them haven't a loaded Graphic.
        rGrfNd.LockModify();
        {
            SwIterator<SwClient,SwGrfNode> aIter(rGrfNd);
            for(SwClient* pLast = aIter.First(); pLast; pLast = aIter.Next())
                if(dynamic_cast<const SwContentFrame*>( pLast) ==  nullptr)
                    pLast->ModifyNotification(&rItem, &rItem);
        }
        {
            SwIterator<SwContentFrame,SwGrfNode> aIter(rGrfNd);
            for(SwClient* pLast = aIter.First(); pLast; pLast = aIter.Next())
                pLast->ModifyNotification(&rItem, &rItem);
        }
        rGrfNd.UnlockModify();
    }

    ::sfx2::SvBaseLink::UpdateResult SwBaseLink::DataChanged(
        const OUString& rMimeType, const uno::Any & rValue )
    {
        if( !m_pContentNode )
        {
            OSL_ENSURE(false, "DataChanged without ContentNode" );
            return ERROR_GENERAL;
        }

        SwDoc* pDoc = m_pContentNode->GetDoc();
        if( pDoc->IsInDtor() || ChkNoDataFlag() )
        {
            return SUCCESS;
        }

        SotClipboardFormatId nFormat = SotExchange::GetFormatIdFromMimeType( rMimeType );

        if( m_pContentNode->IsNoTextNode() &&
            nFormat == sfx2::LinkManager::RegisterStatusInfoId() )
        {
            // Only a status change - serve Events?
            OUString sState;

            if( rValue.hasValue() && ( rValue >>= sState ))
            {
                SvMacroItemId nEvent = SvMacroItemId::NONE;
                switch( sState.toInt32() )
                {
                case sfx2::LinkManager::STATE_LOAD_OK:      nEvent = SvMacroItemId::OnImageLoadDone;  break;
                case sfx2::LinkManager::STATE_LOAD_ERROR:   nEvent = SvMacroItemId::OnImageLoadError; break;
                case sfx2::LinkManager::STATE_LOAD_ABORT:   nEvent = SvMacroItemId::OnImageLoadCancel; break;
                }

                SwFrameFormat* pFormat;
                if( nEvent != SvMacroItemId::NONE && nullptr != ( pFormat = m_pContentNode->GetFlyFormat() ))
                {
                    SwCallMouseEvent aCallEvent;
                    aCallEvent.Set( EVENT_OBJECT_IMAGE, pFormat );
                    pDoc->CallEvent( nEvent, aCallEvent );
                }
            }
            return SUCCESS; // That's it!
        }

        bool bUpdate = false;
        bool bFrameInPaint = false;
        Size aGrfSz, aOldSz;

        SwGrfNode* pSwGrfNode = nullptr;

        if (m_pContentNode->IsGrfNode())
        {
            pSwGrfNode = m_pContentNode->GetGrfNode();
            assert(pSwGrfNode && "Error, pSwGrfNode expected when node answers IsGrfNode() with true (!)");
            aOldSz = pSwGrfNode->GetTwipSize();
            const GraphicObject& rGrfObj = pSwGrfNode->GetGrfObj();

            bFrameInPaint = pSwGrfNode->IsFrameInPaint();

            Graphic aGrf;

            OUString sReferer;
            SfxObjectShell * sh = pDoc->GetPersist();
            if (sh != nullptr && sh->HasName())
            {
                sReferer = sh->GetMedium()->GetName();
            }

            if( sfx2::LinkManager::GetGraphicFromAny(rMimeType, rValue, sReferer, aGrf) &&
                ( GraphicType::Default != aGrf.GetType() ||
                  GraphicType::Default != rGrfObj.GetType() ) )
            {
                aGrfSz = ::GetGraphicSizeTwip( aGrf, nullptr );

                pSwGrfNode->SetGraphic(aGrf);
                bUpdate = true;

                // Always use the correct graphic size
                if( aGrfSz.Height() && aGrfSz.Width() &&
                    aOldSz.Height() && aOldSz.Width() &&
                    aGrfSz != aOldSz )
                {
                    pSwGrfNode->SetTwipSize(aGrfSz);
                    aOldSz = aGrfSz;
                }
            }
        }
        else if( m_pContentNode->IsOLENode() )
            bUpdate = true;

        if ( !bUpdate || bFrameInPaint )
            return SUCCESS;

        if (bUpdate && pSwGrfNode)
        {
            if (!SetGrfFlySize(aGrfSz, pSwGrfNode, aOldSz))
            {
                SwMsgPoolItem aMsgHint(RES_GRAPHIC_ARRIVED);
                lcl_CallModify(*pSwGrfNode, aMsgHint);
                return SUCCESS;
            }
        }

        return SUCCESS;
    }

    static bool SetGrfFlySize( const Size& rGrfSz, SwGrfNode* pGrfNd, const Size& rOrigGrfSize )
    {
        bool bRet = false;
        SwViewShell *pSh = pGrfNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
        std::unique_ptr<CurrShell> pCurr;
        if ( pGrfNd->GetDoc()->GetEditShell() )
            pCurr.reset(new CurrShell( pSh ));

        Size aSz = rOrigGrfSize;
        if ( !(aSz.Width() && aSz.Height()) &&
                rGrfSz.Width() && rGrfSz.Height() )
        {
            SwFrameFormat* pFormat = nullptr;
            if (pGrfNd->IsChgTwipSize())
                pFormat = pGrfNd->GetFlyFormat();
            if (nullptr != pFormat)
            {
                Size aCalcSz( aSz );
                if ( !aSz.Height() && aSz.Width() )
                    // Calculate the right height
                    aCalcSz.setHeight( rGrfSz.Height() *
                            aSz.Width() / rGrfSz.Width() );
                else if ( !aSz.Width() && aSz.Height() )
                    // Calculate the right width
                    aCalcSz.setWidth( rGrfSz.Width() *
                            aSz.Height() / rGrfSz.Height() );
                else
                    // Take over height and width
                    aCalcSz = rGrfSz;

                const SvxBoxItem     &rBox = pFormat->GetBox();
                aCalcSz.AdjustWidth(rBox.CalcLineSpace(SvxBoxItemLine::LEFT) +
                                   rBox.CalcLineSpace(SvxBoxItemLine::RIGHT) );
                aCalcSz.AdjustHeight(rBox.CalcLineSpace(SvxBoxItemLine::TOP) +
                                   rBox.CalcLineSpace(SvxBoxItemLine::BOTTOM) );
                const SwFormatFrameSize& rOldAttr = pFormat->GetFrameSize();
                if( rOldAttr.GetSize() != aCalcSz )
                {
                    SwFormatFrameSize aAttr( rOldAttr  );
                    aAttr.SetSize( aCalcSz );
                    pFormat->SetFormatAttr( aAttr );
                    bRet = true;
                }

                if( !aSz.Width() )
                {
                    // If the graphic is anchored in a table, we need to recalculate
                    // the table rows
                    const SwDoc *pDoc = pGrfNd->GetDoc();
                    const SwPosition* pAPos = pFormat->GetAnchor().GetContentAnchor();
                    SwNode *pANd;
                    SwTableNode *pTableNd;
                    if( pAPos &&
                        nullptr != (pANd = & pAPos->nNode.GetNode()) &&
                        nullptr != (pTableNd = pANd->FindTableNode()) )
                    {
                        const bool bLastGrf = !pTableNd->GetTable().DecGrfsThatResize();
                        SwHTMLTableLayout *pLayout =
                            pTableNd->GetTable().GetHTMLTableLayout();
                        if( pLayout )
                        {
                            const sal_uInt16 nBrowseWidth =
                                        pLayout->GetBrowseWidthByTable( *pDoc );
                            if ( nBrowseWidth )
                            {
                                pLayout->Resize( nBrowseWidth, true, true,
                                                 bLastGrf ? HTMLTABLE_RESIZE_NOW
                                                          : 500 );
                            }
                        }
                    }
                }
            }

            // SetTwipSize rescales an ImageMap if needed for which
            // it requires the Frame Format
            pGrfNd->SetTwipSize( rGrfSz );
        }

        return bRet;
    }

    bool SwBaseLink::SwapIn( bool bWaitForData, bool bNativFormat )
    {
        if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) ))
        {
            AddNextRef();
            GetRealObject_();
            ReleaseRef();
        }

        bool bRes = false;

        if( GetObj() )
        {
            OUString aMimeType( SotExchange::GetFormatMimeType( GetContentType() ));
            uno::Any aValue;
            (void)GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData );

            if( bWaitForData && !GetObj() )
            {
                OSL_ENSURE( false, "The SvxFileObject was deleted in a GetData!" );
            }
            else
            {
                bRes = aValue.hasValue();
                if ( bRes )
                {
                    DataChanged( aMimeType, aValue );
                }
            }
        }
        else if( !IsSynchron() && bWaitForData )
        {
            SetSynchron( true );
            bRes = Update();
            SetSynchron( false );
        }
        else
            bRes = Update();

        return bRes;
    }

    void SwBaseLink::Closed()
    {
        if( m_pContentNode && !m_pContentNode->GetDoc()->IsInDtor() )
        {
            // Delete the connection
            if( m_pContentNode->IsGrfNode() )
                static_cast<SwGrfNode*>(m_pContentNode)->ReleaseLink();
        }
        SvBaseLink::Closed();
    }

    const SwNode* SwBaseLink::GetAnchor() const
    {
        if (m_pContentNode)
        {
            SwFrameFormat *const pFormat = m_pContentNode->GetFlyFormat();
            if (pFormat)
            {
                const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
                SwPosition const*const pAPos = rAnchor.GetContentAnchor();
                if (pAPos &&
                    ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
                     (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
                     (RndStdIds::FLY_AT_FLY  == rAnchor.GetAnchorId()) ||
                     (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId())))
                {
                        return &pAPos->nNode.GetNode();
                }
                return nullptr;
            }
        }

        OSL_ENSURE( false, "GetAnchor is not shadowed" );
        return nullptr;
    }

    bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const
    {
        tools::SvRef<SwServerObject> aRef( static_cast<SwServerObject*>(GetObj()) );
        if( aRef.is() )
        {
            // As it's a ServerObject, we query all contained Links
            // if we are contained in them. Else we have a recursion.
            return aRef->IsLinkInServer( pChkLnk );
        }
        return false;
    }

    bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, sal_Int32, sal_Int32 ) const
    {
        // Not Graphic or OLE Links
        // Fields or Sections have their own derivation!
        return false;
    }

    SwBaseLink::~SwBaseLink()
    {
    }

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

↑ V560 A part of conditional expression is always true: bUpdate.

↑ V1019 Compound assignment expression 'rValue >>= sState' is used inside condition.

↑ V560 A part of conditional expression is always false: !GetObj().

↑ V560 A part of conditional expression is always true.