LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/primitive2d - graphicprimitive2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 36 156 23.1 %
Date: 2012-12-27 Functions: 4 15 26.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
      21             : #include <drawinglayer/animation/animationtiming.hxx>
      22             : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
      23             : #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
      24             : #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
      25             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      26             : #include <basegfx/polygon/b2dpolygon.hxx>
      27             : #include <basegfx/polygon/b2dpolygontools.hxx>
      28             : #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
      29             : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
      30             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      31             : 
      32             : //////////////////////////////////////////////////////////////////////////////
      33             : // helper class for animated graphics
      34             : 
      35             : #include <vcl/animate.hxx>
      36             : #include <vcl/graph.hxx>
      37             : #include <vcl/virdev.hxx>
      38             : #include <vcl/svapp.hxx>
      39             : #include <vcl/metaact.hxx>
      40             : 
      41             : //////////////////////////////////////////////////////////////////////////////
      42             : // includes for testing MetafilePrimitive2D::create2DDecomposition
      43             : 
      44             : //////////////////////////////////////////////////////////////////////////////
      45             : 
      46             : namespace
      47             : {
      48           0 :     struct animationStep
      49             :     {
      50             :         BitmapEx                                maBitmapEx;
      51             :         sal_uInt32                              mnTime;
      52             :     };
      53             : 
      54           0 :     class animatedBitmapExPreparator
      55             :     {
      56             :         ::Animation                             maAnimation;
      57             :         ::std::vector< animationStep >          maSteps;
      58             : 
      59             :         sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
      60             : 
      61             :     public:
      62             :         explicit animatedBitmapExPreparator(const Graphic& rGraphic);
      63             : 
      64           0 :         sal_uInt32 count() const { return maSteps.size(); }
      65           0 :         sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
      66           0 :         sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
      67           0 :         const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
      68             :     };
      69             : 
      70           0 :     sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
      71             :     {
      72           0 :         const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
      73           0 :         sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);
      74             : 
      75             :         // #115934#
      76             :         // Take care of special value for MultiPage TIFFs. ATM these shall just
      77             :         // show their first page. Later we will offer some switching when object
      78             :         // is selected.
      79           0 :         if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
      80             :         {
      81             :             // ATM the huge value would block the timer, so
      82             :             // use a long time to show first page (whole day)
      83           0 :             nWaitTime = 100 * 60 * 60 * 24;
      84             :         }
      85             : 
      86             :         // Bad trap: There are animated gifs with no set WaitTime (!).
      87             :         // In that case use a default value.
      88           0 :         if(0L == nWaitTime)
      89             :         {
      90           0 :             nWaitTime = 100L;
      91             :         }
      92             : 
      93           0 :         return nWaitTime;
      94             :     }
      95             : 
      96           0 :     animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
      97           0 :     :   maAnimation(rGraphic.GetAnimation())
      98             :     {
      99             :         OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
     100             : 
     101             :         // #128539# secure access to Animation, looks like there exist animated GIFs out there
     102             :         // with a step count of zero
     103           0 :         if(maAnimation.Count())
     104             :         {
     105           0 :             VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
     106           0 :             VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
     107             : 
     108             :             // Prepare VirtualDevices and their states
     109           0 :             aVirtualDevice.EnableMapMode(sal_False);
     110           0 :             aVirtualDeviceMask.EnableMapMode(sal_False);
     111           0 :             aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
     112           0 :             aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
     113           0 :             aVirtualDevice.Erase();
     114           0 :             aVirtualDeviceMask.Erase();
     115             : 
     116           0 :             for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
     117             :             {
     118           0 :                 animationStep aNextStep;
     119           0 :                 aNextStep.mnTime = generateStepTime(a);
     120             : 
     121             :                 // prepare step
     122           0 :                 const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
     123             : 
     124           0 :                 switch(rAnimBitmap.eDisposal)
     125             :                 {
     126             :                     case DISPOSE_NOT:
     127             :                     {
     128           0 :                         aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
     129           0 :                         Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
     130             : 
     131           0 :                         if(aMask.IsEmpty())
     132             :                         {
     133           0 :                             const Point aEmpty;
     134           0 :                             const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
     135           0 :                             const Wallpaper aWallpaper(COL_BLACK);
     136           0 :                             aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
     137             :                         }
     138             :                         else
     139             :                         {
     140           0 :                             BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
     141           0 :                             aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
     142             :                         }
     143             : 
     144           0 :                         break;
     145             :                     }
     146             :                     case DISPOSE_BACK:
     147             :                     {
     148             :                         // #i70772# react on no mask, for primitives, too.
     149           0 :                         const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
     150           0 :                         const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());
     151             : 
     152           0 :                         aVirtualDeviceMask.Erase();
     153           0 :                         aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);
     154             : 
     155           0 :                         if(aMask.IsEmpty())
     156             :                         {
     157           0 :                             const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
     158           0 :                             aVirtualDeviceMask.SetFillColor(COL_BLACK);
     159           0 :                             aVirtualDeviceMask.SetLineColor();
     160           0 :                             aVirtualDeviceMask.DrawRect(aRect);
     161             :                         }
     162             :                         else
     163             :                         {
     164           0 :                             aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
     165             :                         }
     166             : 
     167           0 :                         break;
     168             :                     }
     169             :                     case DISPOSE_FULL:
     170             :                     {
     171           0 :                         aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
     172           0 :                         break;
     173             :                     }
     174             :                     case DISPOSE_PREVIOUS :
     175             :                     {
     176           0 :                         aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
     177           0 :                         aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
     178           0 :                         break;
     179             :                     }
     180             :                 }
     181             : 
     182             :                 // create BitmapEx
     183           0 :                 Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
     184           0 :                 Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel());
     185           0 :                 aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
     186             : 
     187             :                 // add to vector
     188           0 :                 maSteps.push_back(aNextStep);
     189           0 :             }
     190             :         }
     191           0 :     }
     192             : } // end of anonymous namespace
     193             : 
     194             : //////////////////////////////////////////////////////////////////////////////
     195             : 
     196             : namespace drawinglayer
     197             : {
     198             :     namespace primitive2d
     199             :     {
     200           8 :         Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&
     201             :             ) const
     202             :         {
     203           8 :             Primitive2DSequence aRetval;
     204             : 
     205           8 :             if(255L != getGraphicAttr().GetTransparency())
     206             :             {
     207           8 :                 Primitive2DReference xPrimitive;
     208             : 
     209             :                 // do not apply mirroring from GraphicAttr to the Metafile by calling
     210             :                 // GetTransformedGraphic, this will try to mirror the Metafile using Scale()
     211             :                 // at the Metafile. This again calls Scale at the single MetaFile actions,
     212             :                 // but this implementation never worked. I reworked that implementations,
     213             :                 // but for security reasons i will try not to use it.
     214           8 :                 basegfx::B2DHomMatrix aTransform(getTransform());
     215             : 
     216           8 :                 if(getGraphicAttr().IsMirrored())
     217             :                 {
     218             :                     // content needs mirroring
     219           0 :                     const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ);
     220           0 :                     const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT);
     221             : 
     222             :                     // mirror by applying negative scale to the unit primitive and
     223             :                     // applying the object transformation on it.
     224             :                     aTransform = basegfx::tools::createScaleB2DHomMatrix(
     225             :                         bHMirr ? -1.0 : 1.0,
     226           0 :                         bVMirr ? -1.0 : 1.0);
     227             :                     aTransform.translate(
     228             :                         bHMirr ? 1.0 : 0.0,
     229           0 :                         bVMirr ? 1.0 : 0.0);
     230           0 :                     aTransform = getTransform() * aTransform;
     231             :                 }
     232             : 
     233             :                 // Get transformed graphic. Suppress rotation and cropping, only filtering is needed
     234             :                 // here (and may be replaced later on). Cropping is handled below as mask primitive (if set).
     235             :                 // Also need to suppress mirroring, it is part of the transformation now (see above).
     236           8 :                 GraphicAttr aSuppressGraphicAttr(getGraphicAttr());
     237           8 :                 aSuppressGraphicAttr.SetCrop(0, 0, 0, 0);
     238           8 :                 aSuppressGraphicAttr.SetRotation(0);
     239           8 :                 aSuppressGraphicAttr.SetMirrorFlags(0);
     240             : 
     241           8 :                 const GraphicObject& rGraphicObject = getGraphicObject();
     242           8 :                 const Graphic aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr));
     243             : 
     244           8 :                 switch(aTransformedGraphic.GetType())
     245             :                 {
     246             :                     case GRAPHIC_BITMAP :
     247             :                     {
     248           7 :                         if(aTransformedGraphic.IsAnimated())
     249             :                         {
     250             :                             // prepare animation data
     251           0 :                             animatedBitmapExPreparator aData(aTransformedGraphic);
     252             : 
     253           0 :                             if(aData.count())
     254             :                             {
     255             :                                 // create sub-primitives for animated bitmap and the needed animation loop
     256           0 :                                 animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
     257           0 :                                 Primitive2DSequence aBitmapPrimitives(aData.count());
     258             : 
     259           0 :                                 for(sal_uInt32 a(0L); a < aData.count(); a++)
     260             :                                 {
     261           0 :                                     animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
     262           0 :                                     aAnimationLoop.append(aTime);
     263           0 :                                     const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform));
     264           0 :                                     aBitmapPrimitives[a] = xRef;
     265           0 :                                 }
     266             : 
     267             :                                 // prepare animation list
     268           0 :                                 animation::AnimationEntryList aAnimationList;
     269           0 :                                 aAnimationList.append(aAnimationLoop);
     270             : 
     271             :                                 // create and add animated switch primitive
     272           0 :                                 xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false));
     273           0 :                             }
     274             :                         }
     275           7 :                         else if(aTransformedGraphic.getSvgData().get())
     276             :                         {
     277             :                             // embedded Svg fill, create embed transform
     278           0 :                             const basegfx::B2DRange& rSvgRange(aTransformedGraphic.getSvgData()->getRange());
     279             : 
     280           0 :                             if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
     281             :                             {
     282             :                                 // translate back to origin, scale to unit coordinates
     283             :                                 basegfx::B2DHomMatrix aEmbedSvg(
     284             :                                     basegfx::tools::createTranslateB2DHomMatrix(
     285           0 :                                         -rSvgRange.getMinX(),
     286           0 :                                         -rSvgRange.getMinY()));
     287             : 
     288             :                                 aEmbedSvg.scale(
     289           0 :                                     1.0 / rSvgRange.getWidth(),
     290           0 :                                     1.0 / rSvgRange.getHeight());
     291             : 
     292             :                                 // apply created object transformation
     293           0 :                                 aEmbedSvg = aTransform * aEmbedSvg;
     294             : 
     295             :                                 // add Svg primitives embedded
     296             :                                 xPrimitive = new TransformPrimitive2D(
     297             :                                     aEmbedSvg,
     298           0 :                                     aTransformedGraphic.getSvgData()->getPrimitive2DSequence());
     299             :                             }
     300             :                         }
     301             :                         else
     302             :                         {
     303           7 :                             xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform));
     304             :                         }
     305             : 
     306           7 :                         break;
     307             :                     }
     308             : 
     309             :                     case GRAPHIC_GDIMETAFILE :
     310             :                     {
     311             :                         // create MetafilePrimitive2D
     312           1 :                         const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
     313             : 
     314             :                         xPrimitive = Primitive2DReference(
     315           1 :                                         new MetafilePrimitive2D( aTransform, rMetafile ) );
     316             : 
     317             :                         // #i100357# find out if clipping is needed for this primitive. Unfortunately,
     318             :                         // there exist Metafiles who's content is bigger than the proposed PrefSize set
     319             :                         // at them. This is an error, but we need to work around this
     320           1 :                         const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
     321             :                         const Size aMetaFileRealSize(
     322             :                                 const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
     323           1 :                                         *Application::GetDefaultDevice()).GetSize());
     324             : 
     325           2 :                         if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
     326           1 :                            || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
     327             :                         {
     328             :                             // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
     329           0 :                             const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1);
     330           0 :                             basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
     331           0 :                             aMaskPolygon.transform(aTransform);
     332             : 
     333             :                             xPrimitive = Primitive2DReference(
     334             :                                     new MaskPrimitive2D(
     335             :                                         basegfx::B2DPolyPolygon(aMaskPolygon),
     336           0 :                                         aChildContent));
     337             :                         }
     338             :                         break;
     339             :                     }
     340             : 
     341             :                     default:
     342             :                     {
     343             :                         // nothing to create
     344           0 :                         break;
     345             :                     }
     346             :                 }
     347             : 
     348           8 :                 if(xPrimitive.is())
     349             :                 {
     350             :                     // check for cropping
     351           8 :                     if(getGraphicAttr().IsCropped())
     352             :                     {
     353             :                         // calculate scalings between real image size and logic object size. This
     354             :                         // is necessary since the crop values are relative to original bitmap size
     355           0 :                         double fFactorX(1.0);
     356           0 :                         double fFactorY(1.0);
     357             : 
     358             :                         {
     359           0 :                             const MapMode aMapMode100thmm(MAP_100TH_MM);
     360           0 :                             Size aBitmapSize(rGraphicObject.GetPrefSize());
     361             : 
     362             :                             // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
     363           0 :                             if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit())
     364             :                             {
     365           0 :                                 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
     366             :                             }
     367             :                             else
     368             :                             {
     369           0 :                                 aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
     370             :                             }
     371             : 
     372           0 :                             const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
     373           0 :                             const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
     374           0 :                             const basegfx::B2DVector aScale(aTransform * basegfx::B2DVector(1.0, 1.0));
     375             : 
     376           0 :                             if(!basegfx::fTools::equalZero(fDivX))
     377             :                             {
     378           0 :                                 fFactorX = fabs(aScale.getX()) / fDivX;
     379             :                             }
     380             : 
     381           0 :                             if(!basegfx::fTools::equalZero(fDivY))
     382             :                             {
     383           0 :                                 fFactorY = fabs(aScale.getY()) / fDivY;
     384           0 :                             }
     385             :                         }
     386             : 
     387             :                         // embed content in cropPrimitive
     388             :                         xPrimitive = new CropPrimitive2D(
     389             :                             Primitive2DSequence(&xPrimitive, 1),
     390             :                             aTransform,
     391           0 :                             getGraphicAttr().GetLeftCrop() * fFactorX,
     392           0 :                             getGraphicAttr().GetTopCrop() * fFactorY,
     393           0 :                             getGraphicAttr().GetRightCrop() * fFactorX,
     394           0 :                             getGraphicAttr().GetBottomCrop() * fFactorY);
     395             :                     }
     396             : 
     397             :                     // add to decomposition
     398           8 :                     appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive);
     399           8 :                 }
     400             :             }
     401             : 
     402           8 :             return aRetval;
     403             :         }
     404             : 
     405          35 :         GraphicPrimitive2D::GraphicPrimitive2D(
     406             :             const basegfx::B2DHomMatrix& rTransform,
     407             :             const GraphicObject& rGraphicObject,
     408             :             const GraphicAttr& rGraphicAttr)
     409             :         :   BufferedDecompositionPrimitive2D(),
     410             :             maTransform(rTransform),
     411             :             maGraphicObject(rGraphicObject),
     412          35 :             maGraphicAttr(rGraphicAttr)
     413             :         {
     414          35 :         }
     415             : 
     416           0 :         bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     417             :         {
     418           0 :             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
     419             :             {
     420           0 :                 const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
     421             : 
     422           0 :                 return (getTransform() == rCompare.getTransform()
     423           0 :                     && getGraphicObject() == rCompare.getGraphicObject()
     424           0 :                     && getGraphicAttr() == rCompare.getGraphicAttr());
     425             :             }
     426             : 
     427           0 :             return false;
     428             :         }
     429             : 
     430          59 :         basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
     431             :         {
     432          59 :             basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
     433          59 :             aRetval.transform(getTransform());
     434          59 :             return aRetval;
     435             :         }
     436             : 
     437             :         // provide unique ID
     438          16 :         ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
     439             : 
     440             :     } // end of namespace primitive2d
     441             : } // end of namespace drawinglayer
     442             : 
     443             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10