1*70f497fbSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*70f497fbSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*70f497fbSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*70f497fbSAndrew Rist * distributed with this work for additional information 6*70f497fbSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*70f497fbSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*70f497fbSAndrew Rist * "License"); you may not use this file except in compliance 9*70f497fbSAndrew Rist * with the License. You may obtain a copy of the License at 10*70f497fbSAndrew Rist * 11*70f497fbSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*70f497fbSAndrew Rist * 13*70f497fbSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*70f497fbSAndrew Rist * software distributed under the License is distributed on an 15*70f497fbSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*70f497fbSAndrew Rist * KIND, either express or implied. See the License for the 17*70f497fbSAndrew Rist * specific language governing permissions and limitations 18*70f497fbSAndrew Rist * under the License. 19*70f497fbSAndrew Rist * 20*70f497fbSAndrew Rist *************************************************************/ 21*70f497fbSAndrew Rist 22*70f497fbSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir // must be first 28cdf0e10cSrcweir #include <canvas/debug.hxx> 29cdf0e10cSrcweir #include <tools/diagnose_ex.h> 30cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include <rtl/logfile.hxx> 33cdf0e10cSrcweir #include <osl/diagnose.hxx> 34cdf0e10cSrcweir #include <com/sun/star/awt/Rectangle.hpp> 35cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 36cdf0e10cSrcweir #include <com/sun/star/awt/FontWeight.hpp> 37cdf0e10cSrcweir #include <comphelper/anytostring.hxx> 38cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx> 39cdf0e10cSrcweir 40cdf0e10cSrcweir #include <vcl/metaact.hxx> 41cdf0e10cSrcweir #include <vcl/gdimtf.hxx> 42cdf0e10cSrcweir #include <vcl/wrkwin.hxx> 43cdf0e10cSrcweir 44cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 45cdf0e10cSrcweir #include <basegfx/range/rangeexpander.hxx> 46cdf0e10cSrcweir 47cdf0e10cSrcweir #include <rtl/math.hxx> 48cdf0e10cSrcweir 49cdf0e10cSrcweir #include <com/sun/star/drawing/TextAnimationKind.hpp> 50cdf0e10cSrcweir 51cdf0e10cSrcweir #include <vcl/svapp.hxx> 52cdf0e10cSrcweir #include <vcl/window.hxx> 53cdf0e10cSrcweir #include <tools/stream.hxx> 54cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp> 55cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 56cdf0e10cSrcweir #include <com/sun/star/datatransfer/XTransferable.hpp> 57cdf0e10cSrcweir 58cdf0e10cSrcweir #include <comphelper/scopeguard.hxx> 59cdf0e10cSrcweir #include <canvas/canvastools.hxx> 60cdf0e10cSrcweir 61cdf0e10cSrcweir #include <cmath> // for trigonometry and fabs 62cdf0e10cSrcweir #include <algorithm> 63cdf0e10cSrcweir #include <functional> 64cdf0e10cSrcweir #include <limits> 65cdf0e10cSrcweir 66cdf0e10cSrcweir #include "drawshapesubsetting.hxx" 67cdf0e10cSrcweir #include "drawshape.hxx" 68cdf0e10cSrcweir #include "eventqueue.hxx" 69cdf0e10cSrcweir #include "wakeupevent.hxx" 70cdf0e10cSrcweir #include "subsettableshapemanager.hxx" 71cdf0e10cSrcweir #include "intrinsicanimationactivity.hxx" 72cdf0e10cSrcweir #include "slideshowexceptions.hxx" 73cdf0e10cSrcweir #include "tools.hxx" 74cdf0e10cSrcweir #include "gdimtftools.hxx" 75cdf0e10cSrcweir #include "drawinglayeranimation.hxx" 76cdf0e10cSrcweir 77cdf0e10cSrcweir #include <boost/bind.hpp> 78cdf0e10cSrcweir #include <math.h> 79cdf0e10cSrcweir 80cdf0e10cSrcweir using namespace ::com::sun::star; 81cdf0e10cSrcweir 82cdf0e10cSrcweir 83cdf0e10cSrcweir namespace slideshow 84cdf0e10cSrcweir { 85cdf0e10cSrcweir namespace internal 86cdf0e10cSrcweir { 87cdf0e10cSrcweir //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% 88cdf0e10cSrcweir //metafiles are resolution dependent when bitmaps are contained with is the case for 3D scenes for example 89cdf0e10cSrcweir //in addition a chart has resolution dependent content as it might skip points that are not visible for a given resolution (this is done for performance reasons) 90cdf0e10cSrcweir bool local_getMetafileForChart( const uno::Reference< lang::XComponent >& xSource, 91cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 92cdf0e10cSrcweir GDIMetaFile& rMtf ) 93cdf0e10cSrcweir { 94cdf0e10cSrcweir //get the chart model 95cdf0e10cSrcweir uno::Reference< beans::XPropertySet > xPropSet( xSource, uno::UNO_QUERY ); 96cdf0e10cSrcweir uno::Reference< frame::XModel > xChartModel; 97cdf0e10cSrcweir getPropertyValue( xChartModel, xPropSet, OUSTR("Model")); 98cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xFact( xChartModel, uno::UNO_QUERY ); 99cdf0e10cSrcweir OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" ); 100cdf0e10cSrcweir if(!xFact.is()) 101cdf0e10cSrcweir return false; 102cdf0e10cSrcweir 103cdf0e10cSrcweir //get the chart view 104cdf0e10cSrcweir uno::Reference< datatransfer::XTransferable > xChartViewTransferable( 105cdf0e10cSrcweir xFact->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.ChartView" ) ) ), uno::UNO_QUERY ); 106cdf0e10cSrcweir uno::Reference< beans::XPropertySet > xChartViewProp( xChartViewTransferable, uno::UNO_QUERY ); 107cdf0e10cSrcweir OSL_ENSURE( xChartViewProp.is(), "Chart cannot be painted pretty!\n" ); 108cdf0e10cSrcweir if( !xChartViewProp.is() ) 109cdf0e10cSrcweir return false; 110cdf0e10cSrcweir 111cdf0e10cSrcweir //estimate zoom and resolution (this is only a workaround, correct would be to know and use the exact zoom and resoltion during slideshow display) 112cdf0e10cSrcweir sal_Int32 nScaleXNumerator = 100;//zoom factor -> exact values are important for the quality of the created bitmap especially for 3D charts 113cdf0e10cSrcweir sal_Int32 nScaleYNumerator = 100; 114cdf0e10cSrcweir sal_Int32 nScaleXDenominator = 100; 115cdf0e10cSrcweir sal_Int32 nScaleYDenominator = 100; 116cdf0e10cSrcweir awt::Size aPixelPerChart( 1000, 1000 );//when data points happen to be on the same pixel as their predecessor no shape is created to safe performance 117cdf0e10cSrcweir 118cdf0e10cSrcweir Window* pActiveTopWindow( Application::GetActiveTopWindow() ); 119cdf0e10cSrcweir WorkWindow* pWorkWindow( dynamic_cast<WorkWindow*>(pActiveTopWindow)); 120cdf0e10cSrcweir if( pWorkWindow && pWorkWindow->IsPresentationMode() ) 121cdf0e10cSrcweir { 122cdf0e10cSrcweir Size aPixScreenSize( pActiveTopWindow->GetOutputSizePixel() ); 123cdf0e10cSrcweir aPixelPerChart = awt::Size( aPixScreenSize.getWidth(), aPixScreenSize.getHeight() );//this is still to much (but costs only seldom performance), correct would be pixel per chart object 124cdf0e10cSrcweir 125cdf0e10cSrcweir uno::Reference< beans::XPropertySet > xPageProp( xContainingPage, uno::UNO_QUERY ); 126cdf0e10cSrcweir sal_Int32 nLogicPageWidth=1; 127cdf0e10cSrcweir sal_Int32 nLogicPageHeight=1; 128cdf0e10cSrcweir if( getPropertyValue( nLogicPageWidth, xPageProp, OUSTR("Width")) && 129cdf0e10cSrcweir getPropertyValue( nLogicPageHeight, xPageProp, OUSTR("Height")) ) 130cdf0e10cSrcweir { 131cdf0e10cSrcweir Size aLogicScreenSize( pActiveTopWindow->PixelToLogic( aPixScreenSize, MAP_100TH_MM ) ); 132cdf0e10cSrcweir nScaleXNumerator = aLogicScreenSize.getWidth(); 133cdf0e10cSrcweir nScaleYNumerator = aLogicScreenSize.getHeight(); 134cdf0e10cSrcweir nScaleXDenominator = nLogicPageWidth; 135cdf0e10cSrcweir nScaleYDenominator = nLogicPageHeight; 136cdf0e10cSrcweir } 137cdf0e10cSrcweir } 138cdf0e10cSrcweir else 139cdf0e10cSrcweir { 140cdf0e10cSrcweir long nMaxPixWidth = 0; 141cdf0e10cSrcweir long nMaxPixHeight = 0; 142cdf0e10cSrcweir unsigned int nScreenCount( Application::GetScreenCount() ); 143cdf0e10cSrcweir for( unsigned int nScreen=0; nScreen<nScreenCount; nScreen++ ) 144cdf0e10cSrcweir { 145cdf0e10cSrcweir Rectangle aCurScreenRect( Application::GetScreenPosSizePixel( nScreen ) ); 146cdf0e10cSrcweir if( aCurScreenRect.GetWidth() > nMaxPixWidth ) 147cdf0e10cSrcweir nMaxPixWidth = aCurScreenRect.GetWidth(); 148cdf0e10cSrcweir if( aCurScreenRect.GetHeight() > nMaxPixHeight ) 149cdf0e10cSrcweir nMaxPixHeight = aCurScreenRect.GetHeight(); 150cdf0e10cSrcweir } 151cdf0e10cSrcweir if(nMaxPixWidth>1 && nMaxPixHeight>1) 152cdf0e10cSrcweir aPixelPerChart = awt::Size( nMaxPixWidth, nMaxPixHeight );//this is still to much (but costs only seldom performance), correct would be pixel per chart object 153cdf0e10cSrcweir } 154cdf0e10cSrcweir 155cdf0e10cSrcweir try 156cdf0e10cSrcweir { 157cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aZoomFactors(4); 158cdf0e10cSrcweir aZoomFactors[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXNumerator") ); 159cdf0e10cSrcweir aZoomFactors[0].Value = uno::makeAny( nScaleXNumerator ); 160cdf0e10cSrcweir aZoomFactors[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXDenominator") ); 161cdf0e10cSrcweir aZoomFactors[1].Value = uno::makeAny( nScaleXDenominator ); 162cdf0e10cSrcweir aZoomFactors[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYNumerator") ); 163cdf0e10cSrcweir aZoomFactors[2].Value = uno::makeAny( nScaleYNumerator ); 164cdf0e10cSrcweir aZoomFactors[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYDenominator") ); 165cdf0e10cSrcweir aZoomFactors[3].Value = uno::makeAny( nScaleYDenominator ); 166cdf0e10cSrcweir 167cdf0e10cSrcweir xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZoomFactors") ), uno::makeAny( aZoomFactors )); 168cdf0e10cSrcweir xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Resolution") ), uno::makeAny( aPixelPerChart )); 169cdf0e10cSrcweir } 170cdf0e10cSrcweir catch (uno::Exception &) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir OSL_ENSURE( false, rtl::OUStringToOString( 173cdf0e10cSrcweir comphelper::anyToString( 174cdf0e10cSrcweir cppu::getCaughtException() ), 175cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 176cdf0e10cSrcweir } 177cdf0e10cSrcweir 178cdf0e10cSrcweir //get a metafile from the prepared chart view 179cdf0e10cSrcweir datatransfer::DataFlavor aDataFlavor( 180cdf0e10cSrcweir ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"") ), 181cdf0e10cSrcweir ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ), 182cdf0e10cSrcweir ::getCppuType( (const uno::Sequence< sal_Int8 >*) 0 ) ); 183cdf0e10cSrcweir uno::Any aData( xChartViewTransferable->getTransferData( aDataFlavor ) ); 184cdf0e10cSrcweir uno::Sequence< sal_Int8 > aSeq; 185cdf0e10cSrcweir if( aData >>= aSeq ) 186cdf0e10cSrcweir { 187cdf0e10cSrcweir ::std::auto_ptr< SvMemoryStream > pSrcStm( new SvMemoryStream( (char*) aSeq.getConstArray(), aSeq.getLength(), STREAM_WRITE | STREAM_TRUNC ) ); 188cdf0e10cSrcweir *(pSrcStm.get() ) >> rMtf; 189cdf0e10cSrcweir return true; 190cdf0e10cSrcweir } 191cdf0e10cSrcweir return false; 192cdf0e10cSrcweir } 193cdf0e10cSrcweir 194cdf0e10cSrcweir //same as getMetafile with an exception for charts 195cdf0e10cSrcweir //for charts a metafile with a higher resolution is created, because charts have resolution dependent content 196cdf0e10cSrcweir bool local_getMetaFile_WithSpecialChartHandling( const uno::Reference< lang::XComponent >& xSource, 197cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 198cdf0e10cSrcweir GDIMetaFile& rMtf, 199cdf0e10cSrcweir int mtfLoadFlags, 200cdf0e10cSrcweir const uno::Reference< uno::XComponentContext >& rxContext ) 201cdf0e10cSrcweir { 202cdf0e10cSrcweir uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY ); 203cdf0e10cSrcweir rtl::OUString sCLSID; 204cdf0e10cSrcweir getPropertyValue( sCLSID, xProp, OUSTR("CLSID")); 205cdf0e10cSrcweir if( sCLSID.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("12DCAE26-281F-416F-a234-c3086127382e")) && local_getMetafileForChart( xSource, xContainingPage, rMtf ) ) 206cdf0e10cSrcweir return true; 207cdf0e10cSrcweir return getMetaFile( xSource, xContainingPage, rMtf, mtfLoadFlags, rxContext ); 208cdf0e10cSrcweir } 209cdf0e10cSrcweir 210cdf0e10cSrcweir 211cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 212cdf0e10cSrcweir // 213cdf0e10cSrcweir // Private methods 214cdf0e10cSrcweir // 215cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 216cdf0e10cSrcweir 217cdf0e10cSrcweir GDIMetaFileSharedPtr DrawShape::forceScrollTextMetaFile() 218cdf0e10cSrcweir { 219cdf0e10cSrcweir if ((mnCurrMtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != MTF_LOAD_SCROLL_TEXT_MTF) 220cdf0e10cSrcweir { 221cdf0e10cSrcweir // reload with added flags: 222cdf0e10cSrcweir mpCurrMtf.reset( new GDIMetaFile ); 223cdf0e10cSrcweir mnCurrMtfLoadFlags |= MTF_LOAD_SCROLL_TEXT_MTF; 224cdf0e10cSrcweir local_getMetaFile_WithSpecialChartHandling( 225cdf0e10cSrcweir uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY), 226cdf0e10cSrcweir mxPage, *mpCurrMtf, mnCurrMtfLoadFlags, 227cdf0e10cSrcweir mxComponentContext ); 228cdf0e10cSrcweir 229cdf0e10cSrcweir // TODO(F1): Currently, the scroll metafile will 230cdf0e10cSrcweir // never contain any verbose text comments. Thus, 231cdf0e10cSrcweir // can only display the full mtf content, no 232cdf0e10cSrcweir // subsets. 233cdf0e10cSrcweir maSubsetting.reset( mpCurrMtf ); 234cdf0e10cSrcweir 235cdf0e10cSrcweir // adapt maBounds. the requested scroll text metafile 236cdf0e10cSrcweir // will typically have dimension different from the 237cdf0e10cSrcweir // actual shape 238cdf0e10cSrcweir ::basegfx::B2DRectangle aScrollRect, aPaintRect; 239cdf0e10cSrcweir ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect, 240cdf0e10cSrcweir aPaintRect, 241cdf0e10cSrcweir mpCurrMtf ), 242cdf0e10cSrcweir "DrawShape::forceScrollTextMetaFile(): Could " 243cdf0e10cSrcweir "not extract scroll anim rectangles from mtf" ); 244cdf0e10cSrcweir 245cdf0e10cSrcweir // take the larger one of the two rectangles (that 246cdf0e10cSrcweir // should be the bound rect of the retrieved 247cdf0e10cSrcweir // metafile) 248cdf0e10cSrcweir if( aScrollRect.isInside( aPaintRect ) ) 249cdf0e10cSrcweir maBounds = aScrollRect; 250cdf0e10cSrcweir else 251cdf0e10cSrcweir maBounds = aPaintRect; 252cdf0e10cSrcweir } 253cdf0e10cSrcweir return mpCurrMtf; 254cdf0e10cSrcweir } 255cdf0e10cSrcweir 256cdf0e10cSrcweir void DrawShape::updateStateIds() const 257cdf0e10cSrcweir { 258cdf0e10cSrcweir // Update the states, we've just redrawn or created a new 259cdf0e10cSrcweir // attribute layer. 260cdf0e10cSrcweir if( mpAttributeLayer ) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir mnAttributeTransformationState = mpAttributeLayer->getTransformationState(); 263cdf0e10cSrcweir mnAttributeClipState = mpAttributeLayer->getClipState(); 264cdf0e10cSrcweir mnAttributeAlphaState = mpAttributeLayer->getAlphaState(); 265cdf0e10cSrcweir mnAttributePositionState = mpAttributeLayer->getPositionState(); 266cdf0e10cSrcweir mnAttributeContentState = mpAttributeLayer->getContentState(); 267cdf0e10cSrcweir mnAttributeVisibilityState = mpAttributeLayer->getVisibilityState(); 268cdf0e10cSrcweir } 269cdf0e10cSrcweir } 270cdf0e10cSrcweir 271cdf0e10cSrcweir void DrawShape::ensureVerboseMtfComments() const 272cdf0e10cSrcweir { 273cdf0e10cSrcweir // TODO(F1): Text effects don't currently work for drawing 274cdf0e10cSrcweir // layer animations. 275cdf0e10cSrcweir 276cdf0e10cSrcweir // only touch mpCurrMtf, if we're not a DrawingLayer 277cdf0e10cSrcweir // animation. 278cdf0e10cSrcweir if( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) == 0 && 279cdf0e10cSrcweir maAnimationFrames.empty() ) 280cdf0e10cSrcweir { 281cdf0e10cSrcweir ENSURE_OR_THROW( !maSubsetting.hasSubsetShapes(), 282cdf0e10cSrcweir "DrawShape::ensureVerboseMtfComments(): reloading the metafile " 283cdf0e10cSrcweir "with active child subsets will wreak havoc on the view!" ); 284cdf0e10cSrcweir ENSURE_OR_THROW( maSubsetting.getSubsetNode().isEmpty(), 285cdf0e10cSrcweir "DrawShape::ensureVerboseMtfComments(): reloading the metafile " 286cdf0e10cSrcweir "for an ALREADY SUBSETTED shape is not possible!" ); 287cdf0e10cSrcweir 288cdf0e10cSrcweir // re-fetch metafile with comments 289cdf0e10cSrcweir // note that, in case of shapes without text, the new 290cdf0e10cSrcweir // metafile might still not provide any useful 291cdf0e10cSrcweir // subsetting information! 292cdf0e10cSrcweir mpCurrMtf.reset( new GDIMetaFile ); 293cdf0e10cSrcweir mnCurrMtfLoadFlags |= MTF_LOAD_VERBOSE_COMMENTS; 294cdf0e10cSrcweir local_getMetaFile_WithSpecialChartHandling( 295cdf0e10cSrcweir uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY), 296cdf0e10cSrcweir mxPage, *mpCurrMtf, mnCurrMtfLoadFlags, 297cdf0e10cSrcweir mxComponentContext ); 298cdf0e10cSrcweir 299cdf0e10cSrcweir maSubsetting.reset( maSubsetting.getSubsetNode(), 300cdf0e10cSrcweir mpCurrMtf ); 301cdf0e10cSrcweir } 302cdf0e10cSrcweir } 303cdf0e10cSrcweir 304cdf0e10cSrcweir ViewShape::RenderArgs DrawShape::getViewRenderArgs() const 305cdf0e10cSrcweir { 306cdf0e10cSrcweir return ViewShape::RenderArgs( 307cdf0e10cSrcweir maBounds, 308cdf0e10cSrcweir getUpdateArea(), 309cdf0e10cSrcweir getBounds(), 310cdf0e10cSrcweir getActualUnitShapeBounds(), 311cdf0e10cSrcweir mpAttributeLayer, 312cdf0e10cSrcweir maSubsetting.getActiveSubsets(), 313cdf0e10cSrcweir mnPriority); 314cdf0e10cSrcweir } 315cdf0e10cSrcweir 316cdf0e10cSrcweir bool DrawShape::implRender( int nUpdateFlags ) const 317cdf0e10cSrcweir { 318cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShape::implRender()" ); 319cdf0e10cSrcweir RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::DrawShape: 0x%X", this ); 320cdf0e10cSrcweir 321cdf0e10cSrcweir // will perform the update now, clear update-enforcing 322cdf0e10cSrcweir // flags 323cdf0e10cSrcweir mbForceUpdate = false; 324cdf0e10cSrcweir mbAttributeLayerRevoked = false; 325cdf0e10cSrcweir 326cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( !maViewShapes.empty(), 327cdf0e10cSrcweir "DrawShape::implRender(): render called on DrawShape without views" ); 328cdf0e10cSrcweir 329cdf0e10cSrcweir if( maBounds.isEmpty() ) 330cdf0e10cSrcweir { 331cdf0e10cSrcweir // zero-sized shapes are effectively invisible, 332cdf0e10cSrcweir // thus, we save us the rendering... 333cdf0e10cSrcweir return true; 334cdf0e10cSrcweir } 335cdf0e10cSrcweir 336cdf0e10cSrcweir // redraw all view shapes, by calling their update() method 337cdf0e10cSrcweir if( ::std::count_if( maViewShapes.begin(), 338cdf0e10cSrcweir maViewShapes.end(), 339cdf0e10cSrcweir ::boost::bind<bool>( 340cdf0e10cSrcweir ::boost::mem_fn( &ViewShape::update ), // though _theoretically_, 341cdf0e10cSrcweir // bind should eat this even 342cdf0e10cSrcweir // with _1 being a shared_ptr, 343cdf0e10cSrcweir // it does _not_ for MSVC without 344cdf0e10cSrcweir // the extra mem_fn. WTF. 345cdf0e10cSrcweir _1, 346cdf0e10cSrcweir ::boost::cref( mpCurrMtf ), 347cdf0e10cSrcweir ::boost::cref( 348cdf0e10cSrcweir getViewRenderArgs() ), 349cdf0e10cSrcweir nUpdateFlags, 350cdf0e10cSrcweir isVisible() ) ) 351cdf0e10cSrcweir != static_cast<ViewShapeVector::difference_type>(maViewShapes.size()) ) 352cdf0e10cSrcweir { 353cdf0e10cSrcweir // at least one of the ViewShape::update() calls did return 354cdf0e10cSrcweir // false - update failed on at least one ViewLayer 355cdf0e10cSrcweir return false; 356cdf0e10cSrcweir } 357cdf0e10cSrcweir 358cdf0e10cSrcweir // successfully redrawn - update state IDs to detect next changes 359cdf0e10cSrcweir updateStateIds(); 360cdf0e10cSrcweir 361cdf0e10cSrcweir return true; 362cdf0e10cSrcweir } 363cdf0e10cSrcweir 364cdf0e10cSrcweir int DrawShape::getUpdateFlags() const 365cdf0e10cSrcweir { 366cdf0e10cSrcweir // default: update nothing, unless ShapeAttributeStack 367cdf0e10cSrcweir // tells us below, or if the attribute layer was revoked 368cdf0e10cSrcweir int nUpdateFlags(ViewShape::NONE); 369cdf0e10cSrcweir 370cdf0e10cSrcweir // possibly the whole shape content changed 371cdf0e10cSrcweir if( mbAttributeLayerRevoked ) 372cdf0e10cSrcweir nUpdateFlags = ViewShape::CONTENT; 373cdf0e10cSrcweir 374cdf0e10cSrcweir 375cdf0e10cSrcweir // determine what has to be updated 376cdf0e10cSrcweir // -------------------------------- 377cdf0e10cSrcweir 378cdf0e10cSrcweir // do we have an attribute layer? 379cdf0e10cSrcweir if( mpAttributeLayer ) 380cdf0e10cSrcweir { 381cdf0e10cSrcweir // Prevent nUpdateFlags to be modified when the shape is not 382cdf0e10cSrcweir // visible, except when it just was hidden. 383cdf0e10cSrcweir if (mpAttributeLayer->getVisibility() 384cdf0e10cSrcweir || mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState ) 385cdf0e10cSrcweir { 386cdf0e10cSrcweir if (mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState ) 387cdf0e10cSrcweir { 388cdf0e10cSrcweir // Change of the visibility state is mapped to 389cdf0e10cSrcweir // content change because when the visibility 390cdf0e10cSrcweir // changes then usually a sprite is shown or hidden 391cdf0e10cSrcweir // and the background under has to be painted once. 392cdf0e10cSrcweir nUpdateFlags |= ViewShape::CONTENT; 393cdf0e10cSrcweir } 394cdf0e10cSrcweir 395cdf0e10cSrcweir // TODO(P1): This can be done without conditional branching. 396cdf0e10cSrcweir // See HAKMEM. 397cdf0e10cSrcweir if( mpAttributeLayer->getPositionState() != mnAttributePositionState ) 398cdf0e10cSrcweir { 399cdf0e10cSrcweir nUpdateFlags |= ViewShape::POSITION; 400cdf0e10cSrcweir } 401cdf0e10cSrcweir if( mpAttributeLayer->getAlphaState() != mnAttributeAlphaState ) 402cdf0e10cSrcweir { 403cdf0e10cSrcweir nUpdateFlags |= ViewShape::ALPHA; 404cdf0e10cSrcweir } 405cdf0e10cSrcweir if( mpAttributeLayer->getClipState() != mnAttributeClipState ) 406cdf0e10cSrcweir { 407cdf0e10cSrcweir nUpdateFlags |= ViewShape::CLIP; 408cdf0e10cSrcweir } 409cdf0e10cSrcweir if( mpAttributeLayer->getTransformationState() != mnAttributeTransformationState ) 410cdf0e10cSrcweir { 411cdf0e10cSrcweir nUpdateFlags |= ViewShape::TRANSFORMATION; 412cdf0e10cSrcweir } 413cdf0e10cSrcweir if( mpAttributeLayer->getContentState() != mnAttributeContentState ) 414cdf0e10cSrcweir { 415cdf0e10cSrcweir nUpdateFlags |= ViewShape::CONTENT; 416cdf0e10cSrcweir } 417cdf0e10cSrcweir } 418cdf0e10cSrcweir } 419cdf0e10cSrcweir 420cdf0e10cSrcweir return nUpdateFlags; 421cdf0e10cSrcweir } 422cdf0e10cSrcweir 423cdf0e10cSrcweir ::basegfx::B2DRectangle DrawShape::getActualUnitShapeBounds() const 424cdf0e10cSrcweir { 425cdf0e10cSrcweir ENSURE_OR_THROW( !maViewShapes.empty(), 426cdf0e10cSrcweir "DrawShape::getActualUnitShapeBounds(): called on DrawShape without views" ); 427cdf0e10cSrcweir 428cdf0e10cSrcweir const VectorOfDocTreeNodes& rSubsets( 429cdf0e10cSrcweir maSubsetting.getActiveSubsets() ); 430cdf0e10cSrcweir 431cdf0e10cSrcweir const ::basegfx::B2DRectangle aDefaultBounds( 0.0,0.0,1.0,1.0 ); 432cdf0e10cSrcweir 433cdf0e10cSrcweir // perform the cheapest check first 434cdf0e10cSrcweir if( rSubsets.empty() ) 435cdf0e10cSrcweir { 436cdf0e10cSrcweir // if subset contains the whole shape, no need to call 437cdf0e10cSrcweir // the somewhat expensive bound calculation, since as 438cdf0e10cSrcweir // long as the subset is empty, this branch will be 439cdf0e10cSrcweir // taken. 440cdf0e10cSrcweir return aDefaultBounds; 441cdf0e10cSrcweir } 442cdf0e10cSrcweir else 443cdf0e10cSrcweir { 444cdf0e10cSrcweir OSL_ENSURE( rSubsets.size() != 1 || 445cdf0e10cSrcweir !rSubsets.front().isEmpty(), 446cdf0e10cSrcweir "DrawShape::getActualUnitShapeBounds() expects a " 447cdf0e10cSrcweir "_non-empty_ subset vector for a subsetted shape!" ); 448cdf0e10cSrcweir 449cdf0e10cSrcweir // are the cached bounds still valid? 450cdf0e10cSrcweir if( !maCurrentShapeUnitBounds ) 451cdf0e10cSrcweir { 452cdf0e10cSrcweir // no, (re)generate them 453cdf0e10cSrcweir // ===================== 454cdf0e10cSrcweir 455cdf0e10cSrcweir // setup cached values to defaults (might fail to 456cdf0e10cSrcweir // retrieve true bounds below) 457cdf0e10cSrcweir maCurrentShapeUnitBounds.reset( aDefaultBounds ); 458cdf0e10cSrcweir 459cdf0e10cSrcweir // TODO(P2): the subset of the master shape (that from 460cdf0e10cSrcweir // which the subsets are subtracted) changes 461cdf0e10cSrcweir // relatively often (every time a subset shape is 462cdf0e10cSrcweir // added or removed). Maybe we should exclude it here, 463cdf0e10cSrcweir // always assuming full bounds? 464cdf0e10cSrcweir 465cdf0e10cSrcweir ::cppcanvas::CanvasSharedPtr pDestinationCanvas( 466cdf0e10cSrcweir maViewShapes.front()->getViewLayer()->getCanvas() ); 467cdf0e10cSrcweir 468cdf0e10cSrcweir // TODO(Q2): Although this _is_ currently 469cdf0e10cSrcweir // view-agnostic, it might not stay like 470cdf0e10cSrcweir // that. Maybe this method should again be moved 471cdf0e10cSrcweir // to the ViewShape 472cdf0e10cSrcweir ::cppcanvas::RendererSharedPtr pRenderer( 473cdf0e10cSrcweir maViewShapes.front()->getRenderer( 474cdf0e10cSrcweir pDestinationCanvas, mpCurrMtf, mpAttributeLayer ) ); 475cdf0e10cSrcweir 476cdf0e10cSrcweir // If we cannot not prefetch, be defensive and assume 477cdf0e10cSrcweir // full shape size 478cdf0e10cSrcweir if( pRenderer ) 479cdf0e10cSrcweir { 480cdf0e10cSrcweir // temporarily, switch total transformation to identity 481cdf0e10cSrcweir // (need the bounds in the [0,1]x[0,1] unit coordinate 482cdf0e10cSrcweir // system. 483cdf0e10cSrcweir ::basegfx::B2DHomMatrix aEmptyTransformation; 484cdf0e10cSrcweir 485cdf0e10cSrcweir ::basegfx::B2DHomMatrix aOldTransform( pDestinationCanvas->getTransformation() ); 486cdf0e10cSrcweir pDestinationCanvas->setTransformation( aEmptyTransformation ); 487cdf0e10cSrcweir pRenderer->setTransformation( aEmptyTransformation ); 488cdf0e10cSrcweir 489cdf0e10cSrcweir // restore old transformation when leaving the scope 490cdf0e10cSrcweir const ::comphelper::ScopeGuard aGuard( 491cdf0e10cSrcweir boost::bind( &::cppcanvas::Canvas::setTransformation, 492cdf0e10cSrcweir pDestinationCanvas, aOldTransform ) ); 493cdf0e10cSrcweir 494cdf0e10cSrcweir 495cdf0e10cSrcweir // retrieve bounds for subset of whole metafile 496cdf0e10cSrcweir // -------------------------------------------- 497cdf0e10cSrcweir 498cdf0e10cSrcweir ::basegfx::B2DRange aTotalBounds; 499cdf0e10cSrcweir 500cdf0e10cSrcweir // cannot use ::boost::bind, ::basegfx::B2DRange::expand() 501cdf0e10cSrcweir // is overloaded. 502cdf0e10cSrcweir VectorOfDocTreeNodes::const_iterator aCurr( rSubsets.begin() ); 503cdf0e10cSrcweir const VectorOfDocTreeNodes::const_iterator aEnd( rSubsets.end() ); 504cdf0e10cSrcweir while( aCurr != aEnd ) 505cdf0e10cSrcweir { 506cdf0e10cSrcweir aTotalBounds.expand( pRenderer->getSubsetArea( 507cdf0e10cSrcweir aCurr->getStartIndex(), 508cdf0e10cSrcweir aCurr->getEndIndex() ) ); 509cdf0e10cSrcweir ++aCurr; 510cdf0e10cSrcweir } 511cdf0e10cSrcweir 512cdf0e10cSrcweir OSL_ENSURE( aTotalBounds.getMinX() >= -0.1 && 513cdf0e10cSrcweir aTotalBounds.getMinY() >= -0.1 && 514cdf0e10cSrcweir aTotalBounds.getMaxX() <= 1.1 && 515cdf0e10cSrcweir aTotalBounds.getMaxY() <= 1.1, 516cdf0e10cSrcweir "DrawShape::getActualUnitShapeBounds(): bounds noticeably larger than original shape - clipping!" ); 517cdf0e10cSrcweir 518cdf0e10cSrcweir // really make sure no shape appears larger than its 519cdf0e10cSrcweir // original bounds (there _are_ some pathologic cases, 520cdf0e10cSrcweir // especially when imported from PPT, that have 521cdf0e10cSrcweir // e.g. obscenely large polygon bounds) 522cdf0e10cSrcweir aTotalBounds.intersect( 523cdf0e10cSrcweir ::basegfx::B2DRange( 0.0, 0.0, 524cdf0e10cSrcweir 1.0, 1.0 )); 525cdf0e10cSrcweir 526cdf0e10cSrcweir maCurrentShapeUnitBounds.reset( aTotalBounds ); 527cdf0e10cSrcweir } 528cdf0e10cSrcweir } 529cdf0e10cSrcweir 530cdf0e10cSrcweir return *maCurrentShapeUnitBounds; 531cdf0e10cSrcweir } 532cdf0e10cSrcweir } 533cdf0e10cSrcweir 534cdf0e10cSrcweir DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape, 535cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 536cdf0e10cSrcweir double nPrio, 537cdf0e10cSrcweir bool bForeignSource, 538cdf0e10cSrcweir const SlideShowContext& rContext ) : 539cdf0e10cSrcweir mxShape( xShape ), 540cdf0e10cSrcweir mxPage( xContainingPage ), 541cdf0e10cSrcweir maAnimationFrames(), // empty, we don't have no intrinsic animation 542cdf0e10cSrcweir mnCurrFrame(0), 543cdf0e10cSrcweir mpCurrMtf(), 544cdf0e10cSrcweir mnCurrMtfLoadFlags( bForeignSource 545cdf0e10cSrcweir ? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ), 546cdf0e10cSrcweir maCurrentShapeUnitBounds(), 547cdf0e10cSrcweir mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ), 548cdf0e10cSrcweir maBounds( getAPIShapeBounds( xShape ) ), 549cdf0e10cSrcweir mpAttributeLayer(), 550cdf0e10cSrcweir mpIntrinsicAnimationActivity(), 551cdf0e10cSrcweir mnAttributeTransformationState(0), 552cdf0e10cSrcweir mnAttributeClipState(0), 553cdf0e10cSrcweir mnAttributeAlphaState(0), 554cdf0e10cSrcweir mnAttributePositionState(0), 555cdf0e10cSrcweir mnAttributeContentState(0), 556cdf0e10cSrcweir mnAttributeVisibilityState(0), 557cdf0e10cSrcweir maViewShapes(), 558cdf0e10cSrcweir mxComponentContext( rContext.mxComponentContext ), 559cdf0e10cSrcweir maHyperlinkIndices(), 560cdf0e10cSrcweir maHyperlinkRegions(), 561cdf0e10cSrcweir maSubsetting(), 562cdf0e10cSrcweir mnIsAnimatedCount(0), 563cdf0e10cSrcweir mnAnimationLoopCount(0), 564cdf0e10cSrcweir meCycleMode(CYCLE_LOOP), 565cdf0e10cSrcweir mbIsVisible( true ), 566cdf0e10cSrcweir mbForceUpdate( false ), 567cdf0e10cSrcweir mbAttributeLayerRevoked( false ), 568cdf0e10cSrcweir mbDrawingLayerAnim( false ) 569cdf0e10cSrcweir { 570cdf0e10cSrcweir ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" ); 571cdf0e10cSrcweir ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" ); 572cdf0e10cSrcweir 573cdf0e10cSrcweir // check for drawing layer animations: 574cdf0e10cSrcweir drawing::TextAnimationKind eKind = drawing::TextAnimationKind_NONE; 575cdf0e10cSrcweir uno::Reference<beans::XPropertySet> xPropSet( mxShape, 576cdf0e10cSrcweir uno::UNO_QUERY ); 577cdf0e10cSrcweir if( xPropSet.is() ) 578cdf0e10cSrcweir getPropertyValue( eKind, xPropSet, 579cdf0e10cSrcweir OUSTR("TextAnimationKind") ); 580cdf0e10cSrcweir mbDrawingLayerAnim = (eKind != drawing::TextAnimationKind_NONE); 581cdf0e10cSrcweir 582cdf0e10cSrcweir // must NOT be called from within initializer list, uses 583cdf0e10cSrcweir // state from mnCurrMtfLoadFlags! 584cdf0e10cSrcweir mpCurrMtf.reset( new GDIMetaFile ); 585cdf0e10cSrcweir local_getMetaFile_WithSpecialChartHandling( 586cdf0e10cSrcweir uno::Reference<lang::XComponent>(xShape, uno::UNO_QUERY), 587cdf0e10cSrcweir xContainingPage, *mpCurrMtf, mnCurrMtfLoadFlags, 588cdf0e10cSrcweir mxComponentContext ); 589cdf0e10cSrcweir ENSURE_OR_THROW( mpCurrMtf, 590cdf0e10cSrcweir "DrawShape::DrawShape(): Invalid metafile" ); 591cdf0e10cSrcweir maSubsetting.reset( mpCurrMtf ); 592cdf0e10cSrcweir 593cdf0e10cSrcweir prepareHyperlinkIndices(); 594cdf0e10cSrcweir } 595cdf0e10cSrcweir 596cdf0e10cSrcweir DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape, 597cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 598cdf0e10cSrcweir double nPrio, 599cdf0e10cSrcweir const Graphic& rGraphic, 600cdf0e10cSrcweir const SlideShowContext& rContext ) : 601cdf0e10cSrcweir mxShape( xShape ), 602cdf0e10cSrcweir mxPage( xContainingPage ), 603cdf0e10cSrcweir maAnimationFrames(), 604cdf0e10cSrcweir mnCurrFrame(0), 605cdf0e10cSrcweir mpCurrMtf(), 606cdf0e10cSrcweir mnCurrMtfLoadFlags( MTF_LOAD_NONE ), 607cdf0e10cSrcweir maCurrentShapeUnitBounds(), 608cdf0e10cSrcweir mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ), 609cdf0e10cSrcweir maBounds( getAPIShapeBounds( xShape ) ), 610cdf0e10cSrcweir mpAttributeLayer(), 611cdf0e10cSrcweir mpIntrinsicAnimationActivity(), 612cdf0e10cSrcweir mnAttributeTransformationState(0), 613cdf0e10cSrcweir mnAttributeClipState(0), 614cdf0e10cSrcweir mnAttributeAlphaState(0), 615cdf0e10cSrcweir mnAttributePositionState(0), 616cdf0e10cSrcweir mnAttributeContentState(0), 617cdf0e10cSrcweir mnAttributeVisibilityState(0), 618cdf0e10cSrcweir maViewShapes(), 619cdf0e10cSrcweir mxComponentContext( rContext.mxComponentContext ), 620cdf0e10cSrcweir maHyperlinkIndices(), 621cdf0e10cSrcweir maHyperlinkRegions(), 622cdf0e10cSrcweir maSubsetting(), 623cdf0e10cSrcweir mnIsAnimatedCount(0), 624cdf0e10cSrcweir mnAnimationLoopCount(0), 625cdf0e10cSrcweir meCycleMode(CYCLE_LOOP), 626cdf0e10cSrcweir mbIsVisible( true ), 627cdf0e10cSrcweir mbForceUpdate( false ), 628cdf0e10cSrcweir mbAttributeLayerRevoked( false ), 629cdf0e10cSrcweir mbDrawingLayerAnim( false ) 630cdf0e10cSrcweir { 631cdf0e10cSrcweir ENSURE_OR_THROW( rGraphic.IsAnimated(), 632cdf0e10cSrcweir "DrawShape::DrawShape(): Graphic is no animation" ); 633cdf0e10cSrcweir 634cdf0e10cSrcweir getAnimationFromGraphic( maAnimationFrames, 635cdf0e10cSrcweir mnAnimationLoopCount, 636cdf0e10cSrcweir meCycleMode, 637cdf0e10cSrcweir rGraphic ); 638cdf0e10cSrcweir 639cdf0e10cSrcweir ENSURE_OR_THROW( !maAnimationFrames.empty() && 640cdf0e10cSrcweir maAnimationFrames.front().mpMtf, 641cdf0e10cSrcweir "DrawShape::DrawShape(): " ); 642cdf0e10cSrcweir mpCurrMtf = maAnimationFrames.front().mpMtf; 643cdf0e10cSrcweir 644cdf0e10cSrcweir ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" ); 645cdf0e10cSrcweir ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" ); 646cdf0e10cSrcweir ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" ); 647cdf0e10cSrcweir } 648cdf0e10cSrcweir 649cdf0e10cSrcweir DrawShape::DrawShape( const DrawShape& rSrc, 650cdf0e10cSrcweir const DocTreeNode& rTreeNode, 651cdf0e10cSrcweir double nPrio ) : 652cdf0e10cSrcweir mxShape( rSrc.mxShape ), 653cdf0e10cSrcweir mxPage( rSrc.mxPage ), 654cdf0e10cSrcweir maAnimationFrames(), // don't copy animations for subsets, 655cdf0e10cSrcweir // only the current frame! 656cdf0e10cSrcweir mnCurrFrame(0), 657cdf0e10cSrcweir mpCurrMtf( rSrc.mpCurrMtf ), 658cdf0e10cSrcweir mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ), 659cdf0e10cSrcweir maCurrentShapeUnitBounds(), 660cdf0e10cSrcweir mnPriority( nPrio ), 661cdf0e10cSrcweir maBounds( rSrc.maBounds ), 662cdf0e10cSrcweir mpAttributeLayer(), 663cdf0e10cSrcweir mpIntrinsicAnimationActivity(), 664cdf0e10cSrcweir mnAttributeTransformationState(0), 665cdf0e10cSrcweir mnAttributeClipState(0), 666cdf0e10cSrcweir mnAttributeAlphaState(0), 667cdf0e10cSrcweir mnAttributePositionState(0), 668cdf0e10cSrcweir mnAttributeContentState(0), 669cdf0e10cSrcweir mnAttributeVisibilityState(0), 670cdf0e10cSrcweir maViewShapes(), 671cdf0e10cSrcweir mxComponentContext( rSrc.mxComponentContext ), 672cdf0e10cSrcweir maHyperlinkIndices(), 673cdf0e10cSrcweir maHyperlinkRegions(), 674cdf0e10cSrcweir maSubsetting( rTreeNode, mpCurrMtf ), 675cdf0e10cSrcweir mnIsAnimatedCount(0), 676cdf0e10cSrcweir mnAnimationLoopCount(0), 677cdf0e10cSrcweir meCycleMode(CYCLE_LOOP), 678cdf0e10cSrcweir mbIsVisible( rSrc.mbIsVisible ), 679cdf0e10cSrcweir mbForceUpdate( false ), 680cdf0e10cSrcweir mbAttributeLayerRevoked( false ), 681cdf0e10cSrcweir mbDrawingLayerAnim( false ) 682cdf0e10cSrcweir { 683cdf0e10cSrcweir ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" ); 684cdf0e10cSrcweir ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" ); 685cdf0e10cSrcweir 686cdf0e10cSrcweir // xxx todo: currently not implemented for subsetted shapes; 687cdf0e10cSrcweir // would mean modifying set of hyperlink regions when 688cdf0e10cSrcweir // subsetting text portions. N.B.: there's already an 689cdf0e10cSrcweir // issue for this #i72828# 690cdf0e10cSrcweir } 691cdf0e10cSrcweir 692cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 693cdf0e10cSrcweir // 694cdf0e10cSrcweir // Public methods 695cdf0e10cSrcweir // 696cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 697cdf0e10cSrcweir 698cdf0e10cSrcweir DrawShapeSharedPtr DrawShape::create( 699cdf0e10cSrcweir const uno::Reference< drawing::XShape >& xShape, 700cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 701cdf0e10cSrcweir double nPrio, 702cdf0e10cSrcweir bool bForeignSource, 703cdf0e10cSrcweir const SlideShowContext& rContext ) 704cdf0e10cSrcweir { 705cdf0e10cSrcweir DrawShapeSharedPtr pShape( new DrawShape(xShape, 706cdf0e10cSrcweir xContainingPage, 707cdf0e10cSrcweir nPrio, 708cdf0e10cSrcweir bForeignSource, 709cdf0e10cSrcweir rContext) ); 710cdf0e10cSrcweir 711cdf0e10cSrcweir if( pShape->hasIntrinsicAnimation() ) 712cdf0e10cSrcweir { 713cdf0e10cSrcweir OSL_ASSERT( pShape->maAnimationFrames.empty() ); 714cdf0e10cSrcweir if( pShape->getNumberOfTreeNodes( 715cdf0e10cSrcweir DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH) > 0 ) 716cdf0e10cSrcweir { 717cdf0e10cSrcweir pShape->mpIntrinsicAnimationActivity = 718cdf0e10cSrcweir createDrawingLayerAnimActivity( 719cdf0e10cSrcweir rContext, 720cdf0e10cSrcweir pShape); 721cdf0e10cSrcweir } 722cdf0e10cSrcweir } 723cdf0e10cSrcweir 724cdf0e10cSrcweir if( pShape->hasHyperlinks() ) 725cdf0e10cSrcweir rContext.mpSubsettableShapeManager->addHyperlinkArea( pShape ); 726cdf0e10cSrcweir 727cdf0e10cSrcweir return pShape; 728cdf0e10cSrcweir } 729cdf0e10cSrcweir 730cdf0e10cSrcweir DrawShapeSharedPtr DrawShape::create( 731cdf0e10cSrcweir const uno::Reference< drawing::XShape >& xShape, 732cdf0e10cSrcweir const uno::Reference< drawing::XDrawPage >& xContainingPage, 733cdf0e10cSrcweir double nPrio, 734cdf0e10cSrcweir const Graphic& rGraphic, 735cdf0e10cSrcweir const SlideShowContext& rContext ) 736cdf0e10cSrcweir { 737cdf0e10cSrcweir DrawShapeSharedPtr pShape( new DrawShape(xShape, 738cdf0e10cSrcweir xContainingPage, 739cdf0e10cSrcweir nPrio, 740cdf0e10cSrcweir rGraphic, 741cdf0e10cSrcweir rContext) ); 742cdf0e10cSrcweir 743cdf0e10cSrcweir if( pShape->hasIntrinsicAnimation() ) 744cdf0e10cSrcweir { 745cdf0e10cSrcweir OSL_ASSERT( !pShape->maAnimationFrames.empty() ); 746cdf0e10cSrcweir 747cdf0e10cSrcweir std::vector<double> aTimeout; 748cdf0e10cSrcweir std::transform( 749cdf0e10cSrcweir pShape->maAnimationFrames.begin(), 750cdf0e10cSrcweir pShape->maAnimationFrames.end(), 751cdf0e10cSrcweir std::back_insert_iterator< std::vector<double> >( aTimeout ), 752cdf0e10cSrcweir boost::mem_fn(&MtfAnimationFrame::getDuration) ); 753cdf0e10cSrcweir 754cdf0e10cSrcweir WakeupEventSharedPtr pWakeupEvent( 755cdf0e10cSrcweir new WakeupEvent( rContext.mrEventQueue.getTimer(), 756cdf0e10cSrcweir rContext.mrActivitiesQueue ) ); 757cdf0e10cSrcweir 758cdf0e10cSrcweir ActivitySharedPtr pActivity = 759cdf0e10cSrcweir createIntrinsicAnimationActivity( 760cdf0e10cSrcweir rContext, 761cdf0e10cSrcweir pShape, 762cdf0e10cSrcweir pWakeupEvent, 763cdf0e10cSrcweir aTimeout, 764cdf0e10cSrcweir pShape->mnAnimationLoopCount, 765cdf0e10cSrcweir pShape->meCycleMode); 766cdf0e10cSrcweir 767cdf0e10cSrcweir pWakeupEvent->setActivity( pActivity ); 768cdf0e10cSrcweir pShape->mpIntrinsicAnimationActivity = pActivity; 769cdf0e10cSrcweir } 770cdf0e10cSrcweir 771cdf0e10cSrcweir OSL_ENSURE( !pShape->hasHyperlinks(), 772cdf0e10cSrcweir "DrawShape::create(): graphic-only shapes must not have hyperlinks!" ); 773cdf0e10cSrcweir 774cdf0e10cSrcweir return pShape; 775cdf0e10cSrcweir } 776cdf0e10cSrcweir 777cdf0e10cSrcweir DrawShape::~DrawShape() 778cdf0e10cSrcweir { 779cdf0e10cSrcweir try 780cdf0e10cSrcweir { 781cdf0e10cSrcweir // dispose intrinsic animation activity, else, it will 782cdf0e10cSrcweir // linger forever 783cdf0e10cSrcweir ActivitySharedPtr pActivity( mpIntrinsicAnimationActivity.lock() ); 784cdf0e10cSrcweir if( pActivity ) 785cdf0e10cSrcweir pActivity->dispose(); 786cdf0e10cSrcweir } 787cdf0e10cSrcweir catch (uno::Exception &) 788cdf0e10cSrcweir { 789cdf0e10cSrcweir OSL_ENSURE( false, rtl::OUStringToOString( 790cdf0e10cSrcweir comphelper::anyToString( 791cdf0e10cSrcweir cppu::getCaughtException() ), 792cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ).getStr() ); 793cdf0e10cSrcweir } 794cdf0e10cSrcweir } 795cdf0e10cSrcweir 796cdf0e10cSrcweir uno::Reference< drawing::XShape > DrawShape::getXShape() const 797cdf0e10cSrcweir { 798cdf0e10cSrcweir return mxShape; 799cdf0e10cSrcweir } 800cdf0e10cSrcweir 801cdf0e10cSrcweir void DrawShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer, 802cdf0e10cSrcweir bool bRedrawLayer ) 803cdf0e10cSrcweir { 804cdf0e10cSrcweir ViewShapeVector::iterator aEnd( maViewShapes.end() ); 805cdf0e10cSrcweir 806cdf0e10cSrcweir // already added? 807cdf0e10cSrcweir if( ::std::find_if( maViewShapes.begin(), 808cdf0e10cSrcweir aEnd, 809cdf0e10cSrcweir ::boost::bind<bool>( 810cdf0e10cSrcweir ::std::equal_to< ViewLayerSharedPtr >(), 811cdf0e10cSrcweir ::boost::bind( &ViewShape::getViewLayer, 812cdf0e10cSrcweir _1 ), 813cdf0e10cSrcweir ::boost::cref( rNewLayer ) ) ) != aEnd ) 814cdf0e10cSrcweir { 815cdf0e10cSrcweir // yes, nothing to do 816cdf0e10cSrcweir return; 817cdf0e10cSrcweir } 818cdf0e10cSrcweir 819cdf0e10cSrcweir ViewShapeSharedPtr pNewShape( new ViewShape( rNewLayer ) ); 820cdf0e10cSrcweir 821cdf0e10cSrcweir maViewShapes.push_back( pNewShape ); 822cdf0e10cSrcweir 823cdf0e10cSrcweir // pass on animation state 824cdf0e10cSrcweir if( mnIsAnimatedCount ) 825cdf0e10cSrcweir { 826cdf0e10cSrcweir for( int i=0; i<mnIsAnimatedCount; ++i ) 827cdf0e10cSrcweir pNewShape->enterAnimationMode(); 828cdf0e10cSrcweir } 829cdf0e10cSrcweir 830cdf0e10cSrcweir // render the Shape on the newly added ViewLayer 831cdf0e10cSrcweir if( bRedrawLayer ) 832cdf0e10cSrcweir { 833cdf0e10cSrcweir pNewShape->update( mpCurrMtf, 834cdf0e10cSrcweir getViewRenderArgs(), 835cdf0e10cSrcweir ViewShape::FORCE, 836cdf0e10cSrcweir isVisible() ); 837cdf0e10cSrcweir } 838cdf0e10cSrcweir } 839cdf0e10cSrcweir 840cdf0e10cSrcweir bool DrawShape::removeViewLayer( const ViewLayerSharedPtr& rLayer ) 841cdf0e10cSrcweir { 842cdf0e10cSrcweir const ViewShapeVector::iterator aEnd( maViewShapes.end() ); 843cdf0e10cSrcweir 844cdf0e10cSrcweir OSL_ENSURE( ::std::count_if(maViewShapes.begin(), 845cdf0e10cSrcweir aEnd, 846cdf0e10cSrcweir ::boost::bind<bool>( 847cdf0e10cSrcweir ::std::equal_to< ViewLayerSharedPtr >(), 848cdf0e10cSrcweir ::boost::bind( &ViewShape::getViewLayer, 849cdf0e10cSrcweir _1 ), 850cdf0e10cSrcweir ::boost::cref( rLayer ) ) ) < 2, 851cdf0e10cSrcweir "DrawShape::removeViewLayer(): Duplicate ViewLayer entries!" ); 852cdf0e10cSrcweir 853cdf0e10cSrcweir ViewShapeVector::iterator aIter; 854cdf0e10cSrcweir 855cdf0e10cSrcweir if( (aIter=::std::remove_if( maViewShapes.begin(), 856cdf0e10cSrcweir aEnd, 857cdf0e10cSrcweir ::boost::bind<bool>( 858cdf0e10cSrcweir ::std::equal_to< ViewLayerSharedPtr >(), 859cdf0e10cSrcweir ::boost::bind( &ViewShape::getViewLayer, 860cdf0e10cSrcweir _1 ), 861cdf0e10cSrcweir ::boost::cref( rLayer ) ) )) == aEnd ) 862cdf0e10cSrcweir { 863cdf0e10cSrcweir // view layer seemingly was not added, failed 864cdf0e10cSrcweir return false; 865cdf0e10cSrcweir } 866cdf0e10cSrcweir 867cdf0e10cSrcweir // actually erase from container 868cdf0e10cSrcweir maViewShapes.erase( aIter, aEnd ); 869cdf0e10cSrcweir 870cdf0e10cSrcweir return true; 871cdf0e10cSrcweir } 872cdf0e10cSrcweir 873cdf0e10cSrcweir bool DrawShape::clearAllViewLayers() 874cdf0e10cSrcweir { 875cdf0e10cSrcweir maViewShapes.clear(); 876cdf0e10cSrcweir return true; 877cdf0e10cSrcweir } 878cdf0e10cSrcweir 879cdf0e10cSrcweir bool DrawShape::update() const 880cdf0e10cSrcweir { 881cdf0e10cSrcweir if( mbForceUpdate ) 882cdf0e10cSrcweir { 883cdf0e10cSrcweir return render(); 884cdf0e10cSrcweir } 885cdf0e10cSrcweir else 886cdf0e10cSrcweir { 887cdf0e10cSrcweir return implRender( getUpdateFlags() ); 888cdf0e10cSrcweir } 889cdf0e10cSrcweir } 890cdf0e10cSrcweir 891cdf0e10cSrcweir bool DrawShape::render() const 892cdf0e10cSrcweir { 893cdf0e10cSrcweir // force redraw. Have to also pass on the update flags, 894cdf0e10cSrcweir // because e.g. content update (regeneration of the 895cdf0e10cSrcweir // metafile renderer) is normally not performed. A simple 896cdf0e10cSrcweir // ViewShape::FORCE would only paint the metafile in its 897cdf0e10cSrcweir // old state. 898cdf0e10cSrcweir return implRender( ViewShape::FORCE | getUpdateFlags() ); 899cdf0e10cSrcweir } 900cdf0e10cSrcweir 901cdf0e10cSrcweir bool DrawShape::isContentChanged() const 902cdf0e10cSrcweir { 903cdf0e10cSrcweir return mbForceUpdate ? 904cdf0e10cSrcweir true : 905cdf0e10cSrcweir getUpdateFlags() != ViewShape::NONE; 906cdf0e10cSrcweir } 907cdf0e10cSrcweir 908cdf0e10cSrcweir 909cdf0e10cSrcweir ::basegfx::B2DRectangle DrawShape::getBounds() const 910cdf0e10cSrcweir { 911cdf0e10cSrcweir // little optimization: for non-modified shapes, we don't 912cdf0e10cSrcweir // create an ShapeAttributeStack, and therefore also don't 913cdf0e10cSrcweir // have to check it. 914cdf0e10cSrcweir return getShapePosSize( maBounds, 915cdf0e10cSrcweir mpAttributeLayer ); 916cdf0e10cSrcweir } 917cdf0e10cSrcweir 918cdf0e10cSrcweir ::basegfx::B2DRectangle DrawShape::getDomBounds() const 919cdf0e10cSrcweir { 920cdf0e10cSrcweir return maBounds; 921cdf0e10cSrcweir } 922cdf0e10cSrcweir 923cdf0e10cSrcweir namespace 924cdf0e10cSrcweir { 925cdf0e10cSrcweir /** Functor expanding AA border for each passed ViewShape 926cdf0e10cSrcweir 927cdf0e10cSrcweir Could not use ::boost::bind here, since 928cdf0e10cSrcweir B2DRange::expand is overloaded (which yields one or 929cdf0e10cSrcweir the other template type deduction ambiguous) 930cdf0e10cSrcweir */ 931cdf0e10cSrcweir class Expander 932cdf0e10cSrcweir { 933cdf0e10cSrcweir public: 934cdf0e10cSrcweir Expander( ::basegfx::B2DSize& rBounds ) : 935cdf0e10cSrcweir mrBounds( rBounds ) 936cdf0e10cSrcweir { 937cdf0e10cSrcweir } 938cdf0e10cSrcweir 939cdf0e10cSrcweir void operator()( const ViewShapeSharedPtr& rShape ) const 940cdf0e10cSrcweir { 941cdf0e10cSrcweir const ::basegfx::B2DSize& rShapeBorder( rShape->getAntialiasingBorder() ); 942cdf0e10cSrcweir 943cdf0e10cSrcweir mrBounds.setX( 944cdf0e10cSrcweir ::std::max( 945cdf0e10cSrcweir rShapeBorder.getX(), 946cdf0e10cSrcweir mrBounds.getX() ) ); 947cdf0e10cSrcweir mrBounds.setY( 948cdf0e10cSrcweir ::std::max( 949cdf0e10cSrcweir rShapeBorder.getY(), 950cdf0e10cSrcweir mrBounds.getY() ) ); 951cdf0e10cSrcweir } 952cdf0e10cSrcweir 953cdf0e10cSrcweir private: 954cdf0e10cSrcweir ::basegfx::B2DSize& mrBounds; 955cdf0e10cSrcweir }; 956cdf0e10cSrcweir } 957cdf0e10cSrcweir 958cdf0e10cSrcweir ::basegfx::B2DRectangle DrawShape::getUpdateArea() const 959cdf0e10cSrcweir { 960cdf0e10cSrcweir ::basegfx::B2DRectangle aBounds; 961cdf0e10cSrcweir 962cdf0e10cSrcweir // an already empty shape bound need no further 963cdf0e10cSrcweir // treatment. In fact, any changes applied below would 964cdf0e10cSrcweir // actually remove the special empty state, thus, don't 965cdf0e10cSrcweir // change! 966cdf0e10cSrcweir if( !maBounds.isEmpty() ) 967cdf0e10cSrcweir { 968cdf0e10cSrcweir basegfx::B2DRectangle aUnitBounds(0.0,0.0,1.0,1.0); 969cdf0e10cSrcweir 970cdf0e10cSrcweir if( !maViewShapes.empty() ) 971cdf0e10cSrcweir aUnitBounds = getActualUnitShapeBounds(); 972cdf0e10cSrcweir 973cdf0e10cSrcweir if( !aUnitBounds.isEmpty() ) 974cdf0e10cSrcweir { 975cdf0e10cSrcweir if( mpAttributeLayer ) 976cdf0e10cSrcweir { 977cdf0e10cSrcweir // calc actual shape area (in user coordinate 978cdf0e10cSrcweir // space) from the transformation as given by the 979cdf0e10cSrcweir // shape attribute layer 980cdf0e10cSrcweir aBounds = getShapeUpdateArea( aUnitBounds, 981cdf0e10cSrcweir getShapeTransformation( getBounds(), 982cdf0e10cSrcweir mpAttributeLayer ), 983cdf0e10cSrcweir mpAttributeLayer ); 984cdf0e10cSrcweir } 985cdf0e10cSrcweir else 986cdf0e10cSrcweir { 987cdf0e10cSrcweir // no attribute layer, thus, the true shape bounds 988cdf0e10cSrcweir // can be directly derived from the XShape bound 989cdf0e10cSrcweir // attribute 990cdf0e10cSrcweir aBounds = getShapeUpdateArea( aUnitBounds, 991cdf0e10cSrcweir maBounds ); 992cdf0e10cSrcweir } 993cdf0e10cSrcweir 994cdf0e10cSrcweir if( !maViewShapes.empty() ) 995cdf0e10cSrcweir { 996cdf0e10cSrcweir // determine border needed for antialiasing the shape 997cdf0e10cSrcweir ::basegfx::B2DSize aAABorder(0.0,0.0); 998cdf0e10cSrcweir 999cdf0e10cSrcweir // for every view, get AA border and 'expand' aAABorder 1000cdf0e10cSrcweir // appropriately. 1001cdf0e10cSrcweir ::std::for_each( maViewShapes.begin(), 1002cdf0e10cSrcweir maViewShapes.end(), 1003cdf0e10cSrcweir Expander( aAABorder ) ); 1004cdf0e10cSrcweir 1005cdf0e10cSrcweir // add calculated AA border to aBounds 1006cdf0e10cSrcweir aBounds = ::basegfx::B2DRectangle( aBounds.getMinX() - aAABorder.getX(), 1007cdf0e10cSrcweir aBounds.getMinY() - aAABorder.getY(), 1008cdf0e10cSrcweir aBounds.getMaxX() + aAABorder.getX(), 1009cdf0e10cSrcweir aBounds.getMaxY() + aAABorder.getY() ); 1010cdf0e10cSrcweir } 1011cdf0e10cSrcweir } 1012cdf0e10cSrcweir } 1013cdf0e10cSrcweir 1014cdf0e10cSrcweir return aBounds; 1015cdf0e10cSrcweir } 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir bool DrawShape::isVisible() const 1018cdf0e10cSrcweir { 1019cdf0e10cSrcweir bool bIsVisible( mbIsVisible ); 1020cdf0e10cSrcweir 1021cdf0e10cSrcweir if( mpAttributeLayer ) 1022cdf0e10cSrcweir { 1023cdf0e10cSrcweir // check whether visibility and alpha are not default 1024cdf0e10cSrcweir // (mpAttributeLayer->isVisibilityValid() returns true 1025cdf0e10cSrcweir // then): bVisible becomes true, if shape visibility 1026cdf0e10cSrcweir // is on and alpha is not 0.0 (fully transparent) 1027cdf0e10cSrcweir if( mpAttributeLayer->isVisibilityValid() ) 1028cdf0e10cSrcweir bIsVisible = mpAttributeLayer->getVisibility(); 1029cdf0e10cSrcweir 1030cdf0e10cSrcweir // only touch bIsVisible, if the shape is still 1031cdf0e10cSrcweir // visible - if getVisibility already made us 1032cdf0e10cSrcweir // invisible, no alpha value will make us appear 1033cdf0e10cSrcweir // again. 1034cdf0e10cSrcweir if( bIsVisible && mpAttributeLayer->isAlphaValid() ) 1035cdf0e10cSrcweir bIsVisible = !::basegfx::fTools::equalZero( mpAttributeLayer->getAlpha() ); 1036cdf0e10cSrcweir } 1037cdf0e10cSrcweir 1038cdf0e10cSrcweir return bIsVisible; 1039cdf0e10cSrcweir } 1040cdf0e10cSrcweir 1041cdf0e10cSrcweir double DrawShape::getPriority() const 1042cdf0e10cSrcweir { 1043cdf0e10cSrcweir return mnPriority; 1044cdf0e10cSrcweir } 1045cdf0e10cSrcweir 1046cdf0e10cSrcweir bool DrawShape::isBackgroundDetached() const 1047cdf0e10cSrcweir { 1048cdf0e10cSrcweir return mnIsAnimatedCount > 0; 1049cdf0e10cSrcweir } 1050cdf0e10cSrcweir 1051cdf0e10cSrcweir bool DrawShape::hasIntrinsicAnimation() const 1052cdf0e10cSrcweir { 1053cdf0e10cSrcweir return (!maAnimationFrames.empty() || mbDrawingLayerAnim); 1054cdf0e10cSrcweir } 1055cdf0e10cSrcweir 1056cdf0e10cSrcweir bool DrawShape::setIntrinsicAnimationFrame( ::std::size_t nCurrFrame ) 1057cdf0e10cSrcweir { 1058cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( nCurrFrame < maAnimationFrames.size(), 1059cdf0e10cSrcweir "DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" ); 1060cdf0e10cSrcweir 1061cdf0e10cSrcweir if( mnCurrFrame != nCurrFrame ) 1062cdf0e10cSrcweir { 1063cdf0e10cSrcweir mnCurrFrame = nCurrFrame; 1064cdf0e10cSrcweir mpCurrMtf = maAnimationFrames[ mnCurrFrame ].mpMtf; 1065cdf0e10cSrcweir mbForceUpdate = true; 1066cdf0e10cSrcweir } 1067cdf0e10cSrcweir 1068cdf0e10cSrcweir return true; 1069cdf0e10cSrcweir } 1070cdf0e10cSrcweir 1071cdf0e10cSrcweir // hyperlink support 1072cdf0e10cSrcweir void DrawShape::prepareHyperlinkIndices() const 1073cdf0e10cSrcweir { 1074cdf0e10cSrcweir if ( !maHyperlinkIndices.empty()) 1075cdf0e10cSrcweir { 1076cdf0e10cSrcweir maHyperlinkIndices.clear(); 1077cdf0e10cSrcweir maHyperlinkRegions.clear(); 1078cdf0e10cSrcweir } 1079cdf0e10cSrcweir 1080cdf0e10cSrcweir sal_Int32 nIndex = 0; 1081cdf0e10cSrcweir for ( MetaAction * pCurrAct = mpCurrMtf->FirstAction(); 1082cdf0e10cSrcweir pCurrAct != 0; pCurrAct = mpCurrMtf->NextAction() ) 1083cdf0e10cSrcweir { 1084cdf0e10cSrcweir if (pCurrAct->GetType() == META_COMMENT_ACTION) { 1085cdf0e10cSrcweir MetaCommentAction * pAct = 1086cdf0e10cSrcweir static_cast<MetaCommentAction *>(pCurrAct); 1087cdf0e10cSrcweir // skip comment if not a special XTEXT comment 1088cdf0e10cSrcweir if (pAct->GetComment().CompareIgnoreCaseToAscii( 1089cdf0e10cSrcweir RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN") ) == 1090cdf0e10cSrcweir COMPARE_EQUAL && 1091cdf0e10cSrcweir // e.g. date field doesn't have data! 1092cdf0e10cSrcweir // currently assuming that only url field, this is 1093cdf0e10cSrcweir // somehow fragile! xxx todo if possible 1094cdf0e10cSrcweir pAct->GetData() != 0 && 1095cdf0e10cSrcweir pAct->GetDataSize() > 0) 1096cdf0e10cSrcweir { 1097cdf0e10cSrcweir if (!maHyperlinkIndices.empty() && 1098cdf0e10cSrcweir maHyperlinkIndices.back().second == -1) { 1099cdf0e10cSrcweir OSL_ENSURE( false, "### pending FIELD_SEQ_END!" ); 1100cdf0e10cSrcweir maHyperlinkIndices.pop_back(); 1101cdf0e10cSrcweir maHyperlinkRegions.pop_back(); 1102cdf0e10cSrcweir } 1103cdf0e10cSrcweir maHyperlinkIndices.push_back( 1104cdf0e10cSrcweir HyperlinkIndexPair( nIndex + 1, 1105cdf0e10cSrcweir -1 /* to be filled below */ ) ); 1106cdf0e10cSrcweir maHyperlinkRegions.push_back( 1107cdf0e10cSrcweir HyperlinkRegion( 1108cdf0e10cSrcweir basegfx::B2DRectangle(), 1109cdf0e10cSrcweir rtl::OUString( 1110cdf0e10cSrcweir reinterpret_cast<sal_Unicode const*>( 1111cdf0e10cSrcweir pAct->GetData()), 1112cdf0e10cSrcweir pAct->GetDataSize() / sizeof(sal_Unicode) ) 1113cdf0e10cSrcweir ) ); 1114cdf0e10cSrcweir } 1115cdf0e10cSrcweir else if (pAct->GetComment().CompareIgnoreCaseToAscii( 1116cdf0e10cSrcweir RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END")) == 1117cdf0e10cSrcweir COMPARE_EQUAL && 1118cdf0e10cSrcweir // pending end is expected: 1119cdf0e10cSrcweir !maHyperlinkIndices.empty() && 1120cdf0e10cSrcweir maHyperlinkIndices.back().second == -1) 1121cdf0e10cSrcweir { 1122cdf0e10cSrcweir maHyperlinkIndices.back().second = nIndex; 1123cdf0e10cSrcweir } 1124cdf0e10cSrcweir ++nIndex; 1125cdf0e10cSrcweir } 1126cdf0e10cSrcweir else 1127cdf0e10cSrcweir nIndex += getNextActionOffset(pCurrAct); 1128cdf0e10cSrcweir } 1129cdf0e10cSrcweir if (!maHyperlinkIndices.empty() && 1130cdf0e10cSrcweir maHyperlinkIndices.back().second == -1) { 1131cdf0e10cSrcweir OSL_ENSURE( false, "### pending FIELD_SEQ_END!" ); 1132cdf0e10cSrcweir maHyperlinkIndices.pop_back(); 1133cdf0e10cSrcweir maHyperlinkRegions.pop_back(); 1134cdf0e10cSrcweir } 1135cdf0e10cSrcweir OSL_ASSERT( maHyperlinkIndices.size() == maHyperlinkRegions.size()); 1136cdf0e10cSrcweir } 1137cdf0e10cSrcweir 1138cdf0e10cSrcweir bool DrawShape::hasHyperlinks() const 1139cdf0e10cSrcweir { 1140cdf0e10cSrcweir return ! maHyperlinkRegions.empty(); 1141cdf0e10cSrcweir } 1142cdf0e10cSrcweir 1143cdf0e10cSrcweir HyperlinkArea::HyperlinkRegions DrawShape::getHyperlinkRegions() const 1144cdf0e10cSrcweir { 1145cdf0e10cSrcweir OSL_ASSERT( !maViewShapes.empty() ); 1146cdf0e10cSrcweir 1147cdf0e10cSrcweir if( !isVisible() ) 1148cdf0e10cSrcweir return HyperlinkArea::HyperlinkRegions(); 1149cdf0e10cSrcweir 1150cdf0e10cSrcweir // late init, determine regions: 1151cdf0e10cSrcweir if( !maHyperlinkRegions.empty() && 1152cdf0e10cSrcweir !maViewShapes.empty() && 1153cdf0e10cSrcweir // region already inited? 1154cdf0e10cSrcweir maHyperlinkRegions.front().first.getWidth() == 0 && 1155cdf0e10cSrcweir maHyperlinkRegions.front().first.getHeight() == 0 && 1156cdf0e10cSrcweir maHyperlinkRegions.size() == maHyperlinkIndices.size() ) 1157cdf0e10cSrcweir { 1158cdf0e10cSrcweir // TODO(Q2): Although this _is_ currently 1159cdf0e10cSrcweir // view-agnostic, it might not stay like that. 1160cdf0e10cSrcweir ViewShapeSharedPtr const& pViewShape = maViewShapes.front(); 1161cdf0e10cSrcweir cppcanvas::CanvasSharedPtr const pCanvas( 1162cdf0e10cSrcweir pViewShape->getViewLayer()->getCanvas() ); 1163cdf0e10cSrcweir 1164cdf0e10cSrcweir // reuse Renderer of first view shape: 1165cdf0e10cSrcweir cppcanvas::RendererSharedPtr const pRenderer( 1166cdf0e10cSrcweir pViewShape->getRenderer( 1167cdf0e10cSrcweir pCanvas, mpCurrMtf, mpAttributeLayer ) ); 1168cdf0e10cSrcweir 1169cdf0e10cSrcweir OSL_ASSERT( pRenderer ); 1170cdf0e10cSrcweir 1171cdf0e10cSrcweir if (pRenderer) 1172cdf0e10cSrcweir { 1173cdf0e10cSrcweir basegfx::B2DHomMatrix const aOldTransform( 1174cdf0e10cSrcweir pCanvas->getTransformation() ); 1175cdf0e10cSrcweir basegfx::B2DHomMatrix aTransform; 1176cdf0e10cSrcweir pCanvas->setTransformation( aTransform /* empty */ ); 1177cdf0e10cSrcweir 1178cdf0e10cSrcweir comphelper::ScopeGuard const resetOldTransformation( 1179cdf0e10cSrcweir boost::bind( &cppcanvas::Canvas::setTransformation, 1180cdf0e10cSrcweir pCanvas.get(), 1181cdf0e10cSrcweir boost::cref(aOldTransform) )); 1182cdf0e10cSrcweir 1183cdf0e10cSrcweir aTransform.scale( maBounds.getWidth(), 1184cdf0e10cSrcweir maBounds.getHeight() ); 1185cdf0e10cSrcweir pRenderer->setTransformation( aTransform ); 1186cdf0e10cSrcweir pRenderer->setClip(); 1187cdf0e10cSrcweir 1188cdf0e10cSrcweir for( std::size_t pos = maHyperlinkRegions.size(); pos--; ) 1189cdf0e10cSrcweir { 1190cdf0e10cSrcweir // get region: 1191cdf0e10cSrcweir HyperlinkIndexPair const& rIndices = maHyperlinkIndices[pos]; 1192cdf0e10cSrcweir basegfx::B2DRectangle const region( 1193cdf0e10cSrcweir pRenderer->getSubsetArea( rIndices.first, 1194cdf0e10cSrcweir rIndices.second )); 1195cdf0e10cSrcweir maHyperlinkRegions[pos].first = region; 1196cdf0e10cSrcweir } 1197cdf0e10cSrcweir } 1198cdf0e10cSrcweir } 1199cdf0e10cSrcweir 1200cdf0e10cSrcweir // shift shape-relative hyperlink regions to 1201cdf0e10cSrcweir // slide-absolute position 1202cdf0e10cSrcweir 1203cdf0e10cSrcweir HyperlinkRegions aTranslatedRegions; 1204cdf0e10cSrcweir const basegfx::B2DPoint& rOffset(getBounds().getMinimum()); 1205cdf0e10cSrcweir HyperlinkRegions::const_iterator aIter( maHyperlinkRegions.begin() ); 1206cdf0e10cSrcweir HyperlinkRegions::const_iterator const aEnd ( maHyperlinkRegions.end() ); 1207cdf0e10cSrcweir while( aIter != aEnd ) 1208cdf0e10cSrcweir { 1209cdf0e10cSrcweir basegfx::B2DRange const& relRegion( aIter->first ); 1210cdf0e10cSrcweir aTranslatedRegions.push_back( 1211cdf0e10cSrcweir std::make_pair( 1212cdf0e10cSrcweir basegfx::B2DRange( 1213cdf0e10cSrcweir relRegion.getMinimum() + rOffset, 1214cdf0e10cSrcweir relRegion.getMaximum() + rOffset), 1215cdf0e10cSrcweir aIter->second) ); 1216cdf0e10cSrcweir ++aIter; 1217cdf0e10cSrcweir } 1218cdf0e10cSrcweir 1219cdf0e10cSrcweir return aTranslatedRegions; 1220cdf0e10cSrcweir } 1221cdf0e10cSrcweir 1222cdf0e10cSrcweir double DrawShape::getHyperlinkPriority() const 1223cdf0e10cSrcweir { 1224cdf0e10cSrcweir return getPriority(); 1225cdf0e10cSrcweir } 1226cdf0e10cSrcweir 1227cdf0e10cSrcweir 1228cdf0e10cSrcweir // AnimatableShape methods 1229cdf0e10cSrcweir // ====================================================== 1230cdf0e10cSrcweir 1231cdf0e10cSrcweir void DrawShape::enterAnimationMode() 1232cdf0e10cSrcweir { 1233cdf0e10cSrcweir OSL_ENSURE( !maViewShapes.empty(), 1234cdf0e10cSrcweir "DrawShape::enterAnimationMode(): called on DrawShape without views" ); 1235cdf0e10cSrcweir 1236cdf0e10cSrcweir if( mnIsAnimatedCount == 0 ) 1237cdf0e10cSrcweir { 1238cdf0e10cSrcweir // notify all ViewShapes, by calling their enterAnimationMode method. 1239cdf0e10cSrcweir // We're now entering animation mode 1240cdf0e10cSrcweir ::std::for_each( maViewShapes.begin(), 1241cdf0e10cSrcweir maViewShapes.end(), 1242cdf0e10cSrcweir ::boost::mem_fn( &ViewShape::enterAnimationMode ) ); 1243cdf0e10cSrcweir } 1244cdf0e10cSrcweir 1245cdf0e10cSrcweir ++mnIsAnimatedCount; 1246cdf0e10cSrcweir } 1247cdf0e10cSrcweir 1248cdf0e10cSrcweir void DrawShape::leaveAnimationMode() 1249cdf0e10cSrcweir { 1250cdf0e10cSrcweir OSL_ENSURE( !maViewShapes.empty(), 1251cdf0e10cSrcweir "DrawShape::leaveAnimationMode(): called on DrawShape without views" ); 1252cdf0e10cSrcweir 1253cdf0e10cSrcweir --mnIsAnimatedCount; 1254cdf0e10cSrcweir 1255cdf0e10cSrcweir if( mnIsAnimatedCount == 0 ) 1256cdf0e10cSrcweir { 1257cdf0e10cSrcweir // notify all ViewShapes, by calling their leaveAnimationMode method. 1258cdf0e10cSrcweir // we're now leaving animation mode 1259cdf0e10cSrcweir ::std::for_each( maViewShapes.begin(), 1260cdf0e10cSrcweir maViewShapes.end(), 1261cdf0e10cSrcweir ::boost::mem_fn( &ViewShape::leaveAnimationMode ) ); 1262cdf0e10cSrcweir } 1263cdf0e10cSrcweir } 1264cdf0e10cSrcweir 1265cdf0e10cSrcweir 1266cdf0e10cSrcweir // AttributableShape methods 1267cdf0e10cSrcweir // ====================================================== 1268cdf0e10cSrcweir 1269cdf0e10cSrcweir ShapeAttributeLayerSharedPtr DrawShape::createAttributeLayer() 1270cdf0e10cSrcweir { 1271cdf0e10cSrcweir // create new layer, with last as its new child 1272cdf0e10cSrcweir mpAttributeLayer.reset( new ShapeAttributeLayer( mpAttributeLayer ) ); 1273cdf0e10cSrcweir 1274cdf0e10cSrcweir // Update the local state ids to reflect those of the new layer. 1275cdf0e10cSrcweir updateStateIds(); 1276cdf0e10cSrcweir 1277cdf0e10cSrcweir return mpAttributeLayer; 1278cdf0e10cSrcweir } 1279cdf0e10cSrcweir 1280cdf0e10cSrcweir bool DrawShape::revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer ) 1281cdf0e10cSrcweir { 1282cdf0e10cSrcweir if( !mpAttributeLayer ) 1283cdf0e10cSrcweir return false; // no layers 1284cdf0e10cSrcweir 1285cdf0e10cSrcweir if( mpAttributeLayer == rLayer ) 1286cdf0e10cSrcweir { 1287cdf0e10cSrcweir // it's the toplevel layer 1288cdf0e10cSrcweir mpAttributeLayer = mpAttributeLayer->getChildLayer(); 1289cdf0e10cSrcweir 1290cdf0e10cSrcweir // force content redraw, all state variables have 1291cdf0e10cSrcweir // possibly changed 1292cdf0e10cSrcweir mbAttributeLayerRevoked = true; 1293cdf0e10cSrcweir 1294cdf0e10cSrcweir return true; 1295cdf0e10cSrcweir } 1296cdf0e10cSrcweir else 1297cdf0e10cSrcweir { 1298cdf0e10cSrcweir // pass on to the layer, to try its children 1299cdf0e10cSrcweir return mpAttributeLayer->revokeChildLayer( rLayer ); 1300cdf0e10cSrcweir } 1301cdf0e10cSrcweir } 1302cdf0e10cSrcweir 1303cdf0e10cSrcweir ShapeAttributeLayerSharedPtr DrawShape::getTopmostAttributeLayer() const 1304cdf0e10cSrcweir { 1305cdf0e10cSrcweir return mpAttributeLayer; 1306cdf0e10cSrcweir } 1307cdf0e10cSrcweir 1308cdf0e10cSrcweir void DrawShape::setVisibility( bool bVisible ) 1309cdf0e10cSrcweir { 1310cdf0e10cSrcweir if( mbIsVisible != bVisible ) 1311cdf0e10cSrcweir { 1312cdf0e10cSrcweir mbIsVisible = bVisible; 1313cdf0e10cSrcweir mbForceUpdate = true; 1314cdf0e10cSrcweir } 1315cdf0e10cSrcweir } 1316cdf0e10cSrcweir 1317cdf0e10cSrcweir const DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() const 1318cdf0e10cSrcweir { 1319cdf0e10cSrcweir return *this; 1320cdf0e10cSrcweir } 1321cdf0e10cSrcweir 1322cdf0e10cSrcweir DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() 1323cdf0e10cSrcweir { 1324cdf0e10cSrcweir return *this; 1325cdf0e10cSrcweir } 1326cdf0e10cSrcweir 1327cdf0e10cSrcweir DocTreeNode DrawShape::getSubsetNode() const 1328cdf0e10cSrcweir { 1329cdf0e10cSrcweir ensureVerboseMtfComments(); 1330cdf0e10cSrcweir 1331cdf0e10cSrcweir // forward to delegate 1332cdf0e10cSrcweir return maSubsetting.getSubsetNode(); 1333cdf0e10cSrcweir } 1334cdf0e10cSrcweir 1335cdf0e10cSrcweir AttributableShapeSharedPtr DrawShape::getSubset( const DocTreeNode& rTreeNode ) const 1336cdf0e10cSrcweir { 1337cdf0e10cSrcweir ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0, 1338cdf0e10cSrcweir "DrawShape::getSubset(): subset query on shape with apparently no subsets" ); 1339cdf0e10cSrcweir 1340cdf0e10cSrcweir // forward to delegate 1341cdf0e10cSrcweir return maSubsetting.getSubsetShape( rTreeNode ); 1342cdf0e10cSrcweir } 1343cdf0e10cSrcweir 1344cdf0e10cSrcweir bool DrawShape::createSubset( AttributableShapeSharedPtr& o_rSubset, 1345cdf0e10cSrcweir const DocTreeNode& rTreeNode ) 1346cdf0e10cSrcweir { 1347cdf0e10cSrcweir ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0, 1348cdf0e10cSrcweir "DrawShape::createSubset(): subset query on shape with apparently no subsets" ); 1349cdf0e10cSrcweir 1350cdf0e10cSrcweir // subset shape already created for this DocTreeNode? 1351cdf0e10cSrcweir AttributableShapeSharedPtr pSubset( maSubsetting.getSubsetShape( rTreeNode ) ); 1352cdf0e10cSrcweir 1353cdf0e10cSrcweir // when true, this method has created a new subset 1354cdf0e10cSrcweir // DrawShape 1355cdf0e10cSrcweir bool bNewlyCreated( false ); 1356cdf0e10cSrcweir 1357cdf0e10cSrcweir if( pSubset ) 1358cdf0e10cSrcweir { 1359cdf0e10cSrcweir o_rSubset = pSubset; 1360cdf0e10cSrcweir 1361cdf0e10cSrcweir // reusing existing subset 1362cdf0e10cSrcweir } 1363cdf0e10cSrcweir else 1364cdf0e10cSrcweir { 1365cdf0e10cSrcweir // not yet created, init entry 1366cdf0e10cSrcweir o_rSubset.reset( new DrawShape( *this, 1367cdf0e10cSrcweir rTreeNode, 1368cdf0e10cSrcweir // TODO(Q3): That's a 1369cdf0e10cSrcweir // hack. We assume 1370cdf0e10cSrcweir // that start and end 1371cdf0e10cSrcweir // index will always 1372cdf0e10cSrcweir // be less than 65535 1373cdf0e10cSrcweir mnPriority + 1374cdf0e10cSrcweir rTreeNode.getStartIndex()/double(SAL_MAX_INT16) )); 1375cdf0e10cSrcweir 1376cdf0e10cSrcweir bNewlyCreated = true; // subset newly created 1377cdf0e10cSrcweir } 1378cdf0e10cSrcweir 1379cdf0e10cSrcweir // always register shape at DrawShapeSubsetting, to keep 1380cdf0e10cSrcweir // refcount up-to-date 1381cdf0e10cSrcweir maSubsetting.addSubsetShape( o_rSubset ); 1382cdf0e10cSrcweir 1383cdf0e10cSrcweir // flush bounds cache 1384cdf0e10cSrcweir maCurrentShapeUnitBounds.reset(); 1385cdf0e10cSrcweir 1386cdf0e10cSrcweir return bNewlyCreated; 1387cdf0e10cSrcweir } 1388cdf0e10cSrcweir 1389cdf0e10cSrcweir bool DrawShape::revokeSubset( const AttributableShapeSharedPtr& rShape ) 1390cdf0e10cSrcweir { 1391cdf0e10cSrcweir ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0, 1392cdf0e10cSrcweir "DrawShape::createSubset(): subset query on shape with apparently no subsets" ); 1393cdf0e10cSrcweir 1394cdf0e10cSrcweir // flush bounds cache 1395cdf0e10cSrcweir maCurrentShapeUnitBounds.reset(); 1396cdf0e10cSrcweir 1397cdf0e10cSrcweir // forward to delegate 1398cdf0e10cSrcweir if( maSubsetting.revokeSubsetShape( rShape ) ) 1399cdf0e10cSrcweir { 1400cdf0e10cSrcweir // force redraw, our content has possibly changed (as 1401cdf0e10cSrcweir // one of the subsets now display within our shape 1402cdf0e10cSrcweir // again). 1403cdf0e10cSrcweir mbForceUpdate = true; 1404cdf0e10cSrcweir 1405cdf0e10cSrcweir // #i47428# TEMP FIX: synchronize visibility of subset 1406cdf0e10cSrcweir // with parent. 1407cdf0e10cSrcweir 1408cdf0e10cSrcweir // TODO(F3): Remove here, and implement 1409cdf0e10cSrcweir // TEXT_ONLY/BACKGROUND_ONLY with the proverbial 1410cdf0e10cSrcweir // additional level of indirection: create a 1411cdf0e10cSrcweir // persistent subset, containing all text/only the 1412cdf0e10cSrcweir // background respectively. From _that_ object, 1413cdf0e10cSrcweir // generate the temporary character subset shapes. 1414cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& rAttrLayer( 1415cdf0e10cSrcweir rShape->getTopmostAttributeLayer() ); 1416cdf0e10cSrcweir if( rAttrLayer && 1417cdf0e10cSrcweir rAttrLayer->isVisibilityValid() && 1418cdf0e10cSrcweir rAttrLayer->getVisibility() != isVisible() ) 1419cdf0e10cSrcweir { 1420cdf0e10cSrcweir const bool bVisibility( rAttrLayer->getVisibility() ); 1421cdf0e10cSrcweir 1422cdf0e10cSrcweir // visibilities differ - adjust ours, then 1423cdf0e10cSrcweir if( mpAttributeLayer ) 1424cdf0e10cSrcweir mpAttributeLayer->setVisibility( bVisibility ); 1425cdf0e10cSrcweir else 1426cdf0e10cSrcweir mbIsVisible = bVisibility; 1427cdf0e10cSrcweir } 1428cdf0e10cSrcweir 1429cdf0e10cSrcweir // END TEMP FIX 1430cdf0e10cSrcweir 1431cdf0e10cSrcweir return true; 1432cdf0e10cSrcweir } 1433cdf0e10cSrcweir 1434cdf0e10cSrcweir return false; 1435cdf0e10cSrcweir } 1436cdf0e10cSrcweir 1437cdf0e10cSrcweir sal_Int32 DrawShape::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException 1438cdf0e10cSrcweir { 1439cdf0e10cSrcweir ensureVerboseMtfComments(); 1440cdf0e10cSrcweir 1441cdf0e10cSrcweir return maSubsetting.getNumberOfTreeNodes( eNodeType ); 1442cdf0e10cSrcweir } 1443cdf0e10cSrcweir 1444cdf0e10cSrcweir DocTreeNode DrawShape::getTreeNode( sal_Int32 nNodeIndex, 1445cdf0e10cSrcweir DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException 1446cdf0e10cSrcweir { 1447cdf0e10cSrcweir ensureVerboseMtfComments(); 1448cdf0e10cSrcweir 1449cdf0e10cSrcweir if ( hasHyperlinks()) 1450cdf0e10cSrcweir { 1451cdf0e10cSrcweir prepareHyperlinkIndices(); 1452cdf0e10cSrcweir } 1453cdf0e10cSrcweir 1454cdf0e10cSrcweir return maSubsetting.getTreeNode( nNodeIndex, eNodeType ); 1455cdf0e10cSrcweir } 1456cdf0e10cSrcweir 1457cdf0e10cSrcweir sal_Int32 DrawShape::getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode, 1458cdf0e10cSrcweir DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException 1459cdf0e10cSrcweir { 1460cdf0e10cSrcweir ensureVerboseMtfComments(); 1461cdf0e10cSrcweir 1462cdf0e10cSrcweir return maSubsetting.getNumberOfSubsetTreeNodes( rParentNode, eNodeType ); 1463cdf0e10cSrcweir } 1464cdf0e10cSrcweir 1465cdf0e10cSrcweir DocTreeNode DrawShape::getSubsetTreeNode( const DocTreeNode& rParentNode, 1466cdf0e10cSrcweir sal_Int32 nNodeIndex, 1467cdf0e10cSrcweir DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException 1468cdf0e10cSrcweir { 1469cdf0e10cSrcweir ensureVerboseMtfComments(); 1470cdf0e10cSrcweir 1471cdf0e10cSrcweir return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType ); 1472cdf0e10cSrcweir } 1473cdf0e10cSrcweir } 1474cdf0e10cSrcweir } 1475