LCOV - code coverage report
Current view: top level - vcl/source/gdi - gdimetafiletools.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 61 395 15.4 %
Date: 2015-06-13 12:38:46 Functions: 2 7 28.6 %
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 <vcl/gdimetafiletools.hxx>
      21             : #include <vcl/metaact.hxx>
      22             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      23             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      24             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      25             : #include <basegfx/polygon/b2dpolygontools.hxx>
      26             : #include <vcl/virdev.hxx>
      27             : #include <vcl/svapp.hxx>
      28             : #include <vcl/graphictools.hxx>
      29             : 
      30             : // helpers
      31             : 
      32             : namespace
      33             : {
      34           0 :     bool handleGeometricContent(
      35             :         const basegfx::B2DPolyPolygon& rClip,
      36             :         const basegfx::B2DPolyPolygon& rSource,
      37             :         GDIMetaFile& rTarget,
      38             :         bool bStroke)
      39             :     {
      40           0 :         if(rSource.count() && rClip.count())
      41             :         {
      42             :             const basegfx::B2DPolyPolygon aResult(
      43             :                 basegfx::tools::clipPolyPolygonOnPolyPolygon(
      44             :                     rSource,
      45             :                     rClip,
      46             :                     true, // inside
      47           0 :                     bStroke));
      48             : 
      49           0 :             if(aResult.count())
      50             :             {
      51           0 :                 if(aResult == rSource)
      52             :                 {
      53             :                     // not clipped, but inside. Add original
      54           0 :                     return false;
      55             :                 }
      56             :                 else
      57             :                 {
      58             :                     // add clipped geometry
      59           0 :                     if(bStroke)
      60             :                     {
      61           0 :                         for(sal_uInt32 a(0); a < aResult.count(); a++)
      62             :                         {
      63             :                             rTarget.AddAction(
      64             :                                 new MetaPolyLineAction(
      65           0 :                                     Polygon(aResult.getB2DPolygon(a))));
      66             :                         }
      67             :                     }
      68             :                     else
      69             :                     {
      70             :                         rTarget.AddAction(
      71             :                             new MetaPolyPolygonAction(
      72           0 :                                 tools::PolyPolygon(aResult)));
      73             :                     }
      74             :                 }
      75           0 :             }
      76             :         }
      77             : 
      78           0 :         return true;
      79             :     }
      80             : 
      81           0 :     bool handleGradientContent(
      82             :         const basegfx::B2DPolyPolygon& rClip,
      83             :         const basegfx::B2DPolyPolygon& rSource,
      84             :         const Gradient& rGradient,
      85             :         GDIMetaFile& rTarget)
      86             :     {
      87           0 :         if(rSource.count() && rClip.count())
      88             :         {
      89             :             const basegfx::B2DPolyPolygon aResult(
      90             :                 basegfx::tools::clipPolyPolygonOnPolyPolygon(
      91             :                     rSource,
      92             :                     rClip,
      93             :                     true, // inside
      94           0 :                     false)); // stroke
      95             : 
      96           0 :             if(aResult.count())
      97             :             {
      98           0 :                 if(aResult == rSource)
      99             :                 {
     100             :                     // not clipped, but inside. Add original
     101           0 :                     return false;
     102             :                 }
     103             :                 else
     104             :                 {
     105             :                     // add clipped geometry
     106             :                     rTarget.AddAction(
     107             :                         new MetaGradientExAction(
     108             :                             tools::PolyPolygon(aResult),
     109           0 :                             rGradient));
     110             :                 }
     111           0 :             }
     112             :         }
     113             : 
     114           0 :         return true;
     115             :     }
     116             : 
     117           0 :     bool handleBitmapContent(
     118             :         const basegfx::B2DPolyPolygon& rClip,
     119             :         const Point& rPoint,
     120             :         const Size& rSize,
     121             :         const BitmapEx& rBitmapEx,
     122             :         GDIMetaFile& rTarget)
     123             :     {
     124           0 :         if(!rSize.Width() || !rSize.Height() || rBitmapEx.IsEmpty())
     125             :         {
     126             :             // bitmap or size is empty
     127           0 :             return true;
     128             :         }
     129             : 
     130             :         const basegfx::B2DRange aLogicBitmapRange(
     131           0 :             rPoint.X(), rPoint.Y(),
     132           0 :             rPoint.X() + rSize.Width(), rPoint.Y() + rSize.Height());
     133             :         const basegfx::B2DPolyPolygon aClipOfBitmap(
     134             :             basegfx::tools::clipPolyPolygonOnRange(
     135             :                 rClip,
     136             :                 aLogicBitmapRange,
     137             :                 true,
     138           0 :                 false)); // stroke
     139             : 
     140           0 :         if(!aClipOfBitmap.count())
     141             :         {
     142             :             // outside clip region
     143           0 :             return true;
     144             :         }
     145             : 
     146             :         // inside or overlapping. Use area to find out if it is completely
     147             :         // covering (inside) or overlapping
     148           0 :         const double fClipArea(basegfx::tools::getArea(aClipOfBitmap));
     149             :         const double fBitmapArea(
     150           0 :             aLogicBitmapRange.getWidth() * aLogicBitmapRange.getWidth() +
     151           0 :             aLogicBitmapRange.getHeight() * aLogicBitmapRange.getHeight());
     152           0 :         const double fFactor(fClipArea / fBitmapArea);
     153             : 
     154           0 :         if(basegfx::fTools::more(fFactor, 1.0 - 0.001))
     155             :         {
     156             :             // completely covering (with 0.1% tolerance)
     157           0 :             return false;
     158             :         }
     159             : 
     160             :         // needs clipping (with 0.1% tolerance). Prepare VirtualDevice
     161             :         // in pixel mode for alpha channel painting (black is transparent,
     162             :         // white to paint 100% opacity)
     163           0 :         const Size aSizePixel(rBitmapEx.GetSizePixel());
     164           0 :         ScopedVclPtrInstance< VirtualDevice > aVDev;
     165             : 
     166           0 :         aVDev->SetOutputSizePixel(aSizePixel);
     167           0 :         aVDev->EnableMapMode(false);
     168           0 :         aVDev->SetFillColor(COL_WHITE);
     169           0 :         aVDev->SetLineColor();
     170             : 
     171           0 :         if(rBitmapEx.IsTransparent())
     172             :         {
     173             :             // use given alpha channel
     174           0 :             aVDev->DrawBitmap(Point(0, 0), rBitmapEx.GetAlpha().GetBitmap());
     175             :         }
     176             :         else
     177             :         {
     178             :             // reset alpha channel
     179           0 :             aVDev->SetBackground(Wallpaper(Color(COL_BLACK)));
     180           0 :             aVDev->Erase();
     181             :         }
     182             : 
     183             :         // transform polygon from clipping to pixel coordinates
     184           0 :         basegfx::B2DPolyPolygon aPixelPoly(aClipOfBitmap);
     185           0 :         basegfx::B2DHomMatrix aTransform;
     186             : 
     187           0 :         aTransform.translate(-aLogicBitmapRange.getMinX(), -aLogicBitmapRange.getMinY());
     188             :         aTransform.scale(
     189           0 :             static_cast< double >(aSizePixel.Width()) / aLogicBitmapRange.getWidth(),
     190           0 :             static_cast< double >(aSizePixel.Height()) / aLogicBitmapRange.getHeight());
     191           0 :         aPixelPoly.transform(aTransform);
     192             : 
     193             :         // to fill the non-covered parts, use the Xor fill rule of
     194             :         // tools::PolyPolygon painting. Start with a all-covering polygon and
     195             :         // add the clip polygon one
     196           0 :         basegfx::B2DPolyPolygon aInvertPixelPoly;
     197             : 
     198             :         aInvertPixelPoly.append(
     199             :             basegfx::tools::createPolygonFromRect(
     200             :                 basegfx::B2DRange(
     201             :                     0.0, 0.0,
     202           0 :                     aSizePixel.Width(), aSizePixel.Height())));
     203           0 :         aInvertPixelPoly.append(aPixelPoly);
     204             : 
     205             :         // paint as alpha
     206           0 :         aVDev->DrawPolyPolygon(aInvertPixelPoly);
     207             : 
     208             :         // get created alpha mask and set defaults
     209             :         AlphaMask aAlpha(
     210           0 :             aVDev->GetBitmap(
     211             :                 Point(0, 0),
     212           0 :                 aSizePixel));
     213             : 
     214           0 :         aAlpha.SetPrefSize(rBitmapEx.GetPrefSize());
     215           0 :         aAlpha.SetPrefMapMode(rBitmapEx.GetPrefMapMode());
     216             : 
     217             :         // add new action replacing the old one
     218             :         rTarget.AddAction(
     219             :             new MetaBmpExScaleAction(
     220             :                 Point(
     221           0 :                     basegfx::fround(aLogicBitmapRange.getMinX()),
     222           0 :                     basegfx::fround(aLogicBitmapRange.getMinY())),
     223             :                 Size(
     224           0 :                     basegfx::fround(aLogicBitmapRange.getWidth()),
     225           0 :                     basegfx::fround(aLogicBitmapRange.getHeight())),
     226           0 :                 BitmapEx(rBitmapEx.GetBitmap(), aAlpha)));
     227             : 
     228           0 :         return true;
     229             :     }
     230             : 
     231           0 :     void addSvtGraphicStroke(const SvtGraphicStroke& rStroke, GDIMetaFile& rTarget)
     232             :     {
     233             :         // write SvtGraphicFill
     234           0 :         SvMemoryStream aMemStm;
     235           0 :         WriteSvtGraphicStroke( aMemStm, rStroke );
     236             :         rTarget.AddAction(
     237             :             new MetaCommentAction(
     238             :                 "XPATHSTROKE_SEQ_BEGIN",
     239             :                 0,
     240             :                 static_cast< const sal_uInt8* >(aMemStm.GetData()),
     241           0 :                 aMemStm.Seek(STREAM_SEEK_TO_END)));
     242           0 :     }
     243             : 
     244           0 :     void addSvtGraphicFill(const SvtGraphicFill &rFilling, GDIMetaFile& rTarget)
     245             :     {
     246             :         // write SvtGraphicFill
     247           0 :         SvMemoryStream aMemStm;
     248           0 :         WriteSvtGraphicFill( aMemStm, rFilling );
     249             :         rTarget.AddAction(
     250             :             new MetaCommentAction(
     251             :                 "XPATHFILL_SEQ_BEGIN",
     252             :                 0,
     253             :                 static_cast< const sal_uInt8* >(aMemStm.GetData()),
     254           0 :                 aMemStm.Seek(STREAM_SEEK_TO_END)));
     255           0 :     }
     256             : } // end of anonymous namespace
     257             : 
     258             : // #i121267# Tooling to internally clip geometry against internal clip regions
     259             : 
     260          38 : void clipMetafileContentAgainstOwnRegions(GDIMetaFile& rSource)
     261             : {
     262          38 :     const sal_uLong nObjCount(rSource.GetActionSize());
     263             : 
     264          38 :     if(!nObjCount)
     265             :     {
     266          38 :         return;
     267             :     }
     268             : 
     269             :     // prepare target data container and push/pop stack data
     270          38 :     GDIMetaFile aTarget;
     271          38 :     bool bChanged(false);
     272          76 :     std::vector< basegfx::B2DPolyPolygon > aClips;
     273          76 :     std::vector< PushFlags > aPushFlags;
     274          76 :     std::vector< MapMode > aMapModes;
     275             : 
     276             :     // start with empty region
     277          38 :     aClips.push_back(basegfx::B2DPolyPolygon());
     278             : 
     279             :     // start with default MapMode (MAP_PIXEL)
     280          38 :     aMapModes.push_back(MapMode());
     281             : 
     282        4013 :     for(sal_uLong i(0); i < nObjCount; ++i)
     283             :     {
     284        3975 :         const MetaAction* pAction(rSource.GetAction(i));
     285        3975 :         const MetaActionType nType(pAction->GetType());
     286        3975 :         bool bDone(false);
     287             : 
     288             :         // basic operation takes care of clipregion actions (four) and push/pop of these
     289             :         // to steer the currently set clip region. There *is* an active
     290             :         // clip region when (aClips.size() && aClips.back().count()), see
     291             :         // below
     292        3975 :         switch(nType)
     293             :         {
     294             :             case MetaActionType::CLIPREGION :
     295             :             {
     296           0 :                 const MetaClipRegionAction* pA = static_cast< const MetaClipRegionAction* >(pAction);
     297             : 
     298           0 :                 if(pA->IsClipping())
     299             :                 {
     300           0 :                     const vcl::Region& rRegion = pA->GetRegion();
     301           0 :                     const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
     302             : 
     303           0 :                     aClips.back() = aNewClip;
     304             :                 }
     305             :                 else
     306             :                 {
     307           0 :                     aClips.back() = basegfx::B2DPolyPolygon();
     308             :                 }
     309             : 
     310           0 :                 break;
     311             :             }
     312             : 
     313             :             case MetaActionType::ISECTRECTCLIPREGION :
     314             :             {
     315          45 :                 const MetaISectRectClipRegionAction* pA = static_cast< const MetaISectRectClipRegionAction* >(pAction);
     316          45 :                 const Rectangle& rRect = pA->GetRect();
     317             : 
     318          45 :                 if(!rRect.IsEmpty() && aClips.size() && aClips.back().count())
     319             :                 {
     320             :                     const basegfx::B2DRange aClipRange(
     321           0 :                         rRect.Left(), rRect.Top(),
     322           0 :                         rRect.Right(), rRect.Bottom());
     323             : 
     324           0 :                     aClips.back() = basegfx::tools::clipPolyPolygonOnRange(
     325           0 :                         aClips.back(),
     326             :                         aClipRange,
     327             :                         true, // inside
     328           0 :                         false); // stroke
     329             :                 }
     330          45 :                 break;
     331             :             }
     332             : 
     333             :             case MetaActionType::ISECTREGIONCLIPREGION :
     334             :             {
     335           7 :                 const MetaISectRegionClipRegionAction* pA = static_cast< const MetaISectRegionClipRegionAction* >(pAction);
     336           7 :                 const vcl::Region& rRegion = pA->GetRegion();
     337             : 
     338           7 :                 if(!rRegion.IsEmpty() && aClips.size() && aClips.back().count())
     339             :                 {
     340           0 :                     const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
     341             : 
     342           0 :                     aClips.back() = basegfx::tools::clipPolyPolygonOnPolyPolygon(
     343           0 :                         aClips.back(),
     344             :                         aNewClip,
     345             :                         true,  // inside
     346           0 :                         false); // stroke
     347             :                 }
     348           7 :                 break;
     349             :             }
     350             : 
     351             :             case MetaActionType::MOVECLIPREGION :
     352             :             {
     353           0 :                 const MetaMoveClipRegionAction* pA = static_cast< const MetaMoveClipRegionAction* >(pAction);
     354           0 :                 const long aHorMove(pA->GetHorzMove());
     355           0 :                 const long aVerMove(pA->GetVertMove());
     356             : 
     357           0 :                 if((aHorMove || aVerMove) && aClips.size() && aClips.back().count())
     358             :                 {
     359           0 :                     aClips.back().transform(
     360             :                         basegfx::tools::createTranslateB2DHomMatrix(
     361             :                             aHorMove,
     362           0 :                             aVerMove));
     363             :                 }
     364           0 :                 break;
     365             :             }
     366             : 
     367             :             case MetaActionType::PUSH :
     368             :             {
     369         476 :                 const MetaPushAction* pA = static_cast< const MetaPushAction* >(pAction);
     370         476 :                 const PushFlags nFlags(pA->GetFlags());
     371             : 
     372         476 :                 aPushFlags.push_back(nFlags);
     373             : 
     374         476 :                 if(nFlags & PushFlags::CLIPREGION)
     375             :                 {
     376         103 :                     aClips.push_back(aClips.back());
     377             :                 }
     378             : 
     379         476 :                 if(nFlags & PushFlags::MAPMODE)
     380             :                 {
     381         401 :                     aMapModes.push_back(aMapModes.back());
     382             :                 }
     383         476 :                 break;
     384             :             }
     385             : 
     386             :             case MetaActionType::POP :
     387             :             {
     388             : 
     389         476 :                 if(aPushFlags.size())
     390             :                 {
     391         476 :                     const PushFlags nFlags(aPushFlags.back());
     392         476 :                     aPushFlags.pop_back();
     393             : 
     394         476 :                     if(nFlags & PushFlags::CLIPREGION)
     395             :                     {
     396         103 :                         if(aClips.size() > 1)
     397             :                         {
     398         103 :                             aClips.pop_back();
     399             :                         }
     400             :                         else
     401             :                         {
     402             :                             OSL_ENSURE(false, "Wrong POP() in ClipRegions (!)");
     403             :                         }
     404             :                     }
     405             : 
     406         476 :                     if(nFlags & PushFlags::MAPMODE)
     407             :                     {
     408         401 :                         if(aMapModes.size() > 1)
     409             :                         {
     410         401 :                             aMapModes.pop_back();
     411             :                         }
     412             :                         else
     413             :                         {
     414             :                             OSL_ENSURE(false, "Wrong POP() in MapModes (!)");
     415             :                         }
     416             :                     }
     417             :                 }
     418             :                 else
     419             :                 {
     420             :                     OSL_ENSURE(false, "Invalid pop() without push() (!)");
     421             :                 }
     422             : 
     423         476 :                 break;
     424             :             }
     425             : 
     426             :             case MetaActionType::MAPMODE :
     427             :             {
     428           6 :                 const MetaMapModeAction* pA = static_cast< const MetaMapModeAction* >(pAction);
     429             : 
     430           6 :                 aMapModes.back() = pA->GetMapMode();
     431           6 :                 break;
     432             :             }
     433             : 
     434             :             default:
     435             :             {
     436        2965 :                 break;
     437             :             }
     438             :         }
     439             : 
     440             :         // this area contains all actions which could potentially be clipped. Since
     441             :         // this tooling is only a fallback (see comments in header), only the needed
     442             :         // actions will be implemented. Extend using the pattern for the already
     443             :         // implemented actions.
     444        3975 :         if(aClips.size() && aClips.back().count())
     445             :         {
     446           0 :             switch(nType)
     447             :             {
     448             : 
     449             :                 // pixel actions, just check on inside
     450             : 
     451             :                 case MetaActionType::PIXEL :
     452             :                 {
     453           0 :                     const MetaPixelAction* pA = static_cast< const MetaPixelAction* >(pAction);
     454           0 :                     const Point& rPoint = pA->GetPoint();
     455             : 
     456           0 :                     if(!basegfx::tools::isInside(
     457           0 :                         aClips.back(),
     458           0 :                         basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
     459             :                     {
     460             :                         // when not inside, do not add original
     461           0 :                         bDone = true;
     462             :                     }
     463           0 :                     break;
     464             :                 }
     465             : 
     466             :                 case MetaActionType::POINT :
     467             :                 {
     468           0 :                     const MetaPointAction* pA = static_cast< const MetaPointAction* >(pAction);
     469           0 :                     const Point& rPoint = pA->GetPoint();
     470             : 
     471           0 :                     if(!basegfx::tools::isInside(
     472           0 :                         aClips.back(),
     473           0 :                         basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
     474             :                     {
     475             :                         // when not inside, do not add original
     476           0 :                         bDone = true;
     477             :                     }
     478           0 :                     break;
     479             :                 }
     480             : 
     481             :                 // geometry actions
     482             : 
     483             :                 case MetaActionType::LINE :
     484             :                 {
     485           0 :                     const MetaLineAction* pA = static_cast< const MetaLineAction* >(pAction);
     486           0 :                     const Point& rStart(pA->GetStartPoint());
     487           0 :                     const Point& rEnd(pA->GetEndPoint());
     488           0 :                     basegfx::B2DPolygon aLine;
     489             : 
     490           0 :                     aLine.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
     491           0 :                     aLine.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
     492             : 
     493             :                     bDone = handleGeometricContent(
     494           0 :                         aClips.back(),
     495             :                         basegfx::B2DPolyPolygon(aLine),
     496             :                         aTarget,
     497           0 :                         true); // stroke
     498           0 :                     break;
     499             :                 }
     500             : 
     501             :                 case MetaActionType::RECT :
     502             :                 {
     503           0 :                     const MetaRectAction* pA = static_cast< const MetaRectAction* >(pAction);
     504           0 :                     const Rectangle& rRect = pA->GetRect();
     505             : 
     506           0 :                     if(rRect.IsEmpty())
     507             :                     {
     508           0 :                         bDone = true;
     509             :                     }
     510             :                     else
     511             :                     {
     512             : 
     513             :                         bDone = handleGeometricContent(
     514           0 :                             aClips.back(),
     515             :                             basegfx::B2DPolyPolygon(
     516             :                                 basegfx::tools::createPolygonFromRect(
     517             :                                     basegfx::B2DRange(
     518           0 :                                         rRect.Left(), rRect.Top(),
     519           0 :                                         rRect.Right(), rRect.Bottom()))),
     520             :                             aTarget,
     521           0 :                             false); // stroke
     522             :                     }
     523           0 :                     break;
     524             :                 }
     525             : 
     526             :                 case MetaActionType::ROUNDRECT :
     527             :                 {
     528           0 :                     const MetaRoundRectAction* pA = static_cast< const MetaRoundRectAction* >(pAction);
     529           0 :                     const Rectangle& rRect = pA->GetRect();
     530             : 
     531           0 :                     if(rRect.IsEmpty())
     532             :                     {
     533           0 :                         bDone = true;
     534             :                     }
     535             :                     else
     536             :                     {
     537           0 :                         const sal_uInt32 nHor(pA->GetHorzRound());
     538           0 :                         const sal_uInt32 nVer(pA->GetVertRound());
     539           0 :                         const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
     540           0 :                         basegfx::B2DPolygon aOutline;
     541             : 
     542           0 :                         if(nHor || nVer)
     543             :                         {
     544           0 :                             double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
     545           0 :                             double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
     546           0 :                             fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
     547           0 :                             fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
     548             : 
     549           0 :                             aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
     550             :                         }
     551             :                         else
     552             :                         {
     553           0 :                             aOutline = basegfx::tools::createPolygonFromRect(aRange);
     554             :                         }
     555             : 
     556             :                         bDone = handleGeometricContent(
     557           0 :                             aClips.back(),
     558             :                             basegfx::B2DPolyPolygon(aOutline),
     559             :                             aTarget,
     560           0 :                             false); // stroke
     561             :                     }
     562           0 :                     break;
     563             :                 }
     564             : 
     565             :                 case MetaActionType::ELLIPSE :
     566             :                 {
     567           0 :                     const MetaEllipseAction* pA = static_cast< const MetaEllipseAction* >(pAction);
     568           0 :                     const Rectangle& rRect = pA->GetRect();
     569             : 
     570           0 :                     if(rRect.IsEmpty())
     571             :                     {
     572           0 :                         bDone = true;
     573             :                     }
     574             :                     else
     575             :                     {
     576           0 :                         const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
     577             : 
     578             :                         bDone = handleGeometricContent(
     579           0 :                             aClips.back(),
     580             :                             basegfx::B2DPolyPolygon(
     581             :                                 basegfx::tools::createPolygonFromEllipse(
     582             :                                     aRange.getCenter(),
     583           0 :                                     aRange.getWidth() * 0.5,
     584           0 :                                     aRange.getHeight() * 0.5)),
     585             :                             aTarget,
     586           0 :                             false); // stroke
     587             :                     }
     588           0 :                     break;
     589             :                 }
     590             : 
     591             :                 case MetaActionType::ARC :
     592             :                 {
     593           0 :                     const MetaArcAction* pA = static_cast< const MetaArcAction* >(pAction);
     594           0 :                     const Rectangle& rRect = pA->GetRect();
     595             : 
     596           0 :                     if(rRect.IsEmpty())
     597             :                     {
     598           0 :                         bDone = true;
     599             :                     }
     600             :                     else
     601             :                     {
     602             :                         const Polygon aToolsPoly(
     603             :                             rRect,
     604           0 :                             pA->GetStartPoint(),
     605           0 :                             pA->GetEndPoint(),
     606           0 :                             POLY_ARC);
     607             : 
     608             :                         bDone = handleGeometricContent(
     609           0 :                             aClips.back(),
     610             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     611             :                             aTarget,
     612           0 :                             true); // stroke
     613             :                     }
     614           0 :                     break;
     615             :                 }
     616             : 
     617             :                 case MetaActionType::PIE :
     618             :                 {
     619           0 :                     const MetaPieAction* pA = static_cast< const MetaPieAction* >(pAction);
     620           0 :                     const Rectangle& rRect = pA->GetRect();
     621             : 
     622           0 :                     if(rRect.IsEmpty())
     623             :                     {
     624           0 :                         bDone = true;
     625             :                     }
     626             :                     else
     627             :                     {
     628             :                         const Polygon aToolsPoly(
     629             :                             rRect,
     630           0 :                             pA->GetStartPoint(),
     631           0 :                             pA->GetEndPoint(),
     632           0 :                             POLY_PIE);
     633             : 
     634             :                         bDone = handleGeometricContent(
     635           0 :                             aClips.back(),
     636             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     637             :                             aTarget,
     638           0 :                             false); // stroke
     639             :                     }
     640           0 :                     break;
     641             :                 }
     642             : 
     643             :                 case MetaActionType::CHORD :
     644             :                 {
     645           0 :                     const MetaChordAction* pA = static_cast< const MetaChordAction* >(pAction);
     646           0 :                     const Rectangle& rRect = pA->GetRect();
     647             : 
     648           0 :                     if(rRect.IsEmpty())
     649             :                     {
     650           0 :                         bDone = true;
     651             :                     }
     652             :                     else
     653             :                     {
     654             :                         const Polygon aToolsPoly(
     655             :                             rRect,
     656           0 :                             pA->GetStartPoint(),
     657           0 :                             pA->GetEndPoint(),
     658           0 :                             POLY_CHORD);
     659             : 
     660             :                         bDone = handleGeometricContent(
     661           0 :                             aClips.back(),
     662             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     663             :                             aTarget,
     664           0 :                             false); // stroke
     665             :                     }
     666           0 :                     break;
     667             :                 }
     668             : 
     669             :                 case MetaActionType::POLYLINE :
     670             :                 {
     671           0 :                     const MetaPolyLineAction* pA = static_cast< const MetaPolyLineAction* >(pAction);
     672             : 
     673             :                     bDone = handleGeometricContent(
     674           0 :                         aClips.back(),
     675           0 :                         basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
     676             :                         aTarget,
     677           0 :                         true); // stroke
     678           0 :                     break;
     679             :                 }
     680             : 
     681             :                 case MetaActionType::POLYGON :
     682             :                 {
     683           0 :                     const MetaPolygonAction* pA = static_cast< const MetaPolygonAction* >(pAction);
     684             : 
     685             :                     bDone = handleGeometricContent(
     686           0 :                         aClips.back(),
     687           0 :                         basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
     688             :                         aTarget,
     689           0 :                         false); // stroke
     690           0 :                     break;
     691             :                 }
     692             : 
     693             :                 case MetaActionType::POLYPOLYGON :
     694             :                 {
     695           0 :                     const MetaPolyPolygonAction* pA = static_cast< const MetaPolyPolygonAction* >(pAction);
     696           0 :                     const tools::PolyPolygon& rPoly = pA->GetPolyPolygon();
     697             : 
     698             :                     bDone = handleGeometricContent(
     699           0 :                         aClips.back(),
     700             :                         rPoly.getB2DPolyPolygon(),
     701             :                         aTarget,
     702           0 :                         false); // stroke
     703           0 :                     break;
     704             :                 }
     705             : 
     706             :                 // bitmap actions, create BitmapEx with alpha channel derived
     707             :                 // from clipping
     708             : 
     709             :                 case MetaActionType::BMPEX :
     710             :                 {
     711           0 :                     const MetaBmpExAction* pA = static_cast< const MetaBmpExAction* >(pAction);
     712           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
     713             : 
     714             :                     // the logical size depends on the PrefSize of the given bitmap in
     715             :                     // combination with the current MapMode
     716           0 :                     Size aLogicalSize(rBitmapEx.GetPrefSize());
     717             : 
     718           0 :                     if(MAP_PIXEL == rBitmapEx.GetPrefMapMode().GetMapUnit())
     719             :                     {
     720           0 :                         aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
     721             :                     }
     722             :                     else
     723             :                     {
     724           0 :                         aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmapEx.GetPrefMapMode(), aMapModes.back().GetMapUnit());
     725             :                     }
     726             : 
     727             :                     bDone = handleBitmapContent(
     728           0 :                         aClips.back(),
     729           0 :                         pA->GetPoint(),
     730             :                         aLogicalSize,
     731             :                         rBitmapEx,
     732           0 :                         aTarget);
     733           0 :                     break;
     734             :                 }
     735             : 
     736             :                 case MetaActionType::BMP :
     737             :                 {
     738           0 :                     const MetaBmpAction* pA = static_cast< const MetaBmpAction* >(pAction);
     739           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
     740             : 
     741             :                     // the logical size depends on the PrefSize of the given bitmap in
     742             :                     // combination with the current MapMode
     743           0 :                     Size aLogicalSize(rBitmap.GetPrefSize());
     744             : 
     745           0 :                     if(MAP_PIXEL == rBitmap.GetPrefMapMode().GetMapUnit())
     746             :                     {
     747           0 :                         aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
     748             :                     }
     749             :                     else
     750             :                     {
     751           0 :                         aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmap.GetPrefMapMode(), aMapModes.back().GetMapUnit());
     752             :                     }
     753             : 
     754             :                     bDone = handleBitmapContent(
     755           0 :                         aClips.back(),
     756           0 :                         pA->GetPoint(),
     757             :                         aLogicalSize,
     758             :                         BitmapEx(rBitmap),
     759           0 :                         aTarget);
     760           0 :                     break;
     761             :                 }
     762             : 
     763             :                 case MetaActionType::BMPEXSCALE :
     764             :                 {
     765           0 :                     const MetaBmpExScaleAction* pA = static_cast< const MetaBmpExScaleAction* >(pAction);
     766             : 
     767             :                     bDone = handleBitmapContent(
     768           0 :                         aClips.back(),
     769           0 :                         pA->GetPoint(),
     770           0 :                         pA->GetSize(),
     771           0 :                         pA->GetBitmapEx(),
     772           0 :                         aTarget);
     773           0 :                     break;
     774             :                 }
     775             : 
     776             :                 case MetaActionType::BMPSCALE :
     777             :                 {
     778           0 :                     const MetaBmpScaleAction* pA = static_cast< const MetaBmpScaleAction* >(pAction);
     779             : 
     780             :                     bDone = handleBitmapContent(
     781           0 :                         aClips.back(),
     782           0 :                         pA->GetPoint(),
     783           0 :                         pA->GetSize(),
     784           0 :                         BitmapEx(pA->GetBitmap()),
     785           0 :                         aTarget);
     786           0 :                     break;
     787             :                 }
     788             : 
     789             :                 case MetaActionType::BMPEXSCALEPART :
     790             :                 {
     791           0 :                     const MetaBmpExScalePartAction* pA = static_cast< const MetaBmpExScalePartAction* >(pAction);
     792           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
     793             : 
     794           0 :                     if(rBitmapEx.IsEmpty())
     795             :                     {
     796             :                         // empty content
     797           0 :                         bDone = true;
     798             :                     }
     799             :                     else
     800             :                     {
     801           0 :                         BitmapEx aCroppedBitmapEx(rBitmapEx);
     802           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
     803             : 
     804           0 :                         if(aCropRectangle.IsEmpty())
     805             :                         {
     806             :                             // empty content
     807           0 :                             bDone = true;
     808             :                         }
     809             :                         else
     810             :                         {
     811           0 :                             aCroppedBitmapEx.Crop(aCropRectangle);
     812             :                             bDone = handleBitmapContent(
     813           0 :                                 aClips.back(),
     814           0 :                                 pA->GetDestPoint(),
     815           0 :                                 pA->GetDestSize(),
     816             :                                 aCroppedBitmapEx,
     817           0 :                                 aTarget);
     818           0 :                         }
     819             :                     }
     820           0 :                     break;
     821             :                 }
     822             : 
     823             :                 case MetaActionType::BMPSCALEPART :
     824             :                 {
     825           0 :                     const MetaBmpScalePartAction* pA = static_cast< const MetaBmpScalePartAction* >(pAction);
     826           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
     827             : 
     828           0 :                     if(rBitmap.IsEmpty())
     829             :                     {
     830             :                         // empty content
     831           0 :                         bDone = true;
     832             :                     }
     833             :                     else
     834             :                     {
     835           0 :                         Bitmap aCroppedBitmap(rBitmap);
     836           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
     837             : 
     838           0 :                         if(aCropRectangle.IsEmpty())
     839             :                         {
     840             :                             // empty content
     841           0 :                             bDone = true;
     842             :                         }
     843             :                         else
     844             :                         {
     845           0 :                             aCroppedBitmap.Crop(aCropRectangle);
     846             :                             bDone = handleBitmapContent(
     847           0 :                                 aClips.back(),
     848           0 :                                 pA->GetDestPoint(),
     849           0 :                                 pA->GetDestSize(),
     850             :                                 BitmapEx(aCroppedBitmap),
     851           0 :                                 aTarget);
     852           0 :                         }
     853             :                     }
     854           0 :                     break;
     855             :                 }
     856             : 
     857             :                 // need to handle all those 'hacks' which hide data in comments
     858             : 
     859             :                 case MetaActionType::COMMENT :
     860             :                 {
     861           0 :                     const MetaCommentAction* pA = static_cast< const MetaCommentAction* >(pAction);
     862           0 :                     const OString& rComment = pA->GetComment();
     863             : 
     864           0 :                     if(rComment.equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
     865             :                     {
     866             :                         // nothing to do; this just means that between here and XGRAD_SEQ_END
     867             :                         // exists a MetaActionType::GRADIENTEX mixed with Xor-tricked painiting
     868             :                         // commands. This comment is used to scan over these and filter for
     869             :                         // the gradient action. It is needed to support MetaActionType::GRADIENTEX
     870             :                         // in this processor to solve usages.
     871             :                     }
     872           0 :                     else if(rComment.equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN"))
     873             :                     {
     874           0 :                         SvtGraphicFill aFilling;
     875           0 :                         tools::PolyPolygon aPath;
     876             : 
     877             :                         {   // read SvtGraphicFill
     878           0 :                             SvMemoryStream aMemStm(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(),StreamMode::READ);
     879           0 :                             ReadSvtGraphicFill( aMemStm, aFilling );
     880             :                         }
     881             : 
     882           0 :                         aFilling.getPath(aPath);
     883             : 
     884           0 :                         if(aPath.Count())
     885             :                         {
     886           0 :                             const basegfx::B2DPolyPolygon aSource(aPath.getB2DPolyPolygon());
     887             :                             const basegfx::B2DPolyPolygon aResult(
     888             :                                 basegfx::tools::clipPolyPolygonOnPolyPolygon(
     889             :                                     aSource,
     890           0 :                                     aClips.back(),
     891             :                                     true, // inside
     892           0 :                                     false)); // stroke
     893             : 
     894           0 :                             if(aResult.count())
     895             :                             {
     896           0 :                                 if(aResult != aSource)
     897             :                                 {
     898             :                                     // add clipped geometry
     899           0 :                                     aFilling.setPath(tools::PolyPolygon(aResult));
     900           0 :                                     addSvtGraphicFill(aFilling, aTarget);
     901           0 :                                     bDone = true;
     902             :                                 }
     903             :                             }
     904             :                             else
     905             :                             {
     906             :                                 // exchange with empty polygon
     907           0 :                                 aFilling.setPath(tools::PolyPolygon());
     908           0 :                                 addSvtGraphicFill(aFilling, aTarget);
     909           0 :                                 bDone = true;
     910           0 :                             }
     911           0 :                         }
     912             :                     }
     913           0 :                     else if(rComment.equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN"))
     914             :                     {
     915           0 :                         SvtGraphicStroke aStroke;
     916           0 :                         Polygon aPath;
     917             : 
     918             :                         {   // read SvtGraphicFill
     919           0 :                             SvMemoryStream aMemStm(const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(),StreamMode::READ);
     920           0 :                             ReadSvtGraphicStroke( aMemStm, aStroke );
     921             :                         }
     922             : 
     923           0 :                         aStroke.getPath(aPath);
     924             : 
     925           0 :                         if(aPath.GetSize())
     926             :                         {
     927           0 :                             const basegfx::B2DPolygon aSource(aPath.getB2DPolygon());
     928             :                             const basegfx::B2DPolyPolygon aResult(
     929             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     930             :                                     aSource,
     931           0 :                                     aClips.back(),
     932             :                                     true, // inside
     933           0 :                                     true)); // stroke
     934             : 
     935           0 :                             if(aResult.count())
     936             :                             {
     937           0 :                                 if(aResult.count() > 1 || aResult.getB2DPolygon(0) != aSource)
     938             :                                 {
     939             :                                     // add clipped geometry
     940           0 :                                     for(sal_uInt32 a(0); a < aResult.count(); a++)
     941             :                                     {
     942           0 :                                         aStroke.setPath(Polygon(aResult.getB2DPolygon(a)));
     943           0 :                                         addSvtGraphicStroke(aStroke, aTarget);
     944             :                                     }
     945             : 
     946           0 :                                     bDone = true;
     947             :                                 }
     948             :                             }
     949             :                             else
     950             :                             {
     951             :                                 // exchange with empty polygon
     952           0 :                                 aStroke.setPath(Polygon());
     953           0 :                                 addSvtGraphicStroke(aStroke, aTarget);
     954           0 :                                 bDone = true;
     955           0 :                             }
     956             : 
     957           0 :                         }
     958             :                     }
     959           0 :                     break;
     960             :                 }
     961             : 
     962             :                 // need to handle gradient fills (hopefully only unroated ones)
     963             : 
     964             :                 case MetaActionType::GRADIENT :
     965             :                 {
     966           0 :                     const MetaGradientAction* pA = static_cast< const MetaGradientAction* >(pAction);
     967           0 :                     const Rectangle& rRect = pA->GetRect();
     968             : 
     969           0 :                     if(rRect.IsEmpty())
     970             :                     {
     971           0 :                         bDone = true;
     972             :                     }
     973             :                     else
     974             :                     {
     975             :                         bDone = handleGradientContent(
     976           0 :                             aClips.back(),
     977             :                             basegfx::B2DPolyPolygon(
     978             :                                 basegfx::tools::createPolygonFromRect(
     979             :                                     basegfx::B2DRange(
     980           0 :                                         rRect.Left(), rRect.Top(),
     981           0 :                                         rRect.Right(), rRect.Bottom()))),
     982           0 :                             pA->GetGradient(),
     983           0 :                             aTarget);
     984             :                     }
     985             : 
     986           0 :                     break;
     987             :                 }
     988             : 
     989             :                 case MetaActionType::GRADIENTEX :
     990             :                 {
     991           0 :                     const MetaGradientExAction* pA = static_cast< const MetaGradientExAction* >(pAction);
     992           0 :                     const tools::PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
     993             : 
     994             :                     bDone = handleGradientContent(
     995           0 :                         aClips.back(),
     996             :                         rPolyPoly.getB2DPolyPolygon(),
     997           0 :                         pA->GetGradient(),
     998           0 :                         aTarget);
     999           0 :                     break;
    1000             :                 }
    1001             : 
    1002             :                 // not (yet) supported actions
    1003             : 
    1004             :                 // MetaActionType::NONE
    1005             :                 // MetaActionType::TEXT
    1006             :                 // MetaActionType::TEXTARRAY
    1007             :                 // MetaActionType::STRETCHTEXT
    1008             :                 // MetaActionType::TEXTRECT
    1009             :                 // MetaActionType::MASK
    1010             :                 // MetaActionType::MASKSCALE
    1011             :                 // MetaActionType::MASKSCALEPART
    1012             :                 // MetaActionType::HATCH
    1013             :                 // MetaActionType::WALLPAPER
    1014             :                 // MetaActionType::FILLCOLOR
    1015             :                 // MetaActionType::TEXTCOLOR
    1016             :                 // MetaActionType::TEXTFILLCOLOR
    1017             :                 // MetaActionType::TEXTALIGN
    1018             :                 // MetaActionType::MAPMODE
    1019             :                 // MetaActionType::FONT
    1020             :                 // MetaActionType::Transparent
    1021             :                 // MetaActionType::EPS
    1022             :                 // MetaActionType::REFPOINT
    1023             :                 // MetaActionType::TEXTLINECOLOR
    1024             :                 // MetaActionType::TEXTLINE
    1025             :                 // MetaActionType::FLOATTRANSPARENT
    1026             :                 // MetaActionType::LAYOUTMODE
    1027             :                 // MetaActionType::TEXTLANGUAGE
    1028             :                 // MetaActionType::OVERLINECOLOR
    1029             : 
    1030             :                 // if an action is not handled at all, it will simply get copied to the
    1031             :                 // target (see below). This is the default for all non-implemented actions
    1032             :                 default:
    1033             :                 {
    1034           0 :                     break;
    1035             :                 }
    1036             :             }
    1037             :         }
    1038             : 
    1039        3975 :         if(bDone)
    1040             :         {
    1041           0 :             bChanged = true;
    1042             :         }
    1043             :         else
    1044             :         {
    1045        3975 :             const_cast< MetaAction* >(pAction)->Duplicate();
    1046        3975 :             aTarget.AddAction(const_cast< MetaAction* >(pAction));
    1047             :         }
    1048             :     }
    1049             : 
    1050          38 :     if(bChanged)
    1051             :     {
    1052             :         // when changed, copy back and do not forget to set MapMode
    1053             :         // and PrefSize
    1054           0 :         aTarget.SetPrefMapMode(rSource.GetPrefMapMode());
    1055           0 :         aTarget.SetPrefSize(rSource.GetPrefSize());
    1056           0 :         rSource = aTarget;
    1057          38 :     }
    1058             : }
    1059             : 
    1060          79 : bool usesClipActions(const GDIMetaFile& rSource)
    1061             : {
    1062          79 :     const sal_uLong nObjCount(rSource.GetActionSize());
    1063             : 
    1064         950 :     for(sal_uLong i(0); i < nObjCount; ++i)
    1065             :     {
    1066         909 :         const MetaAction* pAction(rSource.GetAction(i));
    1067         909 :         const MetaActionType nType(pAction->GetType());
    1068             : 
    1069         909 :         switch(nType)
    1070             :         {
    1071             :             case MetaActionType::CLIPREGION :
    1072             :             case MetaActionType::ISECTRECTCLIPREGION :
    1073             :             case MetaActionType::ISECTREGIONCLIPREGION :
    1074             :             case MetaActionType::MOVECLIPREGION :
    1075             :             {
    1076          38 :                 return true;
    1077             :             }
    1078             : 
    1079         871 :             default: break;
    1080             :         }
    1081             :     }
    1082             : 
    1083          41 :     return false;
    1084             : }
    1085             : 
    1086             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11