/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svtools.hxx" #define ENABLE_BYTESTRING_STREAM_OPERATORS #include #include #include #include #include #include #include #include #include #include #include #include // --> OD 2010-01-04 #i105243# #include // <-- // ----------- // - Defines - // ----------- #define WATERMARK_LUM_OFFSET 50 #define WATERMARK_CON_OFFSET -70 // ----------- // - statics - // ----------- GraphicManager* GraphicObject::mpGlobalMgr = NULL; // --------------------- // - GrfDirectCacheObj - // --------------------- struct GrfSimpleCacheObj { Graphic maGraphic; GraphicAttr maAttr; GrfSimpleCacheObj( const Graphic& rGraphic, const GraphicAttr& rAttr ) : maGraphic( rGraphic ), maAttr( rAttr ) {} }; // ----------------- // - GraphicObject - // ----------------- TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream ); // unique increasing ID for being able to detect the GraphicObject with the // oldest last data changes static sal_uLong aIncrementingTimeOfLastDataChange = 1; void GraphicObject::ImplAfterDataChange() { // set unique timestamp ID of last data change mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; // check memory footprint of all GraphicObjects managed and evtl. take action GetGraphicManager().ImplCheckSizeOfSwappedInGraphics(); } // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const GraphicManager* pMgr ) : mpLink ( NULL ), mpUserData ( NULL ) { ImplConstruct(); ImplAssignGraphicData(); ImplSetGraphicManager( pMgr ); } // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const Graphic& rGraphic, const GraphicManager* pMgr ) : maGraphic ( rGraphic ), mpLink ( NULL ), mpUserData ( NULL ) { ImplConstruct(); ImplAssignGraphicData(); ImplSetGraphicManager( pMgr ); } // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const Graphic& rGraphic, const String& rLink, const GraphicManager* pMgr ) : maGraphic ( rGraphic ), mpLink ( rLink.Len() ? ( new String( rLink ) ) : NULL ), mpUserData ( NULL ) { ImplConstruct(); ImplAssignGraphicData(); ImplSetGraphicManager( pMgr ); } // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const GraphicObject& rGraphicObj, const GraphicManager* pMgr ) : SvDataCopyStream(), maGraphic ( rGraphicObj.GetGraphic() ), maAttr ( rGraphicObj.maAttr ), mpLink ( rGraphicObj.mpLink ? ( new String( *rGraphicObj.mpLink ) ) : NULL ), mpUserData ( rGraphicObj.mpUserData ? ( new String( *rGraphicObj.mpUserData ) ) : NULL ) { ImplConstruct(); ImplAssignGraphicData(); ImplSetGraphicManager( pMgr, NULL, &rGraphicObj ); } // ----------------------------------------------------------------------------- GraphicObject::GraphicObject( const ByteString& rUniqueID, const GraphicManager* pMgr ) : mpLink ( NULL ), mpUserData ( NULL ) { ImplConstruct(); // assign default properties ImplAssignGraphicData(); ImplSetGraphicManager( pMgr, &rUniqueID ); // update properties ImplAssignGraphicData(); } // ----------------------------------------------------------------------------- GraphicObject::~GraphicObject() { if( mpMgr ) { mpMgr->ImplUnregisterObj( *this ); if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() ) delete mpGlobalMgr, mpGlobalMgr = NULL; } delete mpSwapOutTimer; delete mpSwapStreamHdl; delete mpLink; delete mpUserData; delete mpSimpleCache; } // ----------------------------------------------------------------------------- void GraphicObject::ImplConstruct() { mpMgr = NULL; mpSwapStreamHdl = NULL; mpSwapOutTimer = NULL; mpSimpleCache = NULL; mnAnimationLoopCount = 0; mbAutoSwapped = sal_False; mbIsInSwapIn = sal_False; mbIsInSwapOut = sal_False; // Init with a unique, increasing ID mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++; } // ----------------------------------------------------------------------------- void GraphicObject::ImplAssignGraphicData() { maPrefSize = maGraphic.GetPrefSize(); maPrefMapMode = maGraphic.GetPrefMapMode(); mnSizeBytes = maGraphic.GetSizeBytes(); meType = maGraphic.GetType(); mbTransparent = maGraphic.IsTransparent(); mbAlpha = maGraphic.IsAlpha(); mbAnimated = maGraphic.IsAnimated(); mbEPS = maGraphic.IsEPS(); mnAnimationLoopCount = ( mbAnimated ? maGraphic.GetAnimationLoopCount() : 0 ); } // ----------------------------------------------------------------------------- void GraphicObject::ImplSetGraphicManager( const GraphicManager* pMgr, const ByteString* pID, const GraphicObject* pCopyObj ) { if( !mpMgr || ( pMgr != mpMgr ) ) { if( !pMgr && mpMgr && ( mpMgr == mpGlobalMgr ) ) return; else { if( mpMgr ) { mpMgr->ImplUnregisterObj( *this ); if( ( mpMgr == mpGlobalMgr ) && !mpGlobalMgr->ImplHasObjects() ) delete mpGlobalMgr, mpGlobalMgr = NULL; } if( !pMgr ) { if( !mpGlobalMgr ) { SvtCacheOptions aCacheOptions; mpGlobalMgr = new GraphicManager( aCacheOptions.GetGraphicManagerTotalCacheSize(), aCacheOptions.GetGraphicManagerObjectCacheSize() ); mpGlobalMgr->SetCacheTimeout( aCacheOptions.GetGraphicManagerObjectReleaseTime() ); } mpMgr = mpGlobalMgr; } else mpMgr = (GraphicManager*) pMgr; mpMgr->ImplRegisterObj( *this, maGraphic, pID, pCopyObj ); } } } // ----------------------------------------------------------------------------- void GraphicObject::ImplAutoSwapIn() { if( IsSwappedOut() ) { if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) mbAutoSwapped = sal_False; else { mbIsInSwapIn = sal_True; if( maGraphic.SwapIn() ) mbAutoSwapped = sal_False; else { SvStream* pStream = GetSwapStream(); if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream ) { if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream ) { if( HasLink() ) { String aURLStr; if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( GetLink(), aURLStr ) ) { SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aURLStr, STREAM_READ ); if( pIStm ) { (*pIStm) >> maGraphic; mbAutoSwapped = ( maGraphic.GetType() != GRAPHIC_NONE ); delete pIStm; } } } } else if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream ) mbAutoSwapped = !maGraphic.SwapIn(); else if( GRFMGR_AUTOSWAPSTREAM_LOADED == pStream ) mbAutoSwapped = maGraphic.IsSwapOut(); else { mbAutoSwapped = !maGraphic.SwapIn( pStream ); delete pStream; } } else { DBG_ASSERT( ( GRAPHIC_NONE == meType ) || ( GRAPHIC_DEFAULT == meType ), "GraphicObject::ImplAutoSwapIn: could not get stream to swap in graphic! (=>KA)" ); } } mbIsInSwapIn = sal_False; if( !mbAutoSwapped && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedIn( *this ); } // Handle evtl. needed AfterDataChanges ImplAfterDataChange(); } } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::ImplGetCropParams( OutputDevice* pOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr, PolyPolygon& rClipPolyPoly, sal_Bool& bRectClipRegion ) const { sal_Bool bRet = sal_False; if( GetType() != GRAPHIC_NONE ) { Polygon aClipPoly( Rectangle( rPt, rSz ) ); const sal_uInt16 nRot10 = pAttr->GetRotation() % 3600; const Point aOldOrigin( rPt ); // --> OD 2005-09-30 #i54875# - It's not needed to get the graphic again. // const Graphic& rGraphic = GetGraphic(); // <-- const MapMode aMap100( MAP_100TH_MM ); Size aSize100; long nTotalWidth, nTotalHeight; long nNewLeft, nNewTop, nNewRight, nNewBottom; double fScale; if( nRot10 ) { aClipPoly.Rotate( rPt, nRot10 ); bRectClipRegion = sal_False; } else bRectClipRegion = sal_True; rClipPolyPoly = aClipPoly; // --> OD 2005-09-30 #i54875# - directly access member to // get and . // if( rGraphic.GetPrefMapMode() == MAP_PIXEL ) // aSize100 = Application::GetDefaultDevice()->PixelToLogic( rGraphic.GetPrefSize(), aMap100 ); // else // aSize100 = pOut->LogicToLogic( rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode(), aMap100 ); if( maGraphic.GetPrefMapMode() == MAP_PIXEL ) aSize100 = Application::GetDefaultDevice()->PixelToLogic( maGraphic.GetPrefSize(), aMap100 ); else { MapMode m(maGraphic.GetPrefMapMode()); aSize100 = pOut->LogicToLogic( maGraphic.GetPrefSize(), &m, &aMap100 ); } // <-- nTotalWidth = aSize100.Width() - pAttr->GetLeftCrop() - pAttr->GetRightCrop(); nTotalHeight = aSize100.Height() - pAttr->GetTopCrop() - pAttr->GetBottomCrop(); if( aSize100.Width() > 0 && aSize100.Height() > 0 && nTotalWidth > 0 && nTotalHeight > 0 ) { fScale = (double) aSize100.Width() / nTotalWidth; nNewLeft = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_HORZ ) ? pAttr->GetRightCrop() : pAttr->GetLeftCrop() ) * fScale ); nNewRight = nNewLeft + FRound( aSize100.Width() * fScale ) - 1; fScale = (double) rSz.Width() / aSize100.Width(); rPt.X() += FRound( nNewLeft * fScale ); rSz.Width() = FRound( ( nNewRight - nNewLeft + 1 ) * fScale ); fScale = (double) aSize100.Height() / nTotalHeight; nNewTop = -FRound( ( ( pAttr->GetMirrorFlags() & BMP_MIRROR_VERT ) ? pAttr->GetBottomCrop() : pAttr->GetTopCrop() ) * fScale ); nNewBottom = nNewTop + FRound( aSize100.Height() * fScale ) - 1; fScale = (double) rSz.Height() / aSize100.Height(); rPt.Y() += FRound( nNewTop * fScale ); rSz.Height() = FRound( ( nNewBottom - nNewTop + 1 ) * fScale ); if( nRot10 ) { Polygon aOriginPoly( 1 ); aOriginPoly[ 0 ] = rPt; aOriginPoly.Rotate( aOldOrigin, nRot10 ); rPt = aOriginPoly[ 0 ]; } bRet = sal_True; } } return bRet; } // ----------------------------------------------------------------------------- GraphicObject& GraphicObject::operator=( const GraphicObject& rGraphicObj ) { if( &rGraphicObj != this ) { mpMgr->ImplUnregisterObj( *this ); delete mpSwapStreamHdl, mpSwapStreamHdl = NULL; delete mpSimpleCache, mpSimpleCache = NULL; delete mpLink; delete mpUserData; maGraphic = rGraphicObj.GetGraphic(); maAttr = rGraphicObj.maAttr; mpLink = rGraphicObj.mpLink ? new String( *rGraphicObj.mpLink ) : NULL; mpUserData = rGraphicObj.mpUserData ? new String( *rGraphicObj.mpUserData ) : NULL; ImplAssignGraphicData(); mbAutoSwapped = sal_False; mpMgr = rGraphicObj.mpMgr; mpMgr->ImplRegisterObj( *this, maGraphic, NULL, &rGraphicObj ); } return *this; } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::operator==( const GraphicObject& rGraphicObj ) const { return( ( rGraphicObj.maGraphic == maGraphic ) && ( rGraphicObj.maAttr == maAttr ) && ( rGraphicObj.GetLink() == GetLink() ) ); } // ------------------------------------------------------------------------ void GraphicObject::Load( SvStream& rIStm ) { rIStm >> *this; } // ------------------------------------------------------------------------ void GraphicObject::Save( SvStream& rOStm ) { rOStm << *this; } // ------------------------------------------------------------------------ void GraphicObject::Assign( const SvDataCopyStream& rCopyStream ) { *this = (const GraphicObject& ) rCopyStream; } // ----------------------------------------------------------------------------- ByteString GraphicObject::GetUniqueID() const { if ( !IsInSwapIn() && IsEPS() ) const_cast(this)->FireSwapInRequest(); ByteString aRet; if( mpMgr ) aRet = mpMgr->ImplGetUniqueID( *this ); return aRet; } // ----------------------------------------------------------------------------- sal_uLong GraphicObject::GetChecksum() const { return( ( maGraphic.IsSupportedGraphic() && !maGraphic.IsSwapOut() ) ? maGraphic.GetChecksum() : 0 ); } // ----------------------------------------------------------------------------- SvStream* GraphicObject::GetSwapStream() const { return( HasSwapStreamHdl() ? (SvStream*) mpSwapStreamHdl->Call( (void*) this ) : GRFMGR_AUTOSWAPSTREAM_NONE ); } // ----------------------------------------------------------------------------- // !!! to be removed sal_uLong GraphicObject::GetReleaseFromCache() const { return 0; } // ----------------------------------------------------------------------------- void GraphicObject::SetAttr( const GraphicAttr& rAttr ) { maAttr = rAttr; if( mpSimpleCache && ( mpSimpleCache->maAttr != rAttr ) ) delete mpSimpleCache, mpSimpleCache = NULL; } // ----------------------------------------------------------------------------- void GraphicObject::SetLink() { if( mpLink ) delete mpLink, mpLink = NULL; } // ----------------------------------------------------------------------------- void GraphicObject::SetLink( const String& rLink ) { delete mpLink, mpLink = new String( rLink ); } // ----------------------------------------------------------------------------- String GraphicObject::GetLink() const { if( mpLink ) return *mpLink; else return String(); } // ----------------------------------------------------------------------------- void GraphicObject::SetUserData() { if( mpUserData ) delete mpUserData, mpUserData = NULL; } // ----------------------------------------------------------------------------- void GraphicObject::SetUserData( const String& rUserData ) { delete mpUserData, mpUserData = new String( rUserData ); } // ----------------------------------------------------------------------------- String GraphicObject::GetUserData() const { if( mpUserData ) return *mpUserData; else return String(); } // ----------------------------------------------------------------------------- void GraphicObject::SetSwapStreamHdl() { if( mpSwapStreamHdl ) { delete mpSwapOutTimer, mpSwapOutTimer = NULL; delete mpSwapStreamHdl, mpSwapStreamHdl = NULL; } } // ----------------------------------------------------------------------------- void GraphicObject::SetSwapStreamHdl( const Link& rHdl, const sal_uLong nSwapOutTimeout ) { delete mpSwapStreamHdl, mpSwapStreamHdl = new Link( rHdl ); if( nSwapOutTimeout ) { if( !mpSwapOutTimer ) { mpSwapOutTimer = new Timer; mpSwapOutTimer->SetTimeoutHdl( LINK( this, GraphicObject, ImplAutoSwapOutHdl ) ); } mpSwapOutTimer->SetTimeout( nSwapOutTimeout ); mpSwapOutTimer->Start(); } else delete mpSwapOutTimer, mpSwapOutTimer = NULL; } // ----------------------------------------------------------------------------- Link GraphicObject::GetSwapStreamHdl() const { if( mpSwapStreamHdl ) return *mpSwapStreamHdl; else return Link(); } // ----------------------------------------------------------------------------- void GraphicObject::FireSwapInRequest() { ImplAutoSwapIn(); } // ----------------------------------------------------------------------------- void GraphicObject::FireSwapOutRequest() { ImplAutoSwapOutHdl( NULL ); } // ----------------------------------------------------------------------------- void GraphicObject::GraphicManagerDestroyed() { // we're alive, but our manager doesn't live anymore ==> connect to default manager mpMgr = NULL; ImplSetGraphicManager( NULL ); } // ----------------------------------------------------------------------------- void GraphicObject::SetGraphicManager( const GraphicManager& rMgr ) { ImplSetGraphicManager( &rMgr ); } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::IsCached( OutputDevice* pOut, const Point& rPt, const Size& rSz, const GraphicAttr* pAttr, sal_uLong nFlags ) const { sal_Bool bRet; if( nFlags & GRFMGR_DRAW_CACHED ) { // --> OD 2005-10-11 #i54875# - Consider cropped graphics. // Note: The graphic manager caches a cropped graphic with its // uncropped position and size. // bRet = mpMgr->IsInCache( pOut, rPt, rSz, *this, ( pAttr ? *pAttr : GetAttr() ) ); Point aPt( rPt ); Size aSz( rSz ); if ( pAttr->IsCropped() ) { PolyPolygon aClipPolyPoly; sal_Bool bRectClip; ImplGetCropParams( pOut, aPt, aSz, pAttr, aClipPolyPoly, bRectClip ); } bRet = mpMgr->IsInCache( pOut, aPt, aSz, *this, ( pAttr ? *pAttr : GetAttr() ) ); } else bRet = sal_False; return bRet; } // ----------------------------------------------------------------------------- void GraphicObject::ReleaseFromCache() { mpMgr->ReleaseFromCache( *this ); } // ----------------------------------------------------------------------------- void GraphicObject::SetAnimationNotifyHdl( const Link& rLink ) { maGraphic.SetAnimationNotifyHdl( rLink ); } // ----------------------------------------------------------------------------- List* GraphicObject::GetAnimationInfoList() const { return maGraphic.GetAnimationInfoList(); } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz, const GraphicAttr* pAttr, sal_uLong nFlags ) { GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() ); Point aPt( rPt ); Size aSz( rSz ); const sal_uInt32 nOldDrawMode = pOut->GetDrawMode(); sal_Bool bCropped = aAttr.IsCropped(); sal_Bool bCached = sal_False; sal_Bool bRet; // #i29534# Provide output rects for PDF writer Rectangle aCropRect; if( !( GRFMGR_DRAW_USE_DRAWMODE_SETTINGS & nFlags ) ) pOut->SetDrawMode( nOldDrawMode & ( ~( DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ) ) ); // mirrored horizontically if( aSz.Width() < 0L ) { aPt.X() += aSz.Width() + 1; aSz.Width() = -aSz.Width(); aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_HORZ ); } // mirrored vertically if( aSz.Height() < 0L ) { aPt.Y() += aSz.Height() + 1; aSz.Height() = -aSz.Height(); aAttr.SetMirrorFlags( aAttr.GetMirrorFlags() ^ BMP_MIRROR_VERT ); } if( bCropped ) { PolyPolygon aClipPolyPoly; sal_Bool bRectClip; const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip ); pOut->Push( PUSH_CLIPREGION ); if( bCrop ) { if( bRectClip ) { // #i29534# Store crop rect for later forwarding to // PDF writer aCropRect = aClipPolyPoly.GetBoundRect(); pOut->IntersectClipRegion( aCropRect ); } else { pOut->IntersectClipRegion( aClipPolyPoly ); } } } bRet = mpMgr->DrawObj( pOut, aPt, aSz, *this, aAttr, nFlags, bCached ); if( bCropped ) pOut->Pop(); pOut->SetDrawMode( nOldDrawMode ); // #i29534# Moved below OutDev restoration, to avoid multiple swap-ins // (code above needs to call GetGraphic twice) if( bCached ) { if( mpSwapOutTimer ) mpSwapOutTimer->Start(); else FireSwapOutRequest(); } return bRet; } // --> OD 2010-01-04 #i105243# sal_Bool GraphicObject::DrawWithPDFHandling( OutputDevice& rOutDev, const Point& rPt, const Size& rSz, const GraphicAttr* pGrfAttr, const sal_uLong nFlags ) { const GraphicAttr aGrfAttr( pGrfAttr ? *pGrfAttr : GetAttr() ); // Notify PDF writer about linked graphic (if any) sal_Bool bWritingPdfLinkedGraphic( sal_False ); Point aPt( rPt ); Size aSz( rSz ); Rectangle aCropRect; vcl::PDFExtOutDevData* pPDFExtOutDevData = dynamic_cast(rOutDev.GetExtOutDevData()); if( pPDFExtOutDevData ) { // only delegate image handling to PDF, if no special treatment is necessary if( GetGraphic().IsLink() && rSz.Width() > 0L && rSz.Height() > 0L && !aGrfAttr.IsSpecialDrawMode() && !aGrfAttr.IsMirrored() && !aGrfAttr.IsRotated() && !aGrfAttr.IsAdjusted() ) { bWritingPdfLinkedGraphic = true; if( aGrfAttr.IsCropped() ) { PolyPolygon aClipPolyPoly; sal_Bool bRectClip; const sal_Bool bCrop = ImplGetCropParams( &rOutDev, aPt, aSz, &aGrfAttr, aClipPolyPoly, bRectClip ); if ( bCrop && bRectClip ) { aCropRect = aClipPolyPoly.GetBoundRect(); } } pPDFExtOutDevData->BeginGroup(); } } sal_Bool bRet = Draw( &rOutDev, rPt, rSz, &aGrfAttr, nFlags ); // Notify PDF writer about linked graphic (if any) if( bWritingPdfLinkedGraphic ) { pPDFExtOutDevData->EndGroup( const_cast< Graphic& >(GetGraphic()), aGrfAttr.GetTransparency(), Rectangle( aPt, aSz ), aCropRect ); } return bRet; } // <-- // ----------------------------------------------------------------------------- sal_Bool GraphicObject::DrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSize, const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D ) { if( pOut == NULL || rSize.Width() == 0 || rSize.Height() == 0 ) return sal_False; const MapMode aOutMapMode( pOut->GetMapMode() ); const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() ); // #106258# Clamp size to 1 for zero values. This is okay, since // logical size of zero is handled above already const Size aOutTileSize( ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Width() ), ::std::max( 1L, pOut->LogicToPixel( rSize, aOutMapMode ).Height() ) ); //#i69780 clip final tile size to a sane max size while (((sal_Int64)rSize.Width() * nTileCacheSize1D) > SAL_MAX_UINT16) nTileCacheSize1D /= 2; while (((sal_Int64)rSize.Height() * nTileCacheSize1D) > SAL_MAX_UINT16) nTileCacheSize1D /= 2; return ImplDrawTiled( pOut, rArea, aOutTileSize, rOffset, pAttr, nFlags, nTileCacheSize1D ); } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::StartAnimation( OutputDevice* pOut, const Point& rPt, const Size& rSz, long nExtraData, const GraphicAttr* pAttr, sal_uLong /*nFlags*/, OutputDevice* pFirstFrameOutDev ) { sal_Bool bRet = sal_False; GetGraphic(); if( !IsSwappedOut() ) { const GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() ); if( mbAnimated ) { Point aPt( rPt ); Size aSz( rSz ); sal_Bool bCropped = aAttr.IsCropped(); if( bCropped ) { PolyPolygon aClipPolyPoly; sal_Bool bRectClip; const sal_Bool bCrop = ImplGetCropParams( pOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip ); pOut->Push( PUSH_CLIPREGION ); if( bCrop ) { if( bRectClip ) pOut->IntersectClipRegion( aClipPolyPoly.GetBoundRect() ); else pOut->IntersectClipRegion( aClipPolyPoly ); } } if( !mpSimpleCache || ( mpSimpleCache->maAttr != aAttr ) || pFirstFrameOutDev ) { if( mpSimpleCache ) delete mpSimpleCache; mpSimpleCache = new GrfSimpleCacheObj( GetTransformedGraphic( &aAttr ), aAttr ); mpSimpleCache->maGraphic.SetAnimationNotifyHdl( GetAnimationNotifyHdl() ); } mpSimpleCache->maGraphic.StartAnimation( pOut, aPt, aSz, nExtraData, pFirstFrameOutDev ); if( bCropped ) pOut->Pop(); bRet = sal_True; } else bRet = Draw( pOut, rPt, rSz, &aAttr, GRFMGR_DRAW_STANDARD ); } return bRet; } // ----------------------------------------------------------------------------- void GraphicObject::StopAnimation( OutputDevice* pOut, long nExtraData ) { if( mpSimpleCache ) mpSimpleCache->maGraphic.StopAnimation( pOut, nExtraData ); } // ----------------------------------------------------------------------------- const Graphic& GraphicObject::GetGraphic() const { if( mbAutoSwapped ) ( (GraphicObject*) this )->ImplAutoSwapIn(); return maGraphic; } // ----------------------------------------------------------------------------- void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pCopyObj ) { mpMgr->ImplUnregisterObj( *this ); if( mpSwapOutTimer ) mpSwapOutTimer->Stop(); maGraphic = rGraphic; mbAutoSwapped = sal_False; ImplAssignGraphicData(); delete mpLink, mpLink = NULL; delete mpSimpleCache, mpSimpleCache = NULL; mpMgr->ImplRegisterObj( *this, maGraphic, 0, pCopyObj); if( mpSwapOutTimer ) mpSwapOutTimer->Start(); // Handle evtl. needed AfterDataChanges ImplAfterDataChange(); } // ----------------------------------------------------------------------------- void GraphicObject::SetGraphic( const Graphic& rGraphic, const String& rLink ) { SetGraphic( rGraphic ); mpLink = new String( rLink ); } // ----------------------------------------------------------------------------- Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMode& rDestMap, const GraphicAttr& rAttr ) const { // #104550# Extracted from svx/source/svdraw/svdograf.cxx Graphic aTransGraphic( maGraphic ); const GraphicType eType = GetType(); const Size aSrcSize( aTransGraphic.GetPrefSize() ); // #104115# Convert the crop margins to graphic object mapmode const MapMode aMapGraph( aTransGraphic.GetPrefMapMode() ); const MapMode aMap100( MAP_100TH_MM ); Size aCropLeftTop; Size aCropRightBottom; if( GRAPHIC_GDIMETAFILE == eType ) { GDIMetaFile aMtf( aTransGraphic.GetGDIMetaFile() ); if( aMapGraph == MAP_PIXEL ) { // crops are in 1/100th mm -> to aMapGraph -> to MAP_PIXEL aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), aMap100); aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), aMap100); } else { // crops are in GraphicObject units -> to aMapGraph aCropLeftTop = OutputDevice::LogicToLogic( Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), aMap100, aMapGraph); aCropRightBottom = OutputDevice::LogicToLogic( Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), aMap100, aMapGraph); } // #104115# If the metafile is cropped, give it a special // treatment: clip against the remaining area, scale up such // that this area later fills the desired size, and move the // origin to the upper left edge of that area. if( rAttr.IsCropped() ) { const MapMode aMtfMapMode( aMtf.GetPrefMapMode() ); Rectangle aClipRect( aMtfMapMode.GetOrigin().X() + aCropLeftTop.Width(), aMtfMapMode.GetOrigin().Y() + aCropLeftTop.Height(), aMtfMapMode.GetOrigin().X() + aSrcSize.Width() - aCropRightBottom.Width(), aMtfMapMode.GetOrigin().Y() + aSrcSize.Height() - aCropRightBottom.Height() ); // #104115# To correctly crop rotated metafiles, clip by view rectangle aMtf.AddAction( new MetaISectRectClipRegionAction( aClipRect ), 0 ); // #104115# To crop the metafile, scale larger than the output rectangle aMtf.Scale( (double)rDestSize.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()), (double)rDestSize.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) ); // #104115# Adapt the pref size by hand (scale changes it // proportionally, but we want it to be smaller than the // former size, to crop the excess out) aMtf.SetPrefSize( Size( (long)((double)rDestSize.Width() * (1.0 + (aCropLeftTop.Width() + aCropRightBottom.Width()) / aSrcSize.Width()) + .5), (long)((double)rDestSize.Height() * (1.0 + (aCropLeftTop.Height() + aCropRightBottom.Height()) / aSrcSize.Height()) + .5) ) ); // #104115# Adapt the origin of the new mapmode, such that it // is shifted to the place where the cropped output starts Point aNewOrigin( (long)((double)aMtfMapMode.GetOrigin().X() + rDestSize.Width() * aCropLeftTop.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()) + .5), (long)((double)aMtfMapMode.GetOrigin().Y() + rDestSize.Height() * aCropLeftTop.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) + .5) ); MapMode aNewMap( rDestMap ); aNewMap.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin, aMtfMapMode, rDestMap) ); aMtf.SetPrefMapMode( aNewMap ); } else { aMtf.Scale( Fraction( rDestSize.Width(), aSrcSize.Width() ), Fraction( rDestSize.Height(), aSrcSize.Height() ) ); aMtf.SetPrefMapMode( rDestMap ); } aTransGraphic = aMtf; } else if( GRAPHIC_BITMAP == eType ) { BitmapEx aBitmapEx( aTransGraphic.GetBitmapEx() ); Rectangle aCropRect; // convert crops to pixel if(rAttr.IsCropped()) { if( aMapGraph == MAP_PIXEL ) { // crops are in 1/100th mm -> to MAP_PIXEL aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), aMap100); aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), aMap100); } else { // crops are in GraphicObject units -> to MAP_PIXEL aCropLeftTop = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()), aMapGraph); aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel( Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()), aMapGraph); } // convert from prefmapmode to pixel Size aSrcSizePixel( Application::GetDefaultDevice()->LogicToPixel( aSrcSize, aMapGraph)); if(rAttr.IsCropped() && (aSrcSizePixel.Width() != aBitmapEx.GetSizePixel().Width() || aSrcSizePixel.Height() != aBitmapEx.GetSizePixel().Height()) && aSrcSizePixel.Width()) { // the size in pixels calculated from Graphic's internal MapMode (aTransGraphic.GetPrefMapMode()) // and it's internal size (aTransGraphic.GetPrefSize()) is different from it's real pixel size. // This can be interpreted as this values to be set wrong, but needs to be corrected since e.g. // existing cropping is calculated based on this logic values already. // aBitmapEx.Scale(aSrcSizePixel); // another possibility is to adapt the values created so far with a factor; this // will keep the original Bitmap untouched and thus quality will not change // caution: convert to double first, else pretty big errors may occurr const double fFactorX((double)aBitmapEx.GetSizePixel().Width() / aSrcSizePixel.Width()); const double fFactorY((double)aBitmapEx.GetSizePixel().Height() / aSrcSizePixel.Height()); aCropLeftTop.Width() = basegfx::fround(aCropLeftTop.Width() * fFactorX); aCropLeftTop.Height() = basegfx::fround(aCropLeftTop.Height() * fFactorY); aCropRightBottom.Width() = basegfx::fround(aCropRightBottom.Width() * fFactorX); aCropRightBottom.Height() = basegfx::fround(aCropRightBottom.Height() * fFactorY); aSrcSizePixel = aBitmapEx.GetSizePixel(); } // setup crop rectangle in pixel aCropRect = Rectangle( aCropLeftTop.Width(), aCropLeftTop.Height(), aSrcSizePixel.Width() - aCropRightBottom.Width(), aSrcSizePixel.Height() - aCropRightBottom.Height() ); } // #105641# Also crop animations if( aTransGraphic.IsAnimated() ) { sal_uInt16 nFrame; Animation aAnim( aTransGraphic.GetAnimation() ); for( nFrame=0; nFramemaGraphic.ResetAnimationLoopCount(); } } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::SwapOut() { sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut() : sal_False ); if( bRet && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedOut( *this ); return bRet; } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::SwapOut( SvStream* pOStm ) { sal_Bool bRet = ( !mbAutoSwapped ? maGraphic.SwapOut( pOStm ) : sal_False ); if( bRet && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedOut( *this ); return bRet; } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::SwapIn() { sal_Bool bRet; if( mbAutoSwapped ) { ImplAutoSwapIn(); bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) { bRet = sal_True; } else { bRet = maGraphic.SwapIn(); if( bRet && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedIn( *this ); } if( bRet ) { ImplAssignGraphicData(); // Handle evtl. needed AfterDataChanges ImplAfterDataChange(); } return bRet; } // ----------------------------------------------------------------------------- sal_Bool GraphicObject::SwapIn( SvStream* pIStm ) { sal_Bool bRet; if( mbAutoSwapped ) { ImplAutoSwapIn(); bRet = sal_True; } else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) ) { bRet = sal_True; } else { bRet = maGraphic.SwapIn( pIStm ); if( bRet && mpMgr ) mpMgr->ImplGraphicObjectWasSwappedIn( *this ); } if( bRet ) { ImplAssignGraphicData(); // ImplAfterDataChange(); } return bRet; } // ----------------------------------------------------------------------------- void GraphicObject::SetSwapState() { if( !IsSwappedOut() ) { mbAutoSwapped = sal_True; if( mpMgr ) mpMgr->ImplGraphicObjectWasSwappedOut( *this ); } } // ----------------------------------------------------------------------------- IMPL_LINK( GraphicObject, ImplAutoSwapOutHdl, void*, EMPTYARG ) { if( !IsSwappedOut() ) { mbIsInSwapOut = sal_True; SvStream* pStream = GetSwapStream(); if( GRFMGR_AUTOSWAPSTREAM_NONE != pStream ) { if( GRFMGR_AUTOSWAPSTREAM_LINK == pStream ) mbAutoSwapped = SwapOut( NULL ); else { if( GRFMGR_AUTOSWAPSTREAM_TEMP == pStream ) mbAutoSwapped = SwapOut(); else { mbAutoSwapped = SwapOut( pStream ); delete pStream; } } } mbIsInSwapOut = sal_False; } if( mpSwapOutTimer ) mpSwapOutTimer->Start(); return 0L; } // ------------------------------------------------------------------------ SvStream& operator>>( SvStream& rIStm, GraphicObject& rGraphicObj ) { VersionCompat aCompat( rIStm, STREAM_READ ); Graphic aGraphic; GraphicAttr aAttr; ByteString aLink; sal_Bool bLink; rIStm >> aGraphic >> aAttr >> bLink; rGraphicObj.SetGraphic( aGraphic ); rGraphicObj.SetAttr( aAttr ); if( bLink ) { rIStm >> aLink; rGraphicObj.SetLink( UniString( aLink, RTL_TEXTENCODING_UTF8 ) ); } else rGraphicObj.SetLink(); rGraphicObj.SetSwapStreamHdl(); return rIStm; } // ------------------------------------------------------------------------ SvStream& operator<<( SvStream& rOStm, const GraphicObject& rGraphicObj ) { VersionCompat aCompat( rOStm, STREAM_WRITE, 1 ); const sal_Bool bLink = rGraphicObj.HasLink(); rOStm << rGraphicObj.GetGraphic() << rGraphicObj.GetAttr() << bLink; if( bLink ) rOStm << ByteString( rGraphicObj.GetLink(), RTL_TEXTENCODING_UTF8 ); return rOStm; } #define UNO_NAME_GRAPHOBJ_URLPREFIX "vnd.sun.star.GraphicObject:" GraphicObject GraphicObject::CreateGraphicObjectFromURL( const ::rtl::OUString &rURL ) { const String aURL( rURL ), aPrefix( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_GRAPHOBJ_URLPREFIX) ); if( aURL.Search( aPrefix ) == 0 ) { // graphic manager url ByteString aUniqueID( String(rURL.copy( sizeof( UNO_NAME_GRAPHOBJ_URLPREFIX ) - 1 )), RTL_TEXTENCODING_UTF8 ); return GraphicObject( aUniqueID ); } else { Graphic aGraphic; if ( aURL.Len() ) { SvStream* pStream = utl::UcbStreamHelper::CreateStream( aURL, STREAM_READ ); if( pStream ) GraphicConverter::Import( *pStream, aGraphic ); } return GraphicObject( aGraphic ); } } // calculate scalings between real image size and logic object size. This // is necessary since the crop values are relative to original bitmap size basegfx::B2DVector GraphicObject::calculateCropScaling( double fWidth, double fHeight, double fLeftCrop, double fTopCrop, double fRightCrop, double fBottomCrop) const { const MapMode aMapMode100thmm(MAP_100TH_MM); Size aBitmapSize(GetPrefSize()); double fFactorX(1.0); double fFactorY(1.0); if(MAP_PIXEL == GetPrefMapMode().GetMapUnit()) { aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm); } else { aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, GetPrefMapMode(), aMapMode100thmm); } const double fDivX(aBitmapSize.Width() - fLeftCrop - fRightCrop); const double fDivY(aBitmapSize.Height() - fTopCrop - fBottomCrop); if(!basegfx::fTools::equalZero(fDivX)) { fFactorX = fabs(fWidth) / fDivX; } if(!basegfx::fTools::equalZero(fDivY)) { fFactorY = fabs(fHeight) / fDivY; } return basegfx::B2DVector(fFactorX,fFactorY); } // ------------------------------------------------------------------------ // restart SwapOut timer void GraphicObject::restartSwapOutTimer() const { if( mpSwapOutTimer && mpSwapOutTimer->IsActive() ) { mpSwapOutTimer->Start(); } } // eof