/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; static void ImplDrawDefault( OutputDevice* pOutDev, const OUString* pText, vcl::Font* pFont, const Bitmap* pBitmap, const BitmapEx* pBitmapEx, const Point& rDestPt, const Size& rDestSize ) { sal_uInt16 nPixel = (sal_uInt16) pOutDev->PixelToLogic( Size( 1, 1 ) ).Width(); sal_uInt16 nPixelWidth = nPixel; Point aPoint( rDestPt.X() + nPixelWidth, rDestPt.Y() + nPixelWidth ); Size aSize( rDestSize.Width() - ( nPixelWidth << 1 ), rDestSize.Height() - ( nPixelWidth << 1 ) ); bool bFilled = ( pBitmap != nullptr || pBitmapEx != nullptr || pFont != nullptr ); Rectangle aBorderRect( aPoint, aSize ); pOutDev->Push(); pOutDev->SetFillColor(); // On the printer a black rectangle and on the screen one with 3D effect if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) pOutDev->SetLineColor( COL_BLACK ); else { aBorderRect.Left() += nPixel; aBorderRect.Top() += nPixel; pOutDev->SetLineColor( COL_LIGHTGRAY ); pOutDev->DrawRect( aBorderRect ); aBorderRect.Left() -= nPixel; aBorderRect.Top() -= nPixel; aBorderRect.Right() -= nPixel; aBorderRect.Bottom() -= nPixel; pOutDev->SetLineColor( COL_GRAY ); } pOutDev->DrawRect( aBorderRect ); aPoint.X() += nPixelWidth + 2*nPixel; aPoint.Y() += nPixelWidth + 2*nPixel; aSize.Width() -= 2*nPixelWidth + 4*nPixel; aSize.Height() -= 2*nPixelWidth + 4*nPixel; if( aSize.Width() > 0 && aSize.Height() > 0 && ( ( pBitmap && !!*pBitmap ) || ( pBitmapEx && !!*pBitmapEx ) ) ) { Size aBitmapSize( pOutDev->PixelToLogic( pBitmap ? pBitmap->GetSizePixel() : pBitmapEx->GetSizePixel() ) ); if( aSize.Height() > aBitmapSize.Height() && aSize.Width() > aBitmapSize.Width() ) { if ( pBitmap ) pOutDev->DrawBitmap( aPoint, *pBitmap ); else pOutDev->DrawBitmapEx( aPoint, *pBitmapEx ); aPoint.X() += aBitmapSize.Width() + 2*nPixel; aSize.Width() -= aBitmapSize.Width() + 2*nPixel; } } if ( aSize.Width() > 0 && aSize.Height() > 0 && pFont && pText && pText->getLength() && !(!pOutDev->IsOutputEnabled() /*&& pOutDev->GetConnectMetaFile() */) ) { MapMode aMapMode( MAP_POINT ); Size aSz = pOutDev->LogicToLogic( Size( 0, 12 ), &aMapMode, nullptr ); long nThreshold = aSz.Height() / 2; long nStep = nThreshold / 3; if ( !nStep ) nStep = aSz.Height() - nThreshold; for(;; aSz.Height() -= nStep ) { pFont->SetFontSize( aSz ); pOutDev->SetFont( *pFont ); long nTextHeight = pOutDev->GetTextHeight(); long nTextWidth = pOutDev->GetTextWidth( *pText ); if ( nTextHeight ) { // The approximation does not respect imprecisions caused // by word wraps long nLines = aSize.Height() / nTextHeight; long nWidth = aSize.Width() * nLines; // Approximation!!! if ( nTextWidth <= nWidth || aSz.Height() <= nThreshold ) { sal_uInt16 nStart = 0; sal_uInt16 nLen = 0; while( nStart < pText->getLength() && (*pText)[nStart] == ' ' ) nStart++; while( nStart+nLen < pText->getLength() && (*pText)[nStart+nLen] != ' ' ) nLen++; while( nStart < pText->getLength() && nLines-- ) { sal_uInt16 nNext = nLen; do { while ( nStart+nNext < pText->getLength() && (*pText)[nStart+nNext] == ' ' ) nNext++; while ( nStart+nNext < pText->getLength() && (*pText)[nStart+nNext] != ' ' ) nNext++; nTextWidth = pOutDev->GetTextWidth( *pText, nStart, nNext ); if ( nTextWidth > aSize.Width() ) break; nLen = nNext; } while ( nStart+nNext < pText->getLength() ); sal_uInt16 n = nLen; nTextWidth = pOutDev->GetTextWidth( *pText, nStart, n ); while( nTextWidth > aSize.Width() ) nTextWidth = pOutDev->GetTextWidth( *pText, nStart, --n ); pOutDev->DrawText( aPoint, *pText, nStart, n ); aPoint.Y() += nTextHeight; nStart = sal::static_int_cast(nStart + nLen); nLen = nNext-nLen; while( nStart < pText->getLength() && (*pText)[nStart] == ' ' ) { nStart++; nLen--; } } break; } } else break; } } // If the default graphic does not have content, we draw a red rectangle if( !bFilled ) { aBorderRect.Left()++; aBorderRect.Top()++; aBorderRect.Right()--; aBorderRect.Bottom()--; pOutDev->SetLineColor( COL_LIGHTRED ); pOutDev->DrawLine( aBorderRect.TopLeft(), aBorderRect.BottomRight() ); pOutDev->DrawLine( aBorderRect.TopRight(), aBorderRect.BottomLeft() ); } pOutDev->Pop(); } Graphic::Graphic() { mpImpGraphic = new ImpGraphic; } Graphic::Graphic( const Graphic& rGraphic ) : SvDataCopyStream() { if( rGraphic.IsAnimated() ) mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic ); else { mpImpGraphic = rGraphic.mpImpGraphic; mpImpGraphic->mnRefCount++; } } Graphic::Graphic( const Bitmap& rBmp ) { mpImpGraphic = new ImpGraphic( rBmp ); } Graphic::Graphic( const BitmapEx& rBmpEx ) { mpImpGraphic = new ImpGraphic( rBmpEx ); } Graphic::Graphic(const SvgDataPtr& rSvgDataPtr) { mpImpGraphic = new ImpGraphic(rSvgDataPtr); } Graphic::Graphic( const Animation& rAnimation ) { mpImpGraphic = new ImpGraphic( rAnimation ); } Graphic::Graphic( const GDIMetaFile& rMtf ) { mpImpGraphic = new ImpGraphic( rMtf ); } Graphic::Graphic( const css::uno::Reference< css::graphic::XGraphic >& rxGraphic ) { uno::Reference< lang::XUnoTunnel > xTunnel( rxGraphic, uno::UNO_QUERY ); const ::Graphic* pGraphic = ( xTunnel.is() ? reinterpret_cast< ::Graphic* >( xTunnel->getSomething( getUnoTunnelId() ) ) : nullptr ); if( pGraphic ) { if( pGraphic->IsAnimated() ) mpImpGraphic = new ImpGraphic( *pGraphic->mpImpGraphic ); else { mpImpGraphic = pGraphic->mpImpGraphic; mpImpGraphic->mnRefCount++; } } else mpImpGraphic = new ImpGraphic; } Graphic::~Graphic() { if( mpImpGraphic->mnRefCount == 1UL ) delete mpImpGraphic; else mpImpGraphic->mnRefCount--; } void Graphic::ImplTestRefCount() { if( mpImpGraphic->mnRefCount > 1UL ) { mpImpGraphic->mnRefCount--; mpImpGraphic = new ImpGraphic( *mpImpGraphic ); } } Graphic& Graphic::operator=( const Graphic& rGraphic ) { if( &rGraphic != this ) { if( rGraphic.IsAnimated() ) { if( mpImpGraphic->mnRefCount == 1UL ) delete mpImpGraphic; else mpImpGraphic->mnRefCount--; mpImpGraphic = new ImpGraphic( *rGraphic.mpImpGraphic ); } else { rGraphic.mpImpGraphic->mnRefCount++; if( mpImpGraphic->mnRefCount == 1UL ) delete mpImpGraphic; else mpImpGraphic->mnRefCount--; mpImpGraphic = rGraphic.mpImpGraphic; } } return *this; } bool Graphic::operator==( const Graphic& rGraphic ) const { return( *mpImpGraphic == *rGraphic.mpImpGraphic ); } bool Graphic::operator!=( const Graphic& rGraphic ) const { return( *mpImpGraphic != *rGraphic.mpImpGraphic ); } bool Graphic::operator!() const { return( GRAPHIC_NONE == mpImpGraphic->ImplGetType() ); } void Graphic::Clear() { ImplTestRefCount(); mpImpGraphic->ImplClear(); } GraphicType Graphic::GetType() const { return mpImpGraphic->ImplGetType(); } void Graphic::SetDefaultType() { ImplTestRefCount(); mpImpGraphic->ImplSetDefaultType(); } bool Graphic::IsSupportedGraphic() const { return mpImpGraphic->ImplIsSupportedGraphic(); } bool Graphic::IsTransparent() const { return mpImpGraphic->ImplIsTransparent(); } bool Graphic::IsAlpha() const { return mpImpGraphic->ImplIsAlpha(); } bool Graphic::IsAnimated() const { return mpImpGraphic->ImplIsAnimated(); } bool Graphic::IsEPS() const { return mpImpGraphic->ImplIsEPS(); } Bitmap Graphic::GetBitmap(const GraphicConversionParameters& rParameters) const { return mpImpGraphic->ImplGetBitmap(rParameters); } BitmapEx Graphic::GetBitmapEx(const GraphicConversionParameters& rParameters) const { return mpImpGraphic->ImplGetBitmapEx(rParameters); } Animation Graphic::GetAnimation() const { return mpImpGraphic->ImplGetAnimation(); } const GDIMetaFile& Graphic::GetGDIMetaFile() const { return mpImpGraphic->ImplGetGDIMetaFile(); } uno::Reference< graphic::XGraphic > Graphic::GetXGraphic() const { uno::Reference< graphic::XGraphic > xRet; if( GetType() != GRAPHIC_NONE ) { uno::Reference < uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); uno::Reference< graphic::XGraphicProvider > xProv( graphic::GraphicProvider::create( xContext ) ); uno::Sequence< beans::PropertyValue > aLoadProps( 1 ); OUString aURL = "private:memorygraphic/" + OUString::number( reinterpret_cast< sal_Int64 >( this ) ); aLoadProps[ 0 ].Name = "URL"; aLoadProps[ 0 ].Value <<= aURL; xRet = xProv->queryGraphic( aLoadProps ); } return xRet; } Size Graphic::GetPrefSize() const { return mpImpGraphic->ImplGetPrefSize(); } void Graphic::SetPrefSize( const Size& rPrefSize ) { ImplTestRefCount(); mpImpGraphic->ImplSetPrefSize( rPrefSize ); } MapMode Graphic::GetPrefMapMode() const { return mpImpGraphic->ImplGetPrefMapMode(); } void Graphic::SetPrefMapMode( const MapMode& rPrefMapMode ) { ImplTestRefCount(); mpImpGraphic->ImplSetPrefMapMode( rPrefMapMode ); } basegfx::B2DSize Graphic::GetPPI() const { MapMode aMapMode = GetPrefMapMode(); double fWidthInches = ( GetPrefSize().Width() * aMapMode.GetUnitMultiplier() ) / 2540; double fHeightInches = ( GetPrefSize().Height() * aMapMode.GetUnitMultiplier() ) / 2540; double fPpiX = 0; double fPpiY = 0; if ( fWidthInches > 0 || fHeightInches > 0 ) // we don't want a divide by 0 situation { fPpiX = GetSizePixel().Width() / fWidthInches; fPpiY = GetSizePixel().Height() / fHeightInches; } else { SAL_WARN("vcl", "PPI X is " << fPpiX << " and PPI Y is " << fPpiY << ": thus we are making this 0 DPI. This is unlikely."); } return basegfx::B2DSize( fPpiX, fPpiY ); } Size Graphic::GetSizePixel( const OutputDevice* pRefDevice ) const { Size aRet; if( GRAPHIC_BITMAP == mpImpGraphic->ImplGetType() ) aRet = mpImpGraphic->ImplGetBitmapEx(GraphicConversionParameters()).GetSizePixel(); else aRet = ( pRefDevice ? pRefDevice : Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() ); return aRet; } sal_uLong Graphic::GetSizeBytes() const { return mpImpGraphic->ImplGetSizeBytes(); } void Graphic::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const { mpImpGraphic->ImplDraw( pOutDev, rDestPt ); } void Graphic::Draw( OutputDevice* pOutDev, const Point& rDestPt, const Size& rDestSz ) const { if( GRAPHIC_DEFAULT == mpImpGraphic->ImplGetType() ) ImplDrawDefault( pOutDev, nullptr, nullptr, nullptr, nullptr, rDestPt, rDestSz ); else mpImpGraphic->ImplDraw( pOutDev, rDestPt, rDestSz ); } void Graphic::DrawEx( OutputDevice* pOutDev, const OUString& rText, vcl::Font& rFont, const BitmapEx& rBitmap, const Point& rDestPt, const Size& rDestSz ) { ImplDrawDefault( pOutDev, &rText, &rFont, nullptr, &rBitmap, rDestPt, rDestSz ); } void Graphic::StartAnimation( OutputDevice* pOutDev, const Point& rDestPt, const Size& rDestSz, long nExtraData, OutputDevice* pFirstFrameOutDev ) { ImplTestRefCount(); mpImpGraphic->ImplStartAnimation( pOutDev, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev ); } void Graphic::StopAnimation( OutputDevice* pOutDev, long nExtraData ) { ImplTestRefCount(); mpImpGraphic->ImplStopAnimation( pOutDev, nExtraData ); } void Graphic::SetAnimationNotifyHdl( const Link& rLink ) { mpImpGraphic->ImplSetAnimationNotifyHdl( rLink ); } Link Graphic::GetAnimationNotifyHdl() const { return mpImpGraphic->ImplGetAnimationNotifyHdl(); } sal_uLong Graphic::GetAnimationLoopCount() const { return mpImpGraphic->ImplGetAnimationLoopCount(); } GraphicReader* Graphic::GetContext() { return mpImpGraphic->ImplGetContext(); } void Graphic::SetContext( GraphicReader* pReader ) { mpImpGraphic->ImplSetContext( pReader ); } bool Graphic::SwapOut() { ImplTestRefCount(); return mpImpGraphic->ImplSwapOut(); } void Graphic::SwapOutAsLink() { ImplTestRefCount(); mpImpGraphic->ImplSwapOutAsLink(); } bool Graphic::SwapOut( SvStream* pOStream ) { ImplTestRefCount(); return mpImpGraphic->ImplSwapOut( pOStream ); } bool Graphic::SwapIn() { ImplTestRefCount(); return mpImpGraphic->ImplSwapIn(); } bool Graphic::SwapIn( SvStream* pStrm ) { ImplTestRefCount(); return mpImpGraphic->ImplSwapIn( pStrm ); } bool Graphic::IsSwapOut() const { return mpImpGraphic->ImplIsSwapOut(); } void Graphic::SetLink( const GfxLink& rGfxLink ) { ImplTestRefCount(); mpImpGraphic->ImplSetLink( rGfxLink ); } GfxLink Graphic::GetLink() const { return mpImpGraphic->ImplGetLink(); } bool Graphic::IsLink() const { return mpImpGraphic->ImplIsLink(); } BitmapChecksum Graphic::GetChecksum() const { return mpImpGraphic->ImplGetChecksum(); } bool Graphic::ExportNative( SvStream& rOStream ) const { return mpImpGraphic->ImplExportNative( rOStream ); } SvStream& ReadGraphic( SvStream& rIStream, Graphic& rGraphic ) { rGraphic.ImplTestRefCount(); return ReadImpGraphic( rIStream, *rGraphic.mpImpGraphic ); } SvStream& WriteGraphic( SvStream& rOStream, const Graphic& rGraphic ) { return WriteImpGraphic( rOStream, *rGraphic.mpImpGraphic ); } const SvgDataPtr& Graphic::getSvgData() const { return mpImpGraphic->getSvgData(); } namespace { struct Id: public rtl::Static {}; } css::uno::Sequence Graphic::getUnoTunnelId() { return Id::get().getImplementationId(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */