/* -*- 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 "graphiccollector.hxx"
#include <com/sun/star/awt/XDevice.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#include <com/sun/star/presentation/XPresentationPage.hpp>
#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
 
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::graphic;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::presentation;
 
const DeviceInfo& GraphicCollector::GetDeviceInfo( const Reference< XComponentContext >& rxFact )
{
    static DeviceInfo aDeviceInfo;
    if( !aDeviceInfo.Width )
    {
        try
        {
            Reference< XDesktop2 > xDesktop = Desktop::create( rxFact );
            Reference< XFrame > xFrame( xDesktop->getActiveFrame() );
            Reference< XWindow > xWindow( xFrame->getContainerWindow() );
            Reference< XDevice > xDevice( xWindow, UNO_QUERY_THROW );
            aDeviceInfo = xDevice->getInfo();
        }
        catch( Exception& )
        {
        }
    }
    return aDeviceInfo;
}
 
static void ImpAddEntity( std::vector< GraphicCollector::GraphicEntity >& rGraphicEntities, const GraphicSettings& rGraphicSettings, const GraphicCollector::GraphicUser& rUser )
{
    if ( !rGraphicSettings.mbEmbedLinkedGraphics )
        return;
 
    auto aIter = std::find_if(rGraphicEntities.begin(), rGraphicEntities.end(),
        [&rUser](const GraphicCollector::GraphicEntity& rGraphicEntity) {
            return rGraphicEntity.maUser[ 0 ].mxGraphic == rUser.mxGraphic;
        });
    if ( aIter == rGraphicEntities.end() )
    {
        GraphicCollector::GraphicEntity aEntity( rUser );
        rGraphicEntities.push_back( aEntity );
    }
    else
    {
        if ( rUser.maLogicalSize.Width > aIter->maLogicalSize.Width )
            aIter->maLogicalSize.Width = rUser.maLogicalSize.Width;
        if ( rUser.maLogicalSize.Height > aIter->maLogicalSize.Height )
            aIter->maLogicalSize.Height = rUser.maLogicalSize.Height;
        aIter->maUser.push_back( rUser );
    }
}
 
static void ImpAddGraphicEntity( const Reference< XComponentContext >& rxMSF, Reference< XShape > const & rxShape, const GraphicSettings& rGraphicSettings, std::vector< GraphicCollector::GraphicEntity >& rGraphicEntities )
{
    Reference< XGraphic > xGraphic;
    Reference< XPropertySet > xShapePropertySet( rxShape, UNO_QUERY_THROW );
    if ( !(xShapePropertySet->getPropertyValue( u"Graphic"_ustr ) >>= xGraphic) )
        return;
 
    text::GraphicCrop aGraphicCropLogic( 0, 0, 0, 0 );
 
    GraphicCollector::GraphicUser aUser;
    aUser.mxShape = rxShape;
    aUser.mbFillBitmap = false;
    aUser.mxGraphic = xGraphic;
    xShapePropertySet->getPropertyValue( u"GraphicCrop"_ustr ) >>= aGraphicCropLogic;
    awt::Size aLogicalSize( rxShape->getSize() );
 
    // calculating the logical size, as if there were no cropping
    if ( aGraphicCropLogic.Left || aGraphicCropLogic.Right || aGraphicCropLogic.Top || aGraphicCropLogic.Bottom )
    {
        awt::Size aSize100thMM( GraphicCollector::GetOriginalSize( rxMSF, xGraphic ) );
        if ( aSize100thMM.Width && aSize100thMM.Height )
        {
            awt::Size aCropSize( aSize100thMM.Width - ( aGraphicCropLogic.Left + aGraphicCropLogic.Right ),
                                 aSize100thMM.Height - ( aGraphicCropLogic.Top + aGraphicCropLogic.Bottom ));
            if ( aCropSize.Width && aCropSize.Height )
            {
                awt::Size aNewLogSize( static_cast< sal_Int32 >( static_cast< double >( aSize100thMM.Width * aLogicalSize.Width ) / aCropSize.Width ),
                    static_cast< sal_Int32 >( static_cast< double >( aSize100thMM.Height * aLogicalSize.Height ) / aCropSize.Height ) );
                aLogicalSize = aNewLogSize;
            }
        }
    }
    aUser.maGraphicCropLogic = aGraphicCropLogic;
    aUser.maLogicalSize = aLogicalSize;
    ImpAddEntity( rGraphicEntities, rGraphicSettings, aUser );
}
 
static void ImpAddFillBitmapEntity( const Reference< XComponentContext >& rxMSF, const Reference< XPropertySet >& rxPropertySet, const awt::Size& rLogicalSize,
    std::vector< GraphicCollector::GraphicEntity >& rGraphicEntities, const GraphicSettings& rGraphicSettings, const Reference< XPropertySet >& rxPagePropertySet )
{
    try
    {
        FillStyle eFillStyle;
        if ( rxPropertySet->getPropertyValue( u"FillStyle"_ustr ) >>= eFillStyle )
        {
            if ( eFillStyle == FillStyle_BITMAP )
            {
                Reference< XBitmap > xFillBitmap;
                if ( rxPropertySet->getPropertyValue( u"FillBitmap"_ustr ) >>= xFillBitmap )
                {
                    Reference< XGraphic > xGraphic( xFillBitmap, UNO_QUERY_THROW );
                    awt::Size aLogicalSize( rLogicalSize );
                    Reference< XPropertySetInfo > axPropSetInfo( rxPropertySet->getPropertySetInfo() );
                    if ( axPropSetInfo.is() )
                    {
                        if ( axPropSetInfo->hasPropertyByName( u"FillBitmapMode"_ustr ) )
                        {
                            BitmapMode eBitmapMode;
                            if ( rxPropertySet->getPropertyValue( u"FillBitmapMode"_ustr ) >>= eBitmapMode )
                            {
                                if ( ( eBitmapMode == BitmapMode_REPEAT ) || ( eBitmapMode == BitmapMode_NO_REPEAT ) )
                                {
                                    bool bLogicalSize = false;
                                    awt::Size aSize( 0, 0 );
                                    if ( ( rxPropertySet->getPropertyValue( u"FillBitmapLogicalSize"_ustr ) >>= bLogicalSize )
                                      && ( rxPropertySet->getPropertyValue( u"FillBitmapSizeX"_ustr ) >>= aSize.Width )
                                      && ( rxPropertySet->getPropertyValue( u"FillBitmapSizeY"_ustr ) >>= aSize.Height ) )
                                    {
                                        if ( bLogicalSize )
                                        {
                                            if ( !aSize.Width || !aSize.Height )
                                            {
                                                awt::Size aSize100thMM( GraphicCollector::GetOriginalSize( rxMSF, xGraphic ) );
                                                if ( aSize100thMM.Width && aSize100thMM.Height )
                                                    aLogicalSize = aSize100thMM;
                                            }
                                            else
                                                aLogicalSize = aSize;
                                        }
                                        else
                                        {
                                            aLogicalSize.Width = sal::static_int_cast< sal_Int32 >( ( static_cast< double >( aLogicalSize.Width ) * aSize.Width ) / -100.0 );
                                            aLogicalSize.Height = sal::static_int_cast< sal_Int32 >( ( static_cast< double >( aLogicalSize.Height ) * aSize.Height ) / -100.0 );
                                        }
                                    }
                                }
                            }
                        }
                    }
                    GraphicCollector::GraphicUser aUser;
                    aUser.mxPropertySet = rxPropertySet;
                    aUser.mxGraphic = std::move(xGraphic);
                    aUser.mbFillBitmap = true;
                    aUser.maLogicalSize = aLogicalSize;
                    aUser.mxPagePropertySet = rxPagePropertySet;
                    ImpAddEntity( rGraphicEntities, rGraphicSettings, aUser );
                }
            }
        }
    }
    catch( Exception& )
    {
    }
}
 
static void ImpCollectBackgroundGraphic( const Reference< XComponentContext >& rxMSF, const Reference< XDrawPage >& rxDrawPage, const GraphicSettings& rGraphicSettings, std::vector< GraphicCollector::GraphicEntity >& rGraphicEntities )
{
    try
    {
        awt::Size aLogicalSize( 28000, 21000 );
        Reference< XPropertySet > xPropertySet( rxDrawPage, UNO_QUERY_THROW );
        xPropertySet->getPropertyValue( u"Width"_ustr ) >>= aLogicalSize.Width;
        xPropertySet->getPropertyValue( u"Height"_ustr ) >>= aLogicalSize.Height;
 
        Reference< XPropertySet > xBackgroundPropSet;
        if ( xPropertySet->getPropertyValue( u"Background"_ustr ) >>= xBackgroundPropSet )
            ImpAddFillBitmapEntity( rxMSF, xBackgroundPropSet, aLogicalSize, rGraphicEntities, rGraphicSettings, xPropertySet );
    }
    catch( Exception& )
    {
    }
}
 
static void ImpCollectGraphicObjects( const Reference< XComponentContext >& rxMSF, const Reference< XShapes >& rxShapes, const GraphicSettings& rGraphicSettings, std::vector< GraphicCollector::GraphicEntity >& rGraphicEntities )
{
    for ( sal_Int32 i = 0; i < rxShapes->getCount(); i++ )
    {
        try
        {
            Reference< XShape > xShape( rxShapes->getByIndex( i ), UNO_QUERY_THROW );
            const OUString sShapeType( xShape->getShapeType() );
            if ( sShapeType == "com.sun.star.drawing.GroupShape" )
            {
                Reference< XShapes > xShapes( xShape, UNO_QUERY_THROW );
                ImpCollectGraphicObjects( rxMSF, xShapes, rGraphicSettings, rGraphicEntities );
                continue;
            }
 
            if ( sShapeType == "com.sun.star.drawing.GraphicObjectShape" ||
                 sShapeType == "com.sun.star.presentation.GraphicObjectShape" )
                ImpAddGraphicEntity( rxMSF, xShape, rGraphicSettings, rGraphicEntities );
 
            // now check for a fillstyle
            Reference< XPropertySet > xEmptyPagePropSet;
            Reference< XPropertySet > xShapePropertySet( xShape, UNO_QUERY_THROW );
            awt::Size aLogicalSize( xShape->getSize() );
            ImpAddFillBitmapEntity( rxMSF, xShapePropertySet, aLogicalSize, rGraphicEntities, rGraphicSettings, xEmptyPagePropSet );
        }
        catch( Exception& )
        {
        }
    }
}
 
awt::Size GraphicCollector::GetOriginalSize( const Reference< XComponentContext >& rxMSF, const Reference< XGraphic >& rxGraphic )
{
    awt::Size aSize100thMM( 0, 0 );
    Reference< XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
    if ( xGraphicPropertySet->getPropertyValue( u"Size100thMM"_ustr ) >>= aSize100thMM )
    {
        if ( !aSize100thMM.Width && !aSize100thMM.Height )
        {   // MAPMODE_PIXEL USED :-(
            awt::Size aSourceSizePixel( 0, 0 );
            if ( xGraphicPropertySet->getPropertyValue( u"SizePixel"_ustr ) >>= aSourceSizePixel )
            {
                const DeviceInfo& rDeviceInfo( GraphicCollector::GetDeviceInfo( rxMSF ) );
                if ( rDeviceInfo.PixelPerMeterX && rDeviceInfo.PixelPerMeterY )
                {
                    aSize100thMM.Width = static_cast< sal_Int32 >( ( aSourceSizePixel.Width * 100000.0 ) / rDeviceInfo.PixelPerMeterX );
                    aSize100thMM.Height = static_cast< sal_Int32 >( ( aSourceSizePixel.Height * 100000.0 ) / rDeviceInfo.PixelPerMeterY );
                }
            }
        }
    }
    return aSize100thMM;
}
 
void GraphicCollector::CollectGraphics( const Reference< XComponentContext >& rxMSF, const Reference< XModel >& rxModel,
        const GraphicSettings& rGraphicSettings, std::vector< GraphicCollector::GraphicEntity >& rGraphicList )
{
    try
    {
        sal_Int32 i;
        Reference< XDrawPagesSupplier > xDrawPagesSupplier( rxModel, UNO_QUERY_THROW );
        Reference< XDrawPages > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW );
        for ( i = 0; i < xDrawPages->getCount(); i++ )
        {
            Reference< XDrawPage > xDrawPage( xDrawPages->getByIndex( i ), UNO_QUERY_THROW );
            ImpCollectBackgroundGraphic( rxMSF, xDrawPage, rGraphicSettings, rGraphicList );
            ImpCollectGraphicObjects( rxMSF, xDrawPage, rGraphicSettings, rGraphicList );
 
            Reference< XPresentationPage > xPresentationPage( xDrawPage, UNO_QUERY_THROW );
            Reference< XDrawPage > xNotesPage( xPresentationPage->getNotesPage() );
            ImpCollectBackgroundGraphic( rxMSF, xNotesPage, rGraphicSettings, rGraphicList );
            ImpCollectGraphicObjects( rxMSF, xNotesPage, rGraphicSettings, rGraphicList );
        }
        Reference< XMasterPagesSupplier > xMasterPagesSupplier( rxModel, UNO_QUERY_THROW );
        Reference< XDrawPages > xMasterPages( xMasterPagesSupplier->getMasterPages(), UNO_SET_THROW );
        for ( i = 0; i < xMasterPages->getCount(); i++ )
        {
            Reference< XDrawPage > xMasterPage( xMasterPages->getByIndex( i ), UNO_QUERY_THROW );
            ImpCollectBackgroundGraphic( rxMSF, xMasterPage, rGraphicSettings, rGraphicList );
            ImpCollectGraphicObjects( rxMSF, xMasterPage, rGraphicSettings, rGraphicList );
        }
 
        for( auto& rGraphic : rGraphicList )
        {
            // check if it is possible to remove the crop area
            rGraphic.mbRemoveCropArea = rGraphicSettings.mbRemoveCropArea;
            if ( rGraphic.mbRemoveCropArea )
            {
                std::vector< GraphicCollector::GraphicUser >::iterator aGUIter( rGraphic.maUser.begin() );
                while( rGraphic.mbRemoveCropArea && ( aGUIter != rGraphic.maUser.end() ) )
                {
                    if ( aGUIter->maGraphicCropLogic.Left || aGUIter->maGraphicCropLogic.Top
                        || aGUIter->maGraphicCropLogic.Right || aGUIter->maGraphicCropLogic.Bottom )
                    {
                        if ( aGUIter == rGraphic.maUser.begin() )
                            rGraphic.maGraphicCropLogic = aGUIter->maGraphicCropLogic;
                        else if ( ( rGraphic.maGraphicCropLogic.Left != aGUIter->maGraphicCropLogic.Left )
                            || ( rGraphic.maGraphicCropLogic.Top != aGUIter->maGraphicCropLogic.Top )
                            || ( rGraphic.maGraphicCropLogic.Right != aGUIter->maGraphicCropLogic.Right )
                            || ( rGraphic.maGraphicCropLogic.Bottom != aGUIter->maGraphicCropLogic.Bottom ) )
                        {
                            rGraphic.mbRemoveCropArea = false;
                        }
                    }
                    else
                        rGraphic.mbRemoveCropArea = false;
                    ++aGUIter;
                }
            }
            if ( !rGraphic.mbRemoveCropArea )
                rGraphic.maGraphicCropLogic = text::GraphicCrop( 0, 0, 0, 0 );
        }
    }
    catch ( Exception& )
    {
    }
}
 
static void ImpCountGraphicObjects( const Reference< XComponentContext >& rxMSF, const Reference< XShapes >& rxShapes, const GraphicSettings& rGraphicSettings, sal_Int32& rnGraphics )
{
    for ( sal_Int32 i = 0; i < rxShapes->getCount(); i++ )
    {
        try
        {
            Reference< XShape > xShape( rxShapes->getByIndex( i ), UNO_QUERY_THROW );
            const OUString sShapeType( xShape->getShapeType() );
            if ( sShapeType == "com.sun.star.drawing.GroupShape" )
            {
                Reference< XShapes > xShapes( xShape, UNO_QUERY_THROW );
                ImpCountGraphicObjects( rxMSF, xShapes, rGraphicSettings, rnGraphics );
                continue;
            }
 
            if ( sShapeType == "com.sun.star.drawing.GraphicObjectShape" ||
                 sShapeType == "com.sun.star.presentation.GraphicObjectShape" )
            {
                rnGraphics++;
            }
 
            // now check for a fillstyle
            Reference< XPropertySet > xShapePropertySet( xShape, UNO_QUERY_THROW );
            FillStyle eFillStyle;
            if ( xShapePropertySet->getPropertyValue( u"FillStyle"_ustr ) >>= eFillStyle )
            {
                if ( eFillStyle == FillStyle_BITMAP )
                {
                    rnGraphics++;
                }
            }
        }
        catch( Exception& )
        {
        }
    }
}
 
static void ImpCountBackgroundGraphic(
    const Reference< XDrawPage >& rxDrawPage, sal_Int32& rnGraphics )
{
    try
    {
        awt::Size aLogicalSize( 28000, 21000 );
        Reference< XPropertySet > xPropertySet( rxDrawPage, UNO_QUERY_THROW );
        xPropertySet->getPropertyValue( u"Width"_ustr ) >>= aLogicalSize.Width;
        xPropertySet->getPropertyValue( u"Height"_ustr ) >>= aLogicalSize.Height;
 
        Reference< XPropertySet > xBackgroundPropSet;
        if ( xPropertySet->getPropertyValue( u"Background"_ustr ) >>= xBackgroundPropSet )
        {
            FillStyle eFillStyle;
            if ( xBackgroundPropSet->getPropertyValue( u"FillStyle"_ustr ) >>= eFillStyle )
            {
                if ( eFillStyle == FillStyle_BITMAP )
                {
                    rnGraphics++;
                }
            }
        }
    }
    catch( Exception& )
    {
    }
}
 
void GraphicCollector::CountGraphics( const Reference< XComponentContext >& rxMSF, const Reference< XModel >& rxModel,
        const GraphicSettings& rGraphicSettings, sal_Int32& rnGraphics )
{
    try
    {
        sal_Int32 i;
        Reference< XDrawPagesSupplier > xDrawPagesSupplier( rxModel, UNO_QUERY_THROW );
        Reference< XDrawPages > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW );
        for ( i = 0; i < xDrawPages->getCount(); i++ )
        {
            Reference< XDrawPage > xDrawPage( xDrawPages->getByIndex( i ), UNO_QUERY_THROW );
            ImpCountBackgroundGraphic( xDrawPage, rnGraphics );
            ImpCountGraphicObjects( rxMSF, xDrawPage, rGraphicSettings, rnGraphics );
 
            Reference< XPresentationPage > xPresentationPage( xDrawPage, UNO_QUERY_THROW );
            Reference< XDrawPage > xNotesPage( xPresentationPage->getNotesPage() );
            ImpCountBackgroundGraphic( xNotesPage, rnGraphics );
            ImpCountGraphicObjects( rxMSF, xNotesPage, rGraphicSettings, rnGraphics );
        }
        Reference< XMasterPagesSupplier > xMasterPagesSupplier( rxModel, UNO_QUERY_THROW );
        Reference< XDrawPages > xMasterPages( xMasterPagesSupplier->getMasterPages(), UNO_SET_THROW );
        for ( i = 0; i < xMasterPages->getCount(); i++ )
        {
            Reference< XDrawPage > xMasterPage( xMasterPages->getByIndex( i ), UNO_QUERY_THROW );
            ImpCountBackgroundGraphic( xMasterPage, rnGraphics );
            ImpCountGraphicObjects( rxMSF, xMasterPage, rGraphicSettings, rnGraphics );
        }
    }
    catch ( Exception& )
    {
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V614 Uninitialized variable 'eFillStyle' used.

V614 Uninitialized variable 'eBitmapMode' used.

V614 Uninitialized variable 'eFillStyle' used.

V614 Uninitialized variable 'eFillStyle' used.

V547 Expression 'bLogicalSize' is always false.

V1019 Compound assignment expression is used inside condition.

V1019 Compound assignment expression is used inside condition.