LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/source/gdi - gdimetafiletools.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 59 391 15.1 %
Date: 2013-07-09 Functions: 4 9 44.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * This file is part of the LibreOffice project.
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * This file incorporates work covered by the following license notice:
       9             :  *
      10             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      11             :  *   contributor license agreements. See the NOTICE file distributed
      12             :  *   with this work for additional information regarding copyright
      13             :  *   ownership. The ASF licenses this file to you under the Apache
      14             :  *   License, Version 2.0 (the "License"); you may not use this file
      15             :  *   except in compliance with the License. You may obtain a copy of
      16             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      17             :  */
      18             : 
      19             : #include <vcl/gdimetafiletools.hxx>
      20             : #include <vcl/metaact.hxx>
      21             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      22             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      23             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      24             : #include <basegfx/polygon/b2dpolygontools.hxx>
      25             : #include <vcl/virdev.hxx>
      26             : #include <vcl/svapp.hxx>
      27             : #include <vcl/graphictools.hxx>
      28             : 
      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 :                                 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             :                             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 :         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             :         // 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             :             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             :                     basegfx::fround(aLogicBitmapRange.getMinX()),
     222             :                     basegfx::fround(aLogicBitmapRange.getMinY())),
     223             :                 Size(
     224             :                     basegfx::fround(aLogicBitmapRange.getWidth()),
     225             :                     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 :         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 :         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             : //////////////////////////////////////////////////////////////////////////////
     259             : // #i121267# Tooling to internally clip geometry against internal clip regions
     260             : 
     261          31 : void clipMetafileContentAgainstOwnRegions(GDIMetaFile& rSource)
     262             : {
     263          31 :     const sal_uLong nObjCount(rSource.GetActionSize());
     264             : 
     265          31 :     if(!nObjCount)
     266             :     {
     267          31 :         return;
     268             :     }
     269             : 
     270             :     // prepare target data container and push/pop stack data
     271          31 :     GDIMetaFile aTarget;
     272          31 :     bool bChanged(false);
     273          62 :     std::vector< basegfx::B2DPolyPolygon > aClips;
     274          62 :     std::vector< sal_uInt16 > aPushFlags;
     275          62 :     std::vector< MapMode > aMapModes;
     276             : 
     277             :     // start with empty region
     278          31 :     aClips.push_back(basegfx::B2DPolyPolygon());
     279             : 
     280             :     // start with default MapMode (MAP_PIXEL)
     281          31 :     aMapModes.push_back(MapMode());
     282             : 
     283        2883 :     for(sal_uLong i(0); i < nObjCount; ++i)
     284             :     {
     285        2852 :         const MetaAction* pAction(rSource.GetAction(i));
     286        2852 :         const sal_uInt16 nType(pAction->GetType());
     287        2852 :         bool bDone(false);
     288             : 
     289             :         // basic operation takes care of clipregion actions (four) and push/pop of these
     290             :         // to steer the currently set clip region. There *is* an active
     291             :         // clip region when (aClips.size() && aClips.back().count()), see
     292             :         // below
     293        2852 :         switch(nType)
     294             :         {
     295             :             case META_CLIPREGION_ACTION :
     296             :             {
     297           0 :                 const MetaClipRegionAction* pA = static_cast< const MetaClipRegionAction* >(pAction);
     298             : 
     299           0 :                 if(pA->IsClipping())
     300             :                 {
     301           0 :                     const Region& rRegion = pA->GetRegion();
     302           0 :                     const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
     303             : 
     304           0 :                     aClips.back() = aNewClip;
     305             :                 }
     306             :                 else
     307             :                 {
     308           0 :                     aClips.back() = basegfx::B2DPolyPolygon();
     309             :                 }
     310             : 
     311           0 :                 break;
     312             :             }
     313             : 
     314             :             case META_ISECTRECTCLIPREGION_ACTION :
     315             :             {
     316          30 :                 const MetaISectRectClipRegionAction* pA = static_cast< const MetaISectRectClipRegionAction* >(pAction);
     317          30 :                 const Rectangle& rRect = pA->GetRect();
     318             : 
     319          30 :                 if(!rRect.IsEmpty() && aClips.size() && aClips.back().count())
     320             :                 {
     321             :                     const basegfx::B2DRange aClipRange(
     322           0 :                         rRect.Left(), rRect.Top(),
     323           0 :                         rRect.Right(), rRect.Bottom());
     324             : 
     325           0 :                     aClips.back() = basegfx::tools::clipPolyPolygonOnRange(
     326           0 :                         aClips.back(),
     327             :                         aClipRange,
     328             :                         true, // inside
     329           0 :                         false); // stroke
     330             :                 }
     331          30 :                 break;
     332             :             }
     333             : 
     334             :             case META_ISECTREGIONCLIPREGION_ACTION :
     335             :             {
     336           4 :                 const MetaISectRegionClipRegionAction* pA = static_cast< const MetaISectRegionClipRegionAction* >(pAction);
     337           4 :                 const Region& rRegion = pA->GetRegion();
     338             : 
     339           4 :                 if(!rRegion.IsEmpty() && aClips.size() && aClips.back().count())
     340             :                 {
     341           0 :                     const basegfx::B2DPolyPolygon aNewClip(rRegion.GetAsB2DPolyPolygon());
     342             : 
     343           0 :                     aClips.back() = basegfx::tools::clipPolyPolygonOnPolyPolygon(
     344           0 :                         aClips.back(),
     345             :                         aNewClip,
     346             :                         true,  // inside
     347           0 :                         false); // stroke
     348             :                 }
     349           4 :                 break;
     350             :             }
     351             : 
     352             :             case META_MOVECLIPREGION_ACTION :
     353             :             {
     354           0 :                 const MetaMoveClipRegionAction* pA = static_cast< const MetaMoveClipRegionAction* >(pAction);
     355           0 :                 const long aHorMove(pA->GetHorzMove());
     356           0 :                 const long aVerMove(pA->GetVertMove());
     357             : 
     358           0 :                 if((aHorMove || aVerMove) && aClips.size() && aClips.back().count())
     359             :                 {
     360           0 :                     aClips.back().transform(
     361             :                         basegfx::tools::createTranslateB2DHomMatrix(
     362             :                             aHorMove,
     363           0 :                             aVerMove));
     364             :                 }
     365           0 :                 break;
     366             :             }
     367             : 
     368             :             case META_PUSH_ACTION :
     369             :             {
     370         398 :                 const MetaPushAction* pA = static_cast< const MetaPushAction* >(pAction);
     371         398 :                 const sal_uInt16 nFlags(pA->GetFlags());
     372             : 
     373         398 :                 aPushFlags.push_back(nFlags);
     374             : 
     375         398 :                 if(nFlags & PUSH_CLIPREGION)
     376             :                 {
     377          35 :                     aClips.push_back(aClips.back());
     378             :                 }
     379             : 
     380         398 :                 if(nFlags & PUSH_MAPMODE)
     381             :                 {
     382         394 :                     aMapModes.push_back(aMapModes.back());
     383             :                 }
     384         398 :                 break;
     385             :             }
     386             : 
     387             :             case META_POP_ACTION :
     388             :             {
     389             : 
     390         398 :                 if(aPushFlags.size())
     391             :                 {
     392         398 :                     const sal_uInt16 nFlags(aPushFlags.back());
     393         398 :                     aPushFlags.pop_back();
     394             : 
     395         398 :                     if(nFlags & PUSH_CLIPREGION)
     396             :                     {
     397          35 :                         if(aClips.size() > 1)
     398             :                         {
     399          35 :                             aClips.pop_back();
     400             :                         }
     401             :                         else
     402             :                         {
     403             :                             OSL_ENSURE(false, "Wrong POP() in ClipRegions (!)");
     404             :                         }
     405             :                     }
     406             : 
     407         398 :                     if(nFlags & PUSH_MAPMODE)
     408             :                     {
     409         394 :                         if(aMapModes.size() > 1)
     410             :                         {
     411         394 :                             aMapModes.pop_back();
     412             :                         }
     413             :                         else
     414             :                         {
     415             :                             OSL_ENSURE(false, "Wrong POP() in MapModes (!)");
     416             :                         }
     417             :                     }
     418             :                 }
     419             :                 else
     420             :                 {
     421             :                     OSL_ENSURE(false, "Invalid pop() without push() (!)");
     422             :                 }
     423             : 
     424         398 :                 break;
     425             :             }
     426             : 
     427             :             case META_MAPMODE_ACTION :
     428             :             {
     429           0 :                 const MetaMapModeAction* pA = static_cast< const MetaMapModeAction* >(pAction);
     430             : 
     431           0 :                 aMapModes.back() = pA->GetMapMode();
     432           0 :                 break;
     433             :             }
     434             : 
     435             :             default:
     436             :             {
     437        2022 :                 break;
     438             :             }
     439             :         }
     440             : 
     441             :         // this area contains all actions which could potentially be clipped. Since
     442             :         // this tooling is only a fallback (see comments in header), only the needed
     443             :         // actions will be implemented. Extend using the pattern for the already
     444             :         // implemented actions.
     445        2852 :         if(aClips.size() && aClips.back().count())
     446             :         {
     447           0 :             switch(nType)
     448             :             {
     449             :                 //
     450             :                 // pixel actions, just check on inside
     451             :                 //
     452             :                 case META_PIXEL_ACTION :
     453             :                 {
     454           0 :                     const MetaPixelAction* pA = static_cast< const MetaPixelAction* >(pAction);
     455           0 :                     const Point& rPoint = pA->GetPoint();
     456             : 
     457           0 :                     if(!basegfx::tools::isInside(
     458           0 :                         aClips.back(),
     459           0 :                         basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
     460             :                     {
     461             :                         // when not inside, do not add original
     462           0 :                         bDone = true;
     463             :                     }
     464           0 :                     break;
     465             :                 }
     466             : 
     467             :                 case META_POINT_ACTION :
     468             :                 {
     469           0 :                     const MetaPointAction* pA = static_cast< const MetaPointAction* >(pAction);
     470           0 :                     const Point& rPoint = pA->GetPoint();
     471             : 
     472           0 :                     if(!basegfx::tools::isInside(
     473           0 :                         aClips.back(),
     474           0 :                         basegfx::B2DPoint(rPoint.X(), rPoint.Y())))
     475             :                     {
     476             :                         // when not inside, do not add original
     477           0 :                         bDone = true;
     478             :                     }
     479           0 :                     break;
     480             :                 }
     481             : 
     482             :                 //
     483             :                 // geometry actions
     484             :                 //
     485             :                 case META_LINE_ACTION :
     486             :                 {
     487           0 :                     const MetaLineAction* pA = static_cast< const MetaLineAction* >(pAction);
     488           0 :                     const Point& rStart(pA->GetStartPoint());
     489           0 :                     const Point& rEnd(pA->GetEndPoint());
     490           0 :                     basegfx::B2DPolygon aLine;
     491             : 
     492           0 :                     aLine.append(basegfx::B2DPoint(rStart.X(), rStart.Y()));
     493           0 :                     aLine.append(basegfx::B2DPoint(rEnd.X(), rEnd.Y()));
     494             : 
     495             :                     bDone = handleGeometricContent(
     496           0 :                         aClips.back(),
     497             :                         basegfx::B2DPolyPolygon(aLine),
     498             :                         aTarget,
     499           0 :                         true); // stroke
     500           0 :                     break;
     501             :                 }
     502             : 
     503             :                 case META_RECT_ACTION :
     504             :                 {
     505           0 :                     const MetaRectAction* pA = static_cast< const MetaRectAction* >(pAction);
     506           0 :                     const Rectangle& rRect = pA->GetRect();
     507             : 
     508           0 :                     if(rRect.IsEmpty())
     509             :                     {
     510           0 :                         bDone = true;
     511             :                     }
     512             :                     else
     513             :                     {
     514             : 
     515             :                         bDone = handleGeometricContent(
     516           0 :                             aClips.back(),
     517             :                             basegfx::B2DPolyPolygon(
     518             :                                 basegfx::tools::createPolygonFromRect(
     519             :                                     basegfx::B2DRange(
     520           0 :                                         rRect.Left(), rRect.Top(),
     521           0 :                                         rRect.Right(), rRect.Bottom()))),
     522             :                             aTarget,
     523           0 :                             false); // stroke
     524             :                     }
     525           0 :                     break;
     526             :                 }
     527             : 
     528             :                 case META_ROUNDRECT_ACTION :
     529             :                 {
     530           0 :                     const MetaRoundRectAction* pA = static_cast< const MetaRoundRectAction* >(pAction);
     531           0 :                     const Rectangle& rRect = pA->GetRect();
     532             : 
     533           0 :                     if(rRect.IsEmpty())
     534             :                     {
     535           0 :                         bDone = true;
     536             :                     }
     537             :                     else
     538             :                     {
     539           0 :                         const sal_uInt32 nHor(pA->GetHorzRound());
     540           0 :                         const sal_uInt32 nVer(pA->GetVertRound());
     541           0 :                         const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
     542           0 :                         basegfx::B2DPolygon aOutline;
     543             : 
     544           0 :                         if(nHor || nVer)
     545             :                         {
     546           0 :                             double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
     547           0 :                             double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
     548           0 :                             fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
     549           0 :                             fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
     550             : 
     551           0 :                             aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
     552             :                         }
     553             :                         else
     554             :                         {
     555           0 :                             aOutline = basegfx::tools::createPolygonFromRect(aRange);
     556             :                         }
     557             : 
     558             :                         bDone = handleGeometricContent(
     559           0 :                             aClips.back(),
     560             :                             basegfx::B2DPolyPolygon(aOutline),
     561             :                             aTarget,
     562           0 :                             false); // stroke
     563             :                     }
     564           0 :                     break;
     565             :                 }
     566             : 
     567             :                 case META_ELLIPSE_ACTION :
     568             :                 {
     569           0 :                     const MetaEllipseAction* pA = static_cast< const MetaEllipseAction* >(pAction);
     570           0 :                     const Rectangle& rRect = pA->GetRect();
     571             : 
     572           0 :                     if(rRect.IsEmpty())
     573             :                     {
     574           0 :                         bDone = true;
     575             :                     }
     576             :                     else
     577             :                     {
     578           0 :                         const basegfx::B2DRange aRange(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
     579             : 
     580             :                         bDone = handleGeometricContent(
     581           0 :                             aClips.back(),
     582             :                             basegfx::B2DPolyPolygon(
     583             :                                 basegfx::tools::createPolygonFromEllipse(
     584             :                                     aRange.getCenter(),
     585           0 :                                     aRange.getWidth() * 0.5,
     586           0 :                                     aRange.getHeight() * 0.5)),
     587             :                             aTarget,
     588           0 :                             false); // stroke
     589             :                     }
     590           0 :                     break;
     591             :                 }
     592             : 
     593             :                 case META_ARC_ACTION :
     594             :                 {
     595           0 :                     const MetaArcAction* pA = static_cast< const MetaArcAction* >(pAction);
     596           0 :                     const Rectangle& rRect = pA->GetRect();
     597             : 
     598           0 :                     if(rRect.IsEmpty())
     599             :                     {
     600           0 :                         bDone = true;
     601             :                     }
     602             :                     else
     603             :                     {
     604             :                         const Polygon aToolsPoly(
     605             :                             rRect,
     606           0 :                             pA->GetStartPoint(),
     607           0 :                             pA->GetEndPoint(),
     608           0 :                             POLY_ARC);
     609             : 
     610             :                         bDone = handleGeometricContent(
     611           0 :                             aClips.back(),
     612             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     613             :                             aTarget,
     614           0 :                             true); // stroke
     615             :                     }
     616           0 :                     break;
     617             :                 }
     618             : 
     619             :                 case META_PIE_ACTION :
     620             :                 {
     621           0 :                     const MetaPieAction* pA = static_cast< const MetaPieAction* >(pAction);
     622           0 :                     const Rectangle& rRect = pA->GetRect();
     623             : 
     624           0 :                     if(rRect.IsEmpty())
     625             :                     {
     626           0 :                         bDone = true;
     627             :                     }
     628             :                     else
     629             :                     {
     630             :                         const Polygon aToolsPoly(
     631             :                             rRect,
     632           0 :                             pA->GetStartPoint(),
     633           0 :                             pA->GetEndPoint(),
     634           0 :                             POLY_PIE);
     635             : 
     636             :                         bDone = handleGeometricContent(
     637           0 :                             aClips.back(),
     638             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     639             :                             aTarget,
     640           0 :                             false); // stroke
     641             :                     }
     642           0 :                     break;
     643             :                 }
     644             : 
     645             :                 case META_CHORD_ACTION :
     646             :                 {
     647           0 :                     const MetaChordAction* pA = static_cast< const MetaChordAction* >(pAction);
     648           0 :                     const Rectangle& rRect = pA->GetRect();
     649             : 
     650           0 :                     if(rRect.IsEmpty())
     651             :                     {
     652           0 :                         bDone = true;
     653             :                     }
     654             :                     else
     655             :                     {
     656             :                         const Polygon aToolsPoly(
     657             :                             rRect,
     658           0 :                             pA->GetStartPoint(),
     659           0 :                             pA->GetEndPoint(),
     660           0 :                             POLY_CHORD);
     661             : 
     662             :                         bDone = handleGeometricContent(
     663           0 :                             aClips.back(),
     664             :                             basegfx::B2DPolyPolygon(aToolsPoly.getB2DPolygon()),
     665             :                             aTarget,
     666           0 :                             false); // stroke
     667             :                     }
     668           0 :                     break;
     669             :                 }
     670             : 
     671             :                 case META_POLYLINE_ACTION :
     672             :                 {
     673           0 :                     const MetaPolyLineAction* pA = static_cast< const MetaPolyLineAction* >(pAction);
     674             : 
     675             :                     bDone = handleGeometricContent(
     676           0 :                         aClips.back(),
     677           0 :                         basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
     678             :                         aTarget,
     679           0 :                         true); // stroke
     680           0 :                     break;
     681             :                 }
     682             : 
     683             :                 case META_POLYGON_ACTION :
     684             :                 {
     685           0 :                     const MetaPolygonAction* pA = static_cast< const MetaPolygonAction* >(pAction);
     686             : 
     687             :                     bDone = handleGeometricContent(
     688           0 :                         aClips.back(),
     689           0 :                         basegfx::B2DPolyPolygon(pA->GetPolygon().getB2DPolygon()),
     690             :                         aTarget,
     691           0 :                         false); // stroke
     692           0 :                     break;
     693             :                 }
     694             : 
     695             :                 case META_POLYPOLYGON_ACTION :
     696             :                 {
     697           0 :                     const MetaPolyPolygonAction* pA = static_cast< const MetaPolyPolygonAction* >(pAction);
     698           0 :                     const PolyPolygon& rPoly = pA->GetPolyPolygon();
     699             : 
     700             :                     bDone = handleGeometricContent(
     701           0 :                         aClips.back(),
     702             :                         rPoly.getB2DPolyPolygon(),
     703             :                         aTarget,
     704           0 :                         false); // stroke
     705           0 :                     break;
     706             :                 }
     707             : 
     708             :                 //
     709             :                 // bitmap actions, create BitmapEx with alpha channel derived
     710             :                 // from clipping
     711             :                 //
     712             :                 case META_BMPEX_ACTION :
     713             :                 {
     714           0 :                     const MetaBmpExAction* pA = static_cast< const MetaBmpExAction* >(pAction);
     715           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
     716             : 
     717             :                     // the logical size depends on the PrefSize of the given bitmap in
     718             :                     // combination with the current MapMode
     719           0 :                     Size aLogicalSize(rBitmapEx.GetPrefSize());
     720             : 
     721           0 :                     if(MAP_PIXEL == rBitmapEx.GetPrefMapMode().GetMapUnit())
     722             :                     {
     723           0 :                         aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
     724             :                     }
     725             :                     else
     726             :                     {
     727           0 :                         aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmapEx.GetPrefMapMode(), aMapModes.back().GetMapUnit());
     728             :                     }
     729             : 
     730             :                     bDone = handleBitmapContent(
     731           0 :                         aClips.back(),
     732           0 :                         pA->GetPoint(),
     733             :                         aLogicalSize,
     734             :                         rBitmapEx,
     735           0 :                         aTarget);
     736           0 :                     break;
     737             :                 }
     738             : 
     739             :                 case META_BMP_ACTION :
     740             :                 {
     741           0 :                     const MetaBmpAction* pA = static_cast< const MetaBmpAction* >(pAction);
     742           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
     743             : 
     744             :                     // the logical size depends on the PrefSize of the given bitmap in
     745             :                     // combination with the current MapMode
     746           0 :                     Size aLogicalSize(rBitmap.GetPrefSize());
     747             : 
     748           0 :                     if(MAP_PIXEL == rBitmap.GetPrefMapMode().GetMapUnit())
     749             :                     {
     750           0 :                         aLogicalSize = Application::GetDefaultDevice()->PixelToLogic(aLogicalSize, aMapModes.back().GetMapUnit());
     751             :                     }
     752             :                     else
     753             :                     {
     754           0 :                         aLogicalSize = OutputDevice::LogicToLogic(aLogicalSize, rBitmap.GetPrefMapMode(), aMapModes.back().GetMapUnit());
     755             :                     }
     756             : 
     757             :                     bDone = handleBitmapContent(
     758           0 :                         aClips.back(),
     759           0 :                         pA->GetPoint(),
     760             :                         aLogicalSize,
     761             :                         BitmapEx(rBitmap),
     762           0 :                         aTarget);
     763           0 :                     break;
     764             :                 }
     765             : 
     766             :                 case META_BMPEXSCALE_ACTION :
     767             :                 {
     768           0 :                     const MetaBmpExScaleAction* pA = static_cast< const MetaBmpExScaleAction* >(pAction);
     769             : 
     770             :                     bDone = handleBitmapContent(
     771           0 :                         aClips.back(),
     772           0 :                         pA->GetPoint(),
     773           0 :                         pA->GetSize(),
     774           0 :                         pA->GetBitmapEx(),
     775           0 :                         aTarget);
     776           0 :                     break;
     777             :                 }
     778             : 
     779             :                 case META_BMPSCALE_ACTION :
     780             :                 {
     781           0 :                     const MetaBmpScaleAction* pA = static_cast< const MetaBmpScaleAction* >(pAction);
     782             : 
     783             :                     bDone = handleBitmapContent(
     784           0 :                         aClips.back(),
     785           0 :                         pA->GetPoint(),
     786           0 :                         pA->GetSize(),
     787           0 :                         BitmapEx(pA->GetBitmap()),
     788           0 :                         aTarget);
     789           0 :                     break;
     790             :                 }
     791             : 
     792             :                 case META_BMPEXSCALEPART_ACTION :
     793             :                 {
     794           0 :                     const MetaBmpExScalePartAction* pA = static_cast< const MetaBmpExScalePartAction* >(pAction);
     795           0 :                     const BitmapEx& rBitmapEx = pA->GetBitmapEx();
     796             : 
     797           0 :                     if(rBitmapEx.IsEmpty())
     798             :                     {
     799             :                         // empty content
     800           0 :                         bDone = true;
     801             :                     }
     802             :                     else
     803             :                     {
     804           0 :                         BitmapEx aCroppedBitmapEx(rBitmapEx);
     805           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
     806             : 
     807           0 :                         if(aCropRectangle.IsEmpty())
     808             :                         {
     809             :                             // empty content
     810           0 :                             bDone = true;
     811             :                         }
     812             :                         else
     813             :                         {
     814           0 :                             aCroppedBitmapEx.Crop(aCropRectangle);
     815             :                             bDone = handleBitmapContent(
     816           0 :                                 aClips.back(),
     817           0 :                                 pA->GetDestPoint(),
     818           0 :                                 pA->GetDestSize(),
     819             :                                 aCroppedBitmapEx,
     820           0 :                                 aTarget);
     821           0 :                         }
     822             :                     }
     823           0 :                     break;
     824             :                 }
     825             : 
     826             :                 case META_BMPSCALEPART_ACTION :
     827             :                 {
     828           0 :                     const MetaBmpScalePartAction* pA = static_cast< const MetaBmpScalePartAction* >(pAction);
     829           0 :                     const Bitmap& rBitmap = pA->GetBitmap();
     830             : 
     831           0 :                     if(rBitmap.IsEmpty())
     832             :                     {
     833             :                         // empty content
     834           0 :                         bDone = true;
     835             :                     }
     836             :                     else
     837             :                     {
     838           0 :                         Bitmap aCroppedBitmap(rBitmap);
     839           0 :                         const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
     840             : 
     841           0 :                         if(aCropRectangle.IsEmpty())
     842             :                         {
     843             :                             // empty content
     844           0 :                             bDone = true;
     845             :                         }
     846             :                         else
     847             :                         {
     848           0 :                             aCroppedBitmap.Crop(aCropRectangle);
     849             :                             bDone = handleBitmapContent(
     850           0 :                                 aClips.back(),
     851           0 :                                 pA->GetDestPoint(),
     852           0 :                                 pA->GetDestSize(),
     853             :                                 BitmapEx(aCroppedBitmap),
     854           0 :                                 aTarget);
     855           0 :                         }
     856             :                     }
     857           0 :                     break;
     858             :                 }
     859             : 
     860             :                 //
     861             :                 // need to handle all those 'hacks' which hide data in comments
     862             :                 //
     863             :                 case META_COMMENT_ACTION :
     864             :                 {
     865           0 :                     const MetaCommentAction* pA = static_cast< const MetaCommentAction* >(pAction);
     866           0 :                     const OString& rComment = pA->GetComment();
     867             : 
     868           0 :                     if(rComment.equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
     869             :                     {
     870             :                         // nothing to do; this just means that between here and XGRAD_SEQ_END
     871             :                         // exists a META_GRADIENTEX_ACTION mixed with Xor-tricked painiting
     872             :                         // commands. This comment is used to scan over these and filter for
     873             :                         // the gradient action. It is needed to support META_GRADIENTEX_ACTION
     874             :                         // in this processor to solve usages.
     875             :                     }
     876           0 :                     else if(rComment.equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN"))
     877             :                     {
     878           0 :                         SvtGraphicFill aFilling;
     879           0 :                         PolyPolygon aPath;
     880             : 
     881             :                         {   // read SvtGraphicFill
     882           0 :                             SvMemoryStream aMemStm((void*)pA->GetData(), pA->GetDataSize(),STREAM_READ);
     883           0 :                             aMemStm >> aFilling;
     884             :                         }
     885             : 
     886           0 :                         aFilling.getPath(aPath);
     887             : 
     888           0 :                         if(aPath.Count())
     889             :                         {
     890           0 :                             const basegfx::B2DPolyPolygon aSource(aPath.getB2DPolyPolygon());
     891             :                             const basegfx::B2DPolyPolygon aResult(
     892             :                                 basegfx::tools::clipPolyPolygonOnPolyPolygon(
     893             :                                     aSource,
     894           0 :                                     aClips.back(),
     895             :                                     true, // inside
     896           0 :                                     false)); // stroke
     897             : 
     898           0 :                             if(aResult.count())
     899             :                             {
     900           0 :                                 if(aResult != aSource)
     901             :                                 {
     902             :                                     // add clipped geometry
     903           0 :                                     aFilling.setPath(PolyPolygon(aResult));
     904           0 :                                     addSvtGraphicFill(aFilling, aTarget);
     905           0 :                                     bDone = true;
     906             :                                 }
     907             :                             }
     908             :                             else
     909             :                             {
     910             :                                 // exchange with empty polygon
     911           0 :                                 aFilling.setPath(PolyPolygon());
     912           0 :                                 addSvtGraphicFill(aFilling, aTarget);
     913           0 :                                 bDone = true;
     914           0 :                             }
     915           0 :                         }
     916             :                     }
     917           0 :                     else if(rComment.equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN"))
     918             :                     {
     919           0 :                         SvtGraphicStroke aStroke;
     920           0 :                         Polygon aPath;
     921             : 
     922             :                         {   // read SvtGraphicFill
     923           0 :                             SvMemoryStream aMemStm((void*)pA->GetData(), pA->GetDataSize(),STREAM_READ);
     924           0 :                             aMemStm >> aStroke;
     925             :                         }
     926             : 
     927           0 :                         aStroke.getPath(aPath);
     928             : 
     929           0 :                         if(aPath.GetSize())
     930             :                         {
     931           0 :                             const basegfx::B2DPolygon aSource(aPath.getB2DPolygon());
     932             :                             const basegfx::B2DPolyPolygon aResult(
     933             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     934             :                                     aSource,
     935           0 :                                     aClips.back(),
     936             :                                     true, // inside
     937           0 :                                     true)); // stroke
     938             : 
     939           0 :                             if(aResult.count())
     940             :                             {
     941           0 :                                 if(aResult.count() > 1 || aResult.getB2DPolygon(0) != aSource)
     942             :                                 {
     943             :                                     // add clipped geometry
     944           0 :                                     for(sal_uInt32 a(0); a < aResult.count(); a++)
     945             :                                     {
     946           0 :                                         aStroke.setPath(Polygon(aResult.getB2DPolygon(a)));
     947           0 :                                         addSvtGraphicStroke(aStroke, aTarget);
     948             :                                     }
     949             : 
     950           0 :                                     bDone = true;
     951             :                                 }
     952             :                             }
     953             :                             else
     954             :                             {
     955             :                                 // exchange with empty polygon
     956           0 :                                 aStroke.setPath(Polygon());
     957           0 :                                 addSvtGraphicStroke(aStroke, aTarget);
     958           0 :                                 bDone = true;
     959           0 :                             }
     960             : 
     961           0 :                         }
     962             :                     }
     963           0 :                     break;
     964             :                 }
     965             : 
     966             :                 //
     967             :                 // need to handle gradient fills (hopefully only unroated ones)
     968             :                 //
     969             : 
     970             :                 case META_GRADIENT_ACTION :
     971             :                 {
     972           0 :                     const MetaGradientAction* pA = static_cast< const MetaGradientAction* >(pAction);
     973           0 :                     const Rectangle& rRect = pA->GetRect();
     974             : 
     975           0 :                     if(rRect.IsEmpty())
     976             :                     {
     977           0 :                         bDone = true;
     978             :                     }
     979             :                     else
     980             :                     {
     981             :                         bDone = handleGradientContent(
     982           0 :                             aClips.back(),
     983             :                             basegfx::B2DPolyPolygon(
     984             :                                 basegfx::tools::createPolygonFromRect(
     985             :                                     basegfx::B2DRange(
     986           0 :                                         rRect.Left(), rRect.Top(),
     987           0 :                                         rRect.Right(), rRect.Bottom()))),
     988           0 :                             pA->GetGradient(),
     989           0 :                             aTarget);
     990             :                     }
     991             : 
     992             : 
     993           0 :                     break;
     994             :                 }
     995             : 
     996             :                 case META_GRADIENTEX_ACTION :
     997             :                 {
     998           0 :                     const MetaGradientExAction* pA = static_cast< const MetaGradientExAction* >(pAction);
     999           0 :                     const PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
    1000             : 
    1001             :                     bDone = handleGradientContent(
    1002           0 :                         aClips.back(),
    1003             :                         rPolyPoly.getB2DPolyPolygon(),
    1004           0 :                         pA->GetGradient(),
    1005           0 :                         aTarget);
    1006           0 :                     break;
    1007             :                 }
    1008             : 
    1009             :                 // not (yet) supported actions
    1010             :                 //
    1011             :                 // META_NULL_ACTION
    1012             :                 // META_TEXT_ACTION
    1013             :                 // META_TEXTARRAY_ACTION
    1014             :                 // META_STRETCHTEXT_ACTION
    1015             :                 // META_TEXTRECT_ACTION
    1016             :                 // META_MASK_ACTION
    1017             :                 // META_MASKSCALE_ACTION
    1018             :                 // META_MASKSCALEPART_ACTION
    1019             :                 // META_HATCH_ACTION
    1020             :                 // META_WALLPAPER_ACTION
    1021             :                 // META_FILLCOLOR_ACTION
    1022             :                 // META_TEXTCOLOR_ACTION
    1023             :                 // META_TEXTFILLCOLOR_ACTION
    1024             :                 // META_TEXTALIGN_ACTION
    1025             :                 // META_MAPMODE_ACTION
    1026             :                 // META_FONT_ACTION
    1027             :                 // META_TRANSPARENT_ACTION
    1028             :                 // META_EPS_ACTION
    1029             :                 // META_REFPOINT_ACTION
    1030             :                 // META_TEXTLINECOLOR_ACTION
    1031             :                 // META_TEXTLINE_ACTION
    1032             :                 // META_FLOATTRANSPARENT_ACTION
    1033             :                 // META_LAYOUTMODE_ACTION
    1034             :                 // META_TEXTLANGUAGE_ACTION
    1035             :                 // META_OVERLINECOLOR_ACTION
    1036             : 
    1037             :                 // if an action is not handled at all, it will simply get copied to the
    1038             :                 // target (see below). This is the default for all non-implemented actions
    1039             :                 default:
    1040             :                 {
    1041           0 :                     break;
    1042             :                 }
    1043             :             }
    1044             :         }
    1045             : 
    1046        2852 :         if(bDone)
    1047             :         {
    1048           0 :             bChanged = true;
    1049             :         }
    1050             :         else
    1051             :         {
    1052        2852 :             const_cast< MetaAction* >(pAction)->Duplicate();
    1053        2852 :             aTarget.AddAction(const_cast< MetaAction* >(pAction));
    1054             :         }
    1055             :     }
    1056             : 
    1057          31 :     if(bChanged)
    1058             :     {
    1059             :         // when changed, copy back and do not forget to set MapMode
    1060             :         // and PrefSize
    1061           0 :         aTarget.SetPrefMapMode(rSource.GetPrefMapMode());
    1062           0 :         aTarget.SetPrefSize(rSource.GetPrefSize());
    1063           0 :         rSource = aTarget;
    1064          31 :     }
    1065             : }
    1066             : 
    1067             : //////////////////////////////////////////////////////////////////////////////
    1068             : 
    1069          32 : bool VCL_DLLPUBLIC usesClipActions(const GDIMetaFile& rSource)
    1070             : {
    1071          32 :     const sal_uLong nObjCount(rSource.GetActionSize());
    1072             : 
    1073          99 :     for(sal_uLong i(0); i < nObjCount; ++i)
    1074             :     {
    1075          98 :         const MetaAction* pAction(rSource.GetAction(i));
    1076          98 :         const sal_uInt16 nType(pAction->GetType());
    1077             : 
    1078          98 :         switch(nType)
    1079             :         {
    1080             :             case META_CLIPREGION_ACTION :
    1081             :             case META_ISECTRECTCLIPREGION_ACTION :
    1082             :             case META_ISECTREGIONCLIPREGION_ACTION :
    1083             :             case META_MOVECLIPREGION_ACTION :
    1084             :             {
    1085          31 :                 return true;
    1086             :             }
    1087             : 
    1088          67 :             default: break;
    1089             :         }
    1090             :     }
    1091             : 
    1092           1 :     return false;
    1093         465 : }
    1094             : 

Generated by: LCOV version 1.10