LCOV - code coverage report
Current view: top level - cppcanvas/source/mtfrenderer - emfplus.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 346 959 36.1 %
Date: 2015-06-13 12:38:46 Functions: 35 52 67.3 %
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 <tools/stream.hxx>
      21             : #include <vcl/metaact.hxx>
      22             : #include <vcl/graphicfilter.hxx>
      23             : #include <basegfx/tools/canvastools.hxx>
      24             : #include <basegfx/tools/gradienttools.hxx>
      25             : #include <basegfx/tools/tools.hxx>
      26             : #include <basegfx/numeric/ftools.hxx>
      27             : #include <basegfx/point/b2dpoint.hxx>
      28             : #include <basegfx/vector/b2dsize.hxx>
      29             : #include <basegfx/range/b2drange.hxx>
      30             : #include <basegfx/range/b2drectangle.hxx>
      31             : #include <basegfx/polygon/b2dlinegeometry.hxx>
      32             : #include <basegfx/polygon/b2dpolygon.hxx>
      33             : #include <basegfx/polygon/b2dpolygontools.hxx>
      34             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      35             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      36             : #include <vcl/canvastools.hxx>
      37             : #include <rtl/ustring.hxx>
      38             : #include <sal/alloca.h>
      39             : 
      40             : #include <com/sun/star/rendering/PathCapType.hpp>
      41             : #include <com/sun/star/rendering/PathJoinType.hpp>
      42             : #include <com/sun/star/rendering/TexturingMode.hpp>
      43             : #include <com/sun/star/rendering/XCanvas.hpp>
      44             : 
      45             : #include <bitmapaction.hxx>
      46             : #include <implrenderer.hxx>
      47             : #include <outdevstate.hxx>
      48             : #include <polypolyaction.hxx>
      49             : #include <textaction.hxx>
      50             : 
      51             : namespace
      52             : {
      53             : 
      54             : #define EmfPlusRecordTypeHeader 16385
      55             : #define EmfPlusRecordTypeEndOfFile 16386
      56             : #define EmfPlusRecordTypeGetDC 16388
      57             : #define EmfPlusRecordTypeObject 16392
      58             : #define EmfPlusRecordTypeFillRects 16394
      59             : #define EmfPlusRecordTypeFillPolygon 16396
      60             : #define EmfPlusRecordTypeDrawLines 16397
      61             : #define EmfPlusRecordTypeFillEllipse 16398
      62             : #define EmfPlusRecordTypeDrawEllipse 16399
      63             : #define EmfPlusRecordTypeFillPie 16400
      64             : #define EmfPlusRecordTypeFillPath 16404
      65             : #define EmfPlusRecordTypeDrawPath 16405
      66             : #define EmfPlusRecordTypeDrawImage 16410
      67             : #define EmfPlusRecordTypeDrawImagePoints 16411
      68             : #define EmfPlusRecordTypeDrawString 16412
      69             : #define EmfPlusRecordTypeSetRenderingOrigin 16413
      70             : #define EmfPlusRecordTypeSetAntiAliasMode 16414
      71             : #define EmfPlusRecordTypeSetTextRenderingHint 16415
      72             : #define EmfPlusRecordTypeSetInterpolationMode 16417
      73             : #define EmfPlusRecordTypeSetPixelOffsetMode 16418
      74             : #define EmfPlusRecordTypeSetCompositingQuality 16420
      75             : #define EmfPlusRecordTypeSave 16421
      76             : #define EmfPlusRecordTypeRestore 16422
      77             : #define EmfPlusRecordTypeBeginContainerNoParams 16424
      78             : #define EmfPlusRecordTypeEndContainer 16425
      79             : #define EmfPlusRecordTypeSetWorldTransform 16426
      80             : #define EmfPlusRecordTypeResetWorldTransform 16427
      81             : #define EmfPlusRecordTypeMultiplyWorldTransform 16428
      82             : #define EmfPlusRecordTypeSetPageTransform 16432
      83             : #define EmfPlusRecordTypeSetClipRect 16434
      84             : #define EmfPlusRecordTypeSetClipPath 16435
      85             : #define EmfPlusRecordTypeSetClipRegion 16436
      86             : #define EmfPlusRecordTypeDrawDriverString 16438
      87             : 
      88             : #define EmfPlusObjectTypeBrush 0x100
      89             : #define EmfPlusObjectTypePen 0x200
      90             : #define EmfPlusObjectTypePath 0x300
      91             : #define EmfPlusObjectTypeRegion 0x400
      92             : #define EmfPlusObjectTypeImage 0x500
      93             : #define EmfPlusObjectTypeFont 0x600
      94             : #define EmfPlusObjectTypeStringFormat 0x700
      95             : #define EmfPlusObjectTypeImageAttributes 0x800
      96             : #define EmfPlusObjectTypeCustomLineCap 0x900
      97             : 
      98             : #define EmfPlusRegionInitialStateInfinite 0x10000003
      99             : 
     100             : const sal_Int32 EmfPlusLineStyleSolid = 0x00000000;
     101             : const sal_Int32 EmfPlusLineStyleDash = 0x00000001;
     102             : const sal_Int32 EmfPlusLineStyleDot = 0x00000002;
     103             : const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
     104             : const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
     105             : const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
     106             : 
     107             : const sal_uInt32 EmfPlusCustomLineCapDataTypeDefault = 0x00000000;
     108             : const sal_uInt32 EmfPlusCustomLineCapDataTypeAdjustableArrow = 0x00000001;
     109             : 
     110             : const sal_uInt32 EmfPlusCustomLineCapDataFillPath = 0x00000001;
     111             : const sal_uInt32 EmfPlusCustomLineCapDataLinePath = 0x00000002;
     112             : 
     113             : const sal_uInt32 EmfPlusLineCapTypeSquare = 0x00000001;
     114             : const sal_uInt32 EmfPlusLineCapTypeRound = 0x00000002;
     115             : 
     116             : const sal_uInt32 EmfPlusLineJoinTypeMiter = 0x00000000;
     117             : const sal_uInt32 EmfPlusLineJoinTypeBevel = 0x00000001;
     118             : const sal_uInt32 EmfPlusLineJoinTypeRound = 0x00000002;
     119             : const sal_uInt32 EmfPlusLineJoinTypeMiterClipped = 0x00000003;
     120             : 
     121             : enum EmfPlusCombineMode
     122             : {
     123             :     EmfPlusCombineModeReplace = 0x00000000,
     124             :     EmfPlusCombineModeIntersect = 0x00000001,
     125             :     EmfPlusCombineModeUnion = 0x00000002,
     126             :     EmfPlusCombineModeXOR = 0x00000003,
     127             :     EmfPlusCombineModeExclude = 0x00000004,
     128             :     EmfPlusCombineModeComplement = 0x00000005
     129             : };
     130             : 
     131             : enum EmfPlusHatchStyle
     132             : {
     133             :     HatchStyleHorizontal = 0x00000000,
     134             :     HatchStyleVertical = 0x00000001,
     135             :     HatchStyleForwardDiagonal = 0x00000002,
     136             :     HatchStyleBackwardDiagonal = 0x00000003,
     137             :     HatchStyleLargeGrid = 0x00000004,
     138             :     HatchStyleDiagonalCross = 0x00000005,
     139             :     HatchStyle05Percent = 0x00000006,
     140             :     HatchStyle10Percent = 0x00000007,
     141             :     HatchStyle20Percent = 0x00000008,
     142             :     HatchStyle25Percent = 0x00000009,
     143             :     HatchStyle30Percent = 0x0000000A,
     144             :     HatchStyle40Percent = 0x0000000B,
     145             :     HatchStyle50Percent = 0x0000000C,
     146             :     HatchStyle60Percent = 0x0000000D,
     147             :     HatchStyle70Percent = 0x0000000E,
     148             :     HatchStyle75Percent = 0x0000000F,
     149             :     HatchStyle80Percent = 0x00000010,
     150             :     HatchStyle90Percent = 0x00000011,
     151             :     HatchStyleLightDownwardDiagonal = 0x00000012,
     152             :     HatchStyleLightUpwardDiagonal = 0x00000013,
     153             :     HatchStyleDarkDownwardDiagonal = 0x00000014,
     154             :     HatchStyleDarkUpwardDiagonal = 0x00000015,
     155             :     HatchStyleWideDownwardDiagonal = 0x00000016,
     156             :     HatchStyleWideUpwardDiagonal = 0x00000017,
     157             :     HatchStyleLightVertical = 0x00000018,
     158             :     HatchStyleLightHorizontal = 0x00000019,
     159             :     HatchStyleNarrowVertical = 0x0000001A,
     160             :     HatchStyleNarrowHorizontal = 0x0000001B,
     161             :     HatchStyleDarkVertical = 0x0000001C,
     162             :     HatchStyleDarkHorizontal = 0x0000001D,
     163             :     HatchStyleDashedDownwardDiagonal = 0x0000001E,
     164             :     HatchStyleDashedUpwardDiagonal = 0x0000001F,
     165             :     HatchStyleDashedHorizontal = 0x00000020,
     166             :     HatchStyleDashedVertical = 0x00000021,
     167             :     HatchStyleSmallConfetti = 0x00000022,
     168             :     HatchStyleLargeConfetti = 0x00000023,
     169             :     HatchStyleZigZag = 0x00000024,
     170             :     HatchStyleWave = 0x00000025,
     171             :     HatchStyleDiagonalBrick = 0x00000026,
     172             :     HatchStyleHorizontalBrick = 0x00000027,
     173             :     HatchStyleWeave = 0x00000028,
     174             :     HatchStylePlaid = 0x00000029,
     175             :     HatchStyleDivot = 0x0000002A,
     176             :     HatchStyleDottedGrid = 0x0000002B,
     177             :     HatchStyleDottedDiamond = 0x0000002C,
     178             :     HatchStyleShingle = 0x0000002D,
     179             :     HatchStyleTrellis = 0x0000002E,
     180             :     HatchStyleSphere = 0x0000002F,
     181             :     HatchStyleSmallGrid = 0x00000030,
     182             :     HatchStyleSmallCheckerBoard = 0x00000031,
     183             :     HatchStyleLargeCheckerBoard = 0x00000032,
     184             :     HatchStyleOutlinedDiamond = 0x00000033,
     185             :     HatchStyleSolidDiamond = 0x00000034
     186             : };
     187             : 
     188           0 : const char* emfTypeToName(sal_uInt16 type)
     189             : {
     190           0 :     switch(type)
     191             :     {
     192           0 :         case EmfPlusRecordTypeHeader: return "EmfPlusRecordTypeHeader";
     193           0 :         case EmfPlusRecordTypeEndOfFile: return "EmfPlusRecordTypeEndOfFile";
     194           0 :         case EmfPlusRecordTypeGetDC: return "EmfPlusRecordTypeGetDC";
     195           0 :         case EmfPlusRecordTypeObject: return "EmfPlusRecordTypeObject";
     196           0 :         case EmfPlusRecordTypeFillRects: return "EmfPlusRecordTypeFillRects";
     197           0 :         case EmfPlusRecordTypeFillPolygon: return "EmfPlusRecordTypeFillPolygon";
     198           0 :         case EmfPlusRecordTypeDrawLines: return "EmfPlusRecordTypeDrawLines";
     199           0 :         case EmfPlusRecordTypeFillEllipse: return "EmfPlusRecordTypeFillEllipse";
     200           0 :         case EmfPlusRecordTypeDrawEllipse: return "EmfPlusRecordTypeDrawEllipse";
     201           0 :         case EmfPlusRecordTypeFillPie: return "EmfPlusRecordTypeFillPie";
     202           0 :         case EmfPlusRecordTypeFillPath: return "EmfPlusRecordTypeFillPath";
     203           0 :         case EmfPlusRecordTypeDrawPath: return "EmfPlusRecordTypeDrawPath";
     204           0 :         case EmfPlusRecordTypeDrawImage: return "EmfPlusRecordTypeDrawImage";
     205           0 :         case EmfPlusRecordTypeDrawImagePoints: return "EmfPlusRecordTypeDrawImagePoints";
     206           0 :         case EmfPlusRecordTypeDrawString: return "EmfPlusRecordTypeDrawString";
     207           0 :         case EmfPlusRecordTypeSetRenderingOrigin: return "EmfPlusRecordTypeSetRenderingOrigin";
     208           0 :         case EmfPlusRecordTypeSetAntiAliasMode: return "EmfPlusRecordTypeSetAntiAliasMode";
     209           0 :         case EmfPlusRecordTypeSetTextRenderingHint: return "EmfPlusRecordTypeSetTextRenderingHint";
     210           0 :         case EmfPlusRecordTypeSetInterpolationMode: return "EmfPlusRecordTypeSetInterpolationMode";
     211           0 :         case EmfPlusRecordTypeSetPixelOffsetMode: return "EmfPlusRecordTypeSetPixelOffsetMode";
     212           0 :         case EmfPlusRecordTypeSetCompositingQuality: return "EmfPlusRecordTypeSetCompositingQuality";
     213           0 :         case EmfPlusRecordTypeSave: return "EmfPlusRecordTypeSave";
     214           0 :         case EmfPlusRecordTypeRestore: return "EmfPlusRecordTypeRestore";
     215           0 :         case EmfPlusRecordTypeBeginContainerNoParams: return "EmfPlusRecordTypeBeginContainerNoParams";
     216           0 :         case EmfPlusRecordTypeEndContainer: return "EmfPlusRecordTypeEndContainer";
     217           0 :         case EmfPlusRecordTypeSetWorldTransform: return "EmfPlusRecordTypeSetWorldTransform";
     218           0 :         case EmfPlusRecordTypeResetWorldTransform: return "EmfPlusRecordTypeResetWorldTransform";
     219           0 :         case EmfPlusRecordTypeMultiplyWorldTransform: return "EmfPlusRecordTypeMultiplyWorldTransform";
     220           0 :         case EmfPlusRecordTypeSetPageTransform: return "EmfPlusRecordTypeSetPageTransform";
     221           0 :         case EmfPlusRecordTypeSetClipRect: return "EmfPlusRecordTypeSetClipRect";
     222           0 :         case EmfPlusRecordTypeSetClipPath: return "EmfPlusRecordTypeSetClipPath";
     223           0 :         case EmfPlusRecordTypeSetClipRegion: return "EmfPlusRecordTypeSetClipRegion";
     224           0 :         case EmfPlusRecordTypeDrawDriverString: return "EmfPlusRecordTypeDrawDriverString";
     225             :     }
     226           0 :     return "";
     227             : }
     228             : 
     229             : } // anonymous namespace
     230             : 
     231             : using namespace ::com::sun::star;
     232             : using namespace ::basegfx;
     233             : 
     234             : namespace cppcanvas
     235             : {
     236             :     namespace internal
     237             :     {
     238             :         struct EMFPPath : public EMFPObject
     239             :         {
     240             :             ::basegfx::B2DPolyPolygon    aPolygon;
     241             :             sal_Int32                    nPoints;
     242             :             float*                       pPoints;
     243             :             sal_uInt8*                   pPointTypes;
     244             : 
     245             :         public:
     246           6 :             EMFPPath (sal_Int32 _nPoints, bool bLines = false)
     247           6 :             {
     248           6 :                 if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
     249           0 :                     _nPoints = SAL_MAX_INT32/(2*sizeof(float));
     250           6 :                 nPoints = _nPoints;
     251           6 :                 pPoints = new float [nPoints*2];
     252           6 :                 if (!bLines)
     253           6 :                     pPointTypes = new sal_uInt8 [_nPoints];
     254             :                 else
     255           0 :                     pPointTypes = NULL;
     256           6 :             }
     257             : 
     258          12 :             virtual ~EMFPPath ()
     259          12 :             {
     260           6 :                 delete [] pPoints;
     261           6 :                 delete [] pPointTypes;
     262          12 :             }
     263             : 
     264             :             // TODO: remove rR argument when debug code is not longer needed
     265           6 :             void Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
     266             :             {
     267          92 :                 for (int i = 0; i < nPoints; i ++) {
     268          86 :                     if (pathFlags & 0x4000) {
     269             :                         // EMFPlusPoint: stored in signed short 16bit integer format
     270             :                         sal_Int16 x, y;
     271             : 
     272           0 :                         s.ReadInt16( x ).ReadInt16( y );
     273             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPoint [x,y]: " << x << "," << y);
     274           0 :                         pPoints [i*2] = x;
     275           0 :                         pPoints [i*2 + 1] = y;
     276          86 :                     } else if (!(pathFlags & 0xC000)) {
     277             :                         // EMFPlusPointF: stored in Single (float) format
     278          86 :                         s.ReadFloat( pPoints [i*2] ).ReadFloat( pPoints [i*2 + 1] );
     279             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPointF [x,y]: " << pPoints [i*2] << "," << pPoints [i*2 + 1]);
     280             :                     } else { //if (pathFlags & 0x8000)
     281             :                         // EMFPlusPointR: points are stored in EMFPlusInteger7 or
     282             :                         // EMFPlusInteger15 objects, see section 2.2.2.21/22
     283             :                         SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - parse EMFPlusPointR object (section 2.2.1.6)");
     284             :                     }
     285             : 
     286             :                 }
     287             : 
     288           6 :                 if (pPointTypes)
     289          92 :                     for (int i = 0; i < nPoints; i ++) {
     290          86 :                         s.ReadUChar( pPointTypes [i] );
     291             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes [i]);
     292             :                     }
     293             : 
     294           6 :                 aPolygon.clear ();
     295             : 
     296             : #if OSL_DEBUG_LEVEL > 1
     297             :                 const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
     298             : 
     299             :                 SAL_INFO ("cppcanvas.emf",
     300             :                           "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << aBounds.getWidth () << "x" << aBounds.getHeight () << " (mapped)");
     301             : #else
     302             :                 (void) rR; // avoid warnings
     303             : #endif
     304           6 :             }
     305             : 
     306          10 :             ::basegfx::B2DPolyPolygon& GetPolygon (ImplRenderer& rR, bool bMapIt = true)
     307             :             {
     308          10 :                 ::basegfx::B2DPolygon polygon;
     309             : 
     310          10 :                 aPolygon.clear ();
     311             : 
     312          10 :                 int last_normal = 0, p = 0;
     313          20 :                 ::basegfx::B2DPoint prev, mapped;
     314          10 :                 bool hasPrev = false;
     315         176 :                 for (int i = 0; i < nPoints; i ++) {
     316         166 :                     if (p && pPointTypes && (pPointTypes [i] == 0)) {
     317           0 :                         aPolygon.append (polygon);
     318           0 :                         last_normal = i;
     319           0 :                         p = 0;
     320           0 :                         polygon.clear ();
     321             :                     }
     322             : 
     323         166 :                     if (bMapIt)
     324         166 :                         mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
     325             :                     else
     326           0 :                         mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
     327         166 :                     if (pPointTypes) {
     328         166 :                         if ((pPointTypes [i] & 0x07) == 3) {
     329          48 :                             if (((i - last_normal )% 3) == 1) {
     330          16 :                                 polygon.setNextControlPoint (p - 1, mapped);
     331             :                                 SAL_INFO ("cppcanvas.emf", "polygon append  next: " << p - 1 << " mapped: " << mapped.getX () << "," << mapped.getY ());
     332          16 :                                 continue;
     333          32 :                             } else if (((i - last_normal) % 3) == 2) {
     334          16 :                                 prev = mapped;
     335          16 :                                 hasPrev = true;
     336          16 :                                 continue;
     337             :                             }
     338             :                         } else
     339         118 :                             last_normal = i;
     340             :                     }
     341         134 :                     polygon.append (mapped);
     342             :                     SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints [i*2] << "," << pPoints [i*2 + 1] << " mapped: " << mapped.getX () << ":" << mapped.getY ());
     343         134 :                     if (hasPrev) {
     344          16 :                         polygon.setPrevControlPoint (p, prev);
     345             :                         SAL_INFO ("cppcanvas.emf", "polygon append  prev: " << p << " mapped: " << prev.getX () << "," << prev.getY ());
     346          16 :                         hasPrev = false;
     347             :                     }
     348         134 :                     p ++;
     349         134 :                     if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
     350          42 :                         polygon.setClosed (true);
     351          42 :                         aPolygon.append (polygon);
     352             :                         SAL_INFO ("cppcanvas.emf", "close polygon");
     353          42 :                         last_normal = i + 1;
     354          42 :                         p = 0;
     355          42 :                         polygon.clear ();
     356             :                     }
     357             :                 }
     358             : 
     359          10 :                 if (polygon.count ()) {
     360           0 :                     aPolygon.append (polygon);
     361             : 
     362             : #if OSL_DEBUG_LEVEL > 1
     363             :                     for (unsigned int i=0; i<aPolygon.count(); i++) {
     364             :                         polygon = aPolygon.getB2DPolygon(i);
     365             :                         SAL_INFO ("cppcanvas.emf", "polygon: " << i);
     366             :                         for (unsigned int j=0; j<polygon.count(); j++) {
     367             :                             ::basegfx::B2DPoint point = polygon.getB2DPoint(j);
     368             :                             SAL_INFO ("cppcanvas.emf", "point: " << point.getX() << "," << point.getY());
     369             :                             if (polygon.isPrevControlPointUsed(j)) {
     370             :                                 point = polygon.getPrevControlPoint(j);
     371             :                                 SAL_INFO ("cppcanvas.emf", "prev: " << point.getX() << "," << point.getY());
     372             :                             }
     373             :                             if (polygon.isNextControlPointUsed(j)) {
     374             :                                 point = polygon.getNextControlPoint(j);
     375             :                                 SAL_INFO ("cppcanvas.emf", "next: " << point.getX() << "," << point.getY());
     376             :                             }
     377             :                         }
     378             :                     }
     379             : #endif
     380             :                 }
     381             : 
     382          20 :                 return aPolygon;
     383             :             }
     384             :         };
     385             : 
     386             :         struct EMFPRegion : public EMFPObject
     387             :         {
     388             :             sal_Int32 parts;
     389             :             sal_Int32 *combineMode;
     390             :             sal_Int32 initialState;
     391             :             EMFPPath *initialPath;
     392             :             float ix, iy, iw, ih;
     393             : 
     394           6 :             EMFPRegion ()
     395             :                 : parts(0)
     396             :                 , combineMode(NULL)
     397             :                 , initialState(0)
     398             :                 , initialPath(NULL)
     399             :                 , ix(0.0)
     400             :                 , iy(0.0)
     401             :                 , iw(0.0)
     402           6 :                 , ih(0.0)
     403             :             {
     404           6 :             }
     405             : 
     406          12 :             virtual ~EMFPRegion ()
     407          12 :             {
     408           6 :                 if (combineMode) {
     409           0 :                     delete [] combineMode;
     410           0 :                     combineMode = NULL;
     411             :                 }
     412           6 :                 if (initialPath) {
     413           0 :                     delete initialPath;
     414           0 :                     initialPath = NULL;
     415             :                 }
     416          12 :             }
     417             : 
     418           6 :             void Read (SvStream& s)
     419             :             {
     420             :                 sal_uInt32 header;
     421             : 
     422           6 :                 s.ReadUInt32( header ).ReadInt32( parts );
     423             : 
     424             :                 SAL_INFO ("cppcanvas.emf", "EMF+\tregion");
     425             :                 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " parts: " << parts << std::dec );
     426             : 
     427           6 :                 if (parts) {
     428           0 :                     if( parts<0 || sal_uInt32(parts)>SAL_MAX_INT32/sizeof(sal_Int32) )
     429           0 :                         parts = SAL_MAX_INT32/sizeof(sal_Int32);
     430             : 
     431           0 :                     combineMode = new sal_Int32 [parts];
     432             : 
     433           0 :                     for (int i = 0; i < parts; i ++) {
     434           0 :                         s.ReadInt32( combineMode [i] );
     435             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tcombine mode [" << i << "]: 0x" << std::hex << combineMode [i] << std::dec);
     436             :                     }
     437             :                 }
     438             : 
     439           6 :                 s.ReadInt32( initialState );
     440             :                 SAL_INFO ("cppcanvas.emf", "EMF+\tinitial state: 0x" << std::hex << initialState << std::dec);
     441           6 :             }
     442             :         };
     443             : 
     444             :         struct EMFPBrush : public EMFPObject
     445             :         {
     446             :             ::Color solidColor;
     447             :             sal_uInt32 type;
     448             :             sal_uInt32 additionalFlags;
     449             : 
     450             :             /* linear gradient */
     451             :             sal_Int32 wrapMode;
     452             :             float areaX, areaY, areaWidth, areaHeight;
     453             :             ::Color secondColor; // first color is stored in solidColor;
     454             :             XForm transformation;
     455             :             bool hasTransformation;
     456             :             sal_Int32 blendPoints;
     457             :             float* blendPositions;
     458             :             float* blendFactors;
     459             :             sal_Int32 colorblendPoints;
     460             :             float* colorblendPositions;
     461             :             ::Color* colorblendColors;
     462             :             sal_Int32 surroundColorsNumber;
     463             :             ::Color* surroundColors;
     464             :             EMFPPath *path;
     465             :             EmfPlusHatchStyle hatchStyle;
     466             : 
     467             :         public:
     468           4 :             EMFPBrush ()
     469             :                 : type(0)
     470             :                 , additionalFlags(0)
     471             :                 , wrapMode(0)
     472             :                 , areaX(0.0)
     473             :                 , areaY(0.0)
     474             :                 , areaWidth(0.0)
     475             :                 , areaHeight(0.0)
     476             :                 , hasTransformation(false)
     477             :                 , blendPoints(0)
     478             :                 , blendPositions(NULL)
     479             :                 , blendFactors(NULL)
     480             :                 , colorblendPoints(0)
     481             :                 , colorblendPositions(NULL)
     482             :                 , colorblendColors(NULL)
     483             :                 , surroundColorsNumber(0)
     484             :                 , surroundColors(NULL)
     485             :                 , path(NULL)
     486           4 :                 , hatchStyle(HatchStyleHorizontal)
     487             :             {
     488           4 :             }
     489             : 
     490           4 :             virtual ~EMFPBrush ()
     491           8 :             {
     492           4 :                 if (blendPositions != NULL) {
     493           0 :                     delete[] blendPositions;
     494           0 :                     blendPositions = NULL;
     495             :                 }
     496           4 :                 if (colorblendPositions != NULL) {
     497           0 :                     delete[] colorblendPositions;
     498           0 :                     colorblendPositions = NULL;
     499             :                 }
     500           4 :                 if (colorblendColors != NULL) {
     501           0 :                     delete[] colorblendColors;
     502           0 :                     colorblendColors = NULL;
     503             :                 }
     504           4 :                 if (surroundColors != NULL) {
     505           0 :                     delete[] surroundColors;
     506           0 :                     surroundColors = NULL;
     507             :                 }
     508           4 :                 if (path) {
     509           0 :                     delete path;
     510           0 :                     path = NULL;
     511             :                 }
     512           4 :             }
     513             : 
     514             :             sal_uInt32 GetType() const { return type; }
     515           4 :             const ::Color& GetColor() const { return solidColor; }
     516             : 
     517           4 :             void Read (SvStream& s, ImplRenderer& rR)
     518             :             {
     519             :                 sal_uInt32 header;
     520             : 
     521           4 :                 s.ReadUInt32( header ).ReadUInt32( type );
     522             : 
     523             :                 SAL_INFO ("cppcanvas.emf", "EMF+\tbrush");
     524             :                 SAL_INFO ("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec);
     525             : 
     526           4 :                 switch (type) {
     527             :                 case 0:
     528             :                     {
     529             :                         sal_uInt32 color;
     530             : 
     531           4 :                         s.ReadUInt32( color );
     532           4 :                         solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     533             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tsolid color: 0x" << std::hex << color << std::dec);
     534           4 :                         break;
     535             :                     }
     536             :                 case 1:
     537             :                     {
     538             :                         sal_uInt32 style;
     539             :                         sal_uInt32 foregroundColor;
     540             :                         sal_uInt32 backgroundColor;
     541           0 :                         s.ReadUInt32( style );
     542           0 :                         s.ReadUInt32( foregroundColor );
     543           0 :                         s.ReadUInt32( backgroundColor );
     544             : 
     545           0 :                         hatchStyle = static_cast<EmfPlusHatchStyle>(style);
     546           0 :                         solidColor  = ::Color(0xff - (foregroundColor >> 24), (foregroundColor >> 16) & 0xff, (foregroundColor >> 8) & 0xff, foregroundColor & 0xff);
     547           0 :                         secondColor = ::Color(0xff - (backgroundColor >> 24), (backgroundColor >> 16) & 0xff, (backgroundColor >> 8) & 0xff, backgroundColor & 0xff);
     548             :                         SAL_INFO ("cppcanvas.emf", "EMF+\thatch style " << style << " foregroundcolor: 0x" << solidColor.AsRGBHexString() << " background 0x" << secondColor.AsRGBHexString());
     549           0 :                         break;
     550             :                     }
     551             :                 // path gradient
     552             :                 case 3:
     553             :                     {
     554           0 :                         s.ReadUInt32( additionalFlags ).ReadInt32( wrapMode );
     555             : 
     556             :                         SAL_INFO ("cppcanvas.emf", "EMF+\tpath gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
     557             : 
     558             :                         sal_uInt32 color;
     559             : 
     560           0 :                         s.ReadUInt32( color );
     561           0 :                         solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     562             :                         SAL_INFO("cppcanvas.emf", "EMF+\tcenter color: 0x" << std::hex << color << std::dec);
     563             : 
     564           0 :                         s.ReadFloat( areaX ).ReadFloat( areaY );
     565             :                         SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX << "," << areaY);
     566             : 
     567           0 :                         s.ReadInt32( surroundColorsNumber );
     568             :                         SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber);
     569             : 
     570           0 :                         if( surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32/sizeof(::Color) )
     571           0 :                             surroundColorsNumber = SAL_MAX_INT32/sizeof(::Color);
     572             : 
     573           0 :                         surroundColors = new ::Color [surroundColorsNumber];
     574           0 :                         for (int i = 0; i < surroundColorsNumber; i++) {
     575           0 :                             s.ReadUInt32( color );
     576           0 :                             surroundColors[i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     577           0 :                             if (i == 0)
     578           0 :                                 secondColor = surroundColors [0];
     579             :                             SAL_INFO("cppcanvas.emf", "EMF+\tsurround color[" << i << "]: 0x" << std::hex << color << std::dec);
     580             :                         }
     581             : 
     582           0 :                         if (additionalFlags & 0x01) {
     583             :                             sal_Int32 pathLength;
     584             : 
     585           0 :                             s.ReadInt32( pathLength );
     586             :                             SAL_INFO("cppcanvas.emf", "EMF+\tpath length: " << pathLength);
     587             : 
     588           0 :                             sal_Size pos = s.Tell ();
     589             : 
     590             :                             sal_uInt32 pathHeader;
     591             :                             sal_Int32 pathPoints, pathFlags;
     592           0 :                             s.ReadUInt32( pathHeader ).ReadInt32( pathPoints ).ReadInt32( pathFlags );
     593             : 
     594             :                             SAL_INFO("cppcanvas.emf", "EMF+\tpath (brush path gradient)");
     595             :                             SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
     596             : 
     597           0 :                             path = new EMFPPath (pathPoints);
     598           0 :                             path->Read (s, pathFlags, rR);
     599             : 
     600           0 :                             s.Seek (pos + pathLength);
     601             : 
     602           0 :                             const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (path->GetPolygon (rR, false)));
     603           0 :                             areaWidth = aBounds.getWidth ();
     604           0 :                             areaHeight = aBounds.getHeight ();
     605             : 
     606             :                             SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << " " << aBounds.getWidth () << "x" << aBounds.getHeight ());
     607             : 
     608             : 
     609           0 :                         if (additionalFlags & 0x02) {
     610             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
     611           0 :                             ReadXForm( s, transformation );
     612           0 :                             hasTransformation = true;
     613             :                             SAL_INFO("cppcanvas.emf",
     614             :                                     "EMF+\tm11: "   << transformation.eM11 << " m12: " << transformation.eM12 <<
     615             :                                     "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
     616             :                                     "\nEMF+\tdx: "  << transformation.eDx  << " dy: "  << transformation.eDy);
     617             : 
     618             :                         }
     619           0 :                         if (additionalFlags & 0x08) {
     620           0 :                             s.ReadInt32( blendPoints );
     621             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
     622           0 :                             if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
     623           0 :                                 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
     624           0 :                             blendPositions = new float [2*blendPoints];
     625           0 :                             blendFactors = blendPositions + blendPoints;
     626           0 :                             for (int i=0; i < blendPoints; i ++) {
     627           0 :                                 s.ReadFloat( blendPositions [i] );
     628             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
     629             :                             }
     630           0 :                             for (int i=0; i < blendPoints; i ++) {
     631           0 :                                 s.ReadFloat( blendFactors [i] );
     632             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
     633             :                             }
     634             :                         }
     635             : 
     636           0 :                         if (additionalFlags & 0x04) {
     637           0 :                             s.ReadInt32( colorblendPoints );
     638             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
     639           0 :                             if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
     640           0 :                                 colorblendPoints = SAL_MAX_INT32/sizeof(float);
     641           0 :                             if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
     642           0 :                                 colorblendPoints = SAL_MAX_INT32/sizeof(::Color);
     643           0 :                             colorblendPositions = new float [colorblendPoints];
     644           0 :                             colorblendColors = new ::Color [colorblendPoints];
     645           0 :                             for (int i=0; i < colorblendPoints; i ++) {
     646           0 :                                 s.ReadFloat( colorblendPositions [i] );
     647             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
     648             :                             }
     649           0 :                             for (int i=0; i < colorblendPoints; i ++) {
     650           0 :                                 s.ReadUInt32( color );
     651           0 :                                 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     652             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
     653             :                             }
     654             :                         }
     655             :                         }
     656           0 :                         break;
     657             :                     }
     658             :                 // linear gradient
     659             :                 case 4:
     660             :                     {
     661           0 :                         s.ReadUInt32( additionalFlags ).ReadInt32( wrapMode );
     662             : 
     663             :                         SAL_INFO("cppcanvas.emf", "EMF+\tlinear gradient, additional flags: 0x" << std::hex << additionalFlags << std::dec);
     664             : 
     665           0 :                         s.ReadFloat( areaX ).ReadFloat( areaY ).ReadFloat( areaWidth ).ReadFloat( areaHeight );
     666             : 
     667             :                         SAL_INFO("cppcanvas.emf", "EMF+\tarea: " << areaX << "," << areaY << " - " << areaWidth << "x" << areaHeight);
     668             : 
     669             :                         sal_uInt32 color;
     670             : 
     671           0 :                         s.ReadUInt32( color );
     672           0 :                         solidColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     673             :                         SAL_INFO("cppcanvas.emf", "EMF+\tfirst color: 0x" << std::hex << color << std::dec);
     674             : 
     675           0 :                         s.ReadUInt32( color );
     676           0 :                         secondColor = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     677             :                         SAL_INFO("cppcanvas.emf", "EMF+\tsecond color: 0x" << std::hex << color << std::dec);
     678             : 
     679             :                         // repeated colors, unknown meaning, see http://www.aces.uiuc.edu/~jhtodd/Metafile/MetafileRecords/ObjectBrush.html
     680           0 :                         s.ReadUInt32( color );
     681           0 :                         s.ReadUInt32( color );
     682             : 
     683           0 :                         if (additionalFlags & 0x02) {
     684             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
     685           0 :                             ReadXForm( s, transformation );
     686           0 :                             hasTransformation = true;
     687             :                             SAL_INFO("cppcanvas.emf",
     688             :                                     "EMF+\tm11: "   << transformation.eM11 << " m12: " << transformation.eM12 <<
     689             :                                     "\nEMF+\tm21: " << transformation.eM21 << " m22: " << transformation.eM22 <<
     690             :                                     "\nEMF+\tdx: "  << transformation.eDx  << " dy: "  << transformation.eDy);
     691             :                         }
     692           0 :                         if (additionalFlags & 0x08) {
     693           0 :                             s.ReadInt32( blendPoints );
     694             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
     695           0 :                             if( blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
     696           0 :                                 blendPoints = SAL_MAX_INT32/(2*sizeof(float));
     697           0 :                             blendPositions = new float [2*blendPoints];
     698           0 :                             blendFactors = blendPositions + blendPoints;
     699           0 :                             for (int i=0; i < blendPoints; i ++) {
     700           0 :                                 s.ReadFloat( blendPositions [i] );
     701             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions [i]);
     702             :                             }
     703           0 :                             for (int i=0; i < blendPoints; i ++) {
     704           0 :                                 s.ReadFloat( blendFactors [i] );
     705             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors [i]);
     706             :                             }
     707             :                         }
     708             : 
     709           0 :                         if (additionalFlags & 0x04) {
     710           0 :                             s.ReadInt32( colorblendPoints );
     711             :                             SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
     712           0 :                             if( colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(float) )
     713           0 :                                 colorblendPoints = SAL_MAX_INT32/sizeof(float);
     714           0 :                             if( sal_uInt32(colorblendPoints)>SAL_MAX_INT32/sizeof(::Color) )
     715           0 :                                 colorblendPoints = sal_uInt32(SAL_MAX_INT32)/sizeof(::Color);
     716           0 :                             colorblendPositions = new float [colorblendPoints];
     717           0 :                             colorblendColors = new ::Color [colorblendPoints];
     718           0 :                             for (int i=0; i < colorblendPoints; i ++) {
     719           0 :                                 s.ReadFloat( colorblendPositions [i] );
     720             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions [i]);
     721             :                             }
     722           0 :                             for (int i=0; i < colorblendPoints; i ++) {
     723           0 :                                 s.ReadUInt32( color );
     724           0 :                                 colorblendColors [i] = ::Color (0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
     725             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
     726             :                             }
     727             :                         }
     728             : 
     729           0 :                         break;
     730             :                     }
     731             :                 default:
     732             :                     SAL_INFO("cppcanvas.emf", "EMF+\tunhandled brush type: " << std::hex << type << std::dec);
     733             :                 }
     734           4 :             }
     735             :         };
     736             : 
     737             :         /// Convert stroke caps between EMF+ and rendering API
     738           0 :         sal_Int8 lcl_convertStrokeCap(sal_uInt32 nEmfStroke)
     739             :         {
     740           0 :             switch (nEmfStroke)
     741             :             {
     742           0 :                 case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE;
     743           0 :                 case EmfPlusLineCapTypeRound:  return rendering::PathCapType::ROUND;
     744             :             }
     745             : 
     746             :             // we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
     747             :             // so return BUTT always
     748           0 :             return rendering::PathCapType::BUTT;
     749             :         }
     750             : 
     751           4 :         sal_Int8 lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin)
     752             :         {
     753           4 :             switch (nEmfLineJoin)
     754             :             {
     755             :                 case EmfPlusLineJoinTypeMiter:        // fall-through
     756           0 :                 case EmfPlusLineJoinTypeMiterClipped: return rendering::PathJoinType::MITER;
     757           0 :                 case EmfPlusLineJoinTypeBevel:        return rendering::PathJoinType::BEVEL;
     758           4 :                 case EmfPlusLineJoinTypeRound:        return rendering::PathJoinType::ROUND;
     759             :             }
     760             :             assert(false); // Line Join type isn't in specification.
     761           0 :             return 0;
     762             :         }
     763             : 
     764             :         struct EMFPCustomLineCap : public EMFPObject
     765             :         {
     766             :             sal_uInt32 type;
     767             :             sal_uInt32 strokeStartCap, strokeEndCap, strokeJoin;
     768             :             float miterLimit;
     769             :             basegfx::B2DPolyPolygon polygon;
     770             :             bool mbIsFilled;
     771             : 
     772             :         public:
     773           0 :             EMFPCustomLineCap()
     774             :                 : EMFPObject()
     775             :                 , type(0)
     776             :                 , strokeStartCap(0)
     777             :                 , strokeEndCap(0)
     778             :                 , strokeJoin(0)
     779             :                 , miterLimit(0.0)
     780           0 :                 , mbIsFilled(false)
     781             :             {
     782           0 :             }
     783             : 
     784           0 :             virtual ~EMFPCustomLineCap()
     785           0 :             {
     786           0 :             }
     787             : 
     788           0 :             void SetAttributes(rendering::StrokeAttributes& aAttributes)
     789             :             {
     790           0 :                 aAttributes.StartCapType = lcl_convertStrokeCap(strokeStartCap);
     791           0 :                 aAttributes.EndCapType = lcl_convertStrokeCap(strokeEndCap);
     792           0 :                 aAttributes.JoinType = lcl_convertLineJoinType(strokeJoin);
     793             : 
     794           0 :                 aAttributes.MiterLimit = miterLimit;
     795           0 :             }
     796             : 
     797           0 :             void ReadPath(SvStream& s, ImplRenderer& rR, bool bFill)
     798             :             {
     799             :                 sal_Int32 pathLength;
     800           0 :                 s.ReadInt32( pathLength );
     801             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath length: " << pathLength);
     802             : 
     803             :                 sal_uInt32 pathHeader;
     804             :                 sal_Int32 pathPoints, pathFlags;
     805           0 :                 s.ReadUInt32( pathHeader ).ReadInt32( pathPoints ).ReadInt32( pathFlags );
     806             : 
     807             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\tpath (custom cap line path)");
     808             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << pathHeader << " points: " << std::dec << pathPoints << " additional flags: 0x" << std::hex << pathFlags << std::dec );
     809             : 
     810           0 :                 EMFPPath path(pathPoints);
     811           0 :                 path.Read(s, pathFlags, rR);
     812             : 
     813           0 :                 polygon = path.GetPolygon(rR, false);
     814           0 :                 mbIsFilled = bFill;
     815             : 
     816             :                 // transformation to convert the path to what LibreOffice
     817             :                 // expects
     818           0 :                 B2DHomMatrix aMatrix;
     819           0 :                 aMatrix.scale(1.0, -1.0);
     820             : 
     821           0 :                 polygon.transform(aMatrix);
     822           0 :             };
     823             : 
     824           0 :             void Read (SvStream& s, ImplRenderer& rR)
     825             :             {
     826             :                 sal_uInt32 header;
     827             : 
     828           0 :                 s.ReadUInt32( header ).ReadUInt32( type );
     829             : 
     830             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\tcustom cap");
     831             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\theader: 0x" << std::hex << header << " type: " << type << std::dec);
     832             : 
     833           0 :                 if (type == EmfPlusCustomLineCapDataTypeDefault)
     834             :                 {
     835             :                     sal_uInt32 customLineCapDataFlags, baseCap;
     836             :                     float baseInset;
     837             :                     float widthScale;
     838             :                     float fillHotSpotX, fillHotSpotY, strokeHotSpotX, strokeHotSpotY;
     839             : 
     840           0 :                     s.ReadUInt32( customLineCapDataFlags ).ReadUInt32( baseCap ).ReadFloat( baseInset )
     841           0 :                      .ReadUInt32( strokeStartCap ).ReadUInt32( strokeEndCap ).ReadUInt32( strokeJoin )
     842           0 :                      .ReadFloat( miterLimit ).ReadFloat( widthScale )
     843           0 :                      .ReadFloat( fillHotSpotX ).ReadFloat( fillHotSpotY ).ReadFloat( strokeHotSpotX ).ReadFloat( strokeHotSpotY );
     844             : 
     845             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomLineCapDataFlags: 0x" << std::hex << customLineCapDataFlags);
     846             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseCap: 0x" << std::hex << baseCap);
     847             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tbaseInset: " << baseInset);
     848             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeStartCap: 0x" << std::hex << strokeStartCap);
     849             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeEndCap: 0x" << std::hex << strokeEndCap);
     850             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tstrokeJoin: 0x" << std::hex << strokeJoin);
     851             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tmiterLimit: " << miterLimit);
     852             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\twidthScale: " << widthScale);
     853             : 
     854           0 :                     if (customLineCapDataFlags & EmfPlusCustomLineCapDataFillPath)
     855             :                     {
     856           0 :                         ReadPath(s, rR, true);
     857             :                     }
     858             : 
     859           0 :                     if (customLineCapDataFlags & EmfPlusCustomLineCapDataLinePath)
     860             :                     {
     861           0 :                         ReadPath(s, rR, false);
     862             :                     }
     863             :                 }
     864           0 :                 else if (type == EmfPlusCustomLineCapDataTypeAdjustableArrow)
     865             :                 {
     866             :                     // TODO only reads the data, does not use them [I've had
     867             :                     // no test document to be able to implement it]
     868             : 
     869             :                     sal_Int32 width, height, middleInset, fillState, lineStartCap;
     870             :                     sal_Int32 lineEndCap, lineJoin, widthScale;
     871             :                     float fillHotSpotX, fillHotSpotY, lineHotSpotX, lineHotSpotY;
     872             : 
     873           0 :                     s.ReadInt32( width ).ReadInt32( height ).ReadInt32( middleInset ).ReadInt32( fillState ).ReadInt32( lineStartCap )
     874           0 :                      .ReadInt32( lineEndCap ).ReadInt32( lineJoin ).ReadFloat( miterLimit ).ReadInt32( widthScale )
     875           0 :                      .ReadFloat( fillHotSpotX ).ReadFloat( fillHotSpotY ).ReadFloat( lineHotSpotX ).ReadFloat( lineHotSpotY );
     876             : 
     877             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - actually read EmfPlusCustomLineCapArrowData object (section 2.2.2.12)");
     878             :                 }
     879           0 :             }
     880             :         };
     881             : 
     882             :         struct EMFPPen : public EMFPBrush
     883             :         {
     884             :             XForm transformation;
     885             :             float width;
     886             :             sal_Int32 startCap;
     887             :             sal_Int32 endCap;
     888             :             sal_Int32 lineJoin;
     889             :             float mitterLimit;
     890             :             sal_Int32 dashStyle;
     891             :             sal_Int32 dashCap;
     892             :             float dashOffset;
     893             :             sal_Int32 dashPatternLen;
     894             :             float *dashPattern;
     895             :             sal_Int32 alignment;
     896             :             sal_Int32 compoundArrayLen;
     897             :             float *compoundArray;
     898             :             sal_Int32 customStartCapLen;
     899             :             EMFPCustomLineCap *customStartCap;
     900             :             sal_Int32 customEndCapLen;
     901             :             EMFPCustomLineCap *customEndCap;
     902             : 
     903             :         public:
     904           4 :             EMFPPen ()
     905             :                 : EMFPBrush()
     906             :                 , width(0.0)
     907             :                 , startCap(0)
     908             :                 , endCap(0)
     909             :                 , lineJoin(0)
     910             :                 , mitterLimit(0.0)
     911             :                 , dashStyle(0)
     912             :                 , dashCap(0)
     913             :                 , dashOffset(0.0)
     914             :                 , dashPatternLen(0)
     915             :                 , dashPattern(NULL)
     916             :                 , alignment(0)
     917             :                 , compoundArrayLen(0)
     918             :                 , compoundArray(NULL)
     919             :                 , customStartCapLen(0)
     920             :                 , customStartCap(NULL)
     921             :                 , customEndCapLen(0)
     922           4 :                 , customEndCap(NULL)
     923             :             {
     924           4 :             }
     925             : 
     926           8 :             virtual ~EMFPPen()
     927           8 :             {
     928           4 :                 delete[] dashPattern;
     929           4 :                 delete[] compoundArray;
     930           4 :                 delete customStartCap;
     931           4 :                 delete customEndCap;
     932           8 :             }
     933             : 
     934           4 :             void SetStrokeWidth(rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
     935             :             {
     936             : #if OSL_DEBUG_LEVEL > 1
     937             :                 if (width == 0.0) {
     938             :                     SAL_INFO ("cppcanvas.emf", "TODO: pen with zero width - using minimal which might not be correct\n");
     939             :                 }
     940             : #endif
     941           4 :                 rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize (width == 0.0 ? 0.05 : width, 0)).getLength());
     942           4 :             }
     943             : 
     944           4 :             void SetStrokeAttributes(rendering::StrokeAttributes& rStrokeAttributes)
     945             :             {
     946           4 :                 rStrokeAttributes.JoinType = lcl_convertLineJoinType(lineJoin);
     947             : 
     948           4 :                 if (dashStyle != EmfPlusLineStyleSolid)
     949             :                 {
     950           0 :                     const float dash[] = {3, 3};
     951           0 :                     const float dot[] = {1, 3};
     952           0 :                     const float dashdot[] = {3, 3, 1, 3};
     953           0 :                     const float dashdotdot[] = {3, 3, 1, 3, 1, 3};
     954             : 
     955           0 :                     sal_Int32 nLen = 0;
     956           0 :                     const float *pPattern = NULL;
     957           0 :                     switch (dashStyle)
     958             :                     {
     959           0 :                         case EmfPlusLineStyleDash:       nLen = SAL_N_ELEMENTS(dash); pPattern = dash; break;
     960           0 :                         case EmfPlusLineStyleDot:        nLen = SAL_N_ELEMENTS(dot); pPattern = dot; break;
     961           0 :                         case EmfPlusLineStyleDashDot:    nLen = SAL_N_ELEMENTS(dashdot); pPattern = dashdot; break;
     962           0 :                         case EmfPlusLineStyleDashDotDot: nLen = SAL_N_ELEMENTS(dashdotdot); pPattern = dashdotdot; break;
     963           0 :                         case EmfPlusLineStyleCustom:     nLen = dashPatternLen; pPattern = dashPattern; break;
     964             :                     }
     965           0 :                     if (nLen > 0)
     966             :                     {
     967           0 :                         uno::Sequence<double> aDashArray(nLen);
     968           0 :                         for (int i = 0; i < nLen; ++i)
     969           0 :                             aDashArray[i] = pPattern[i];
     970             : 
     971           0 :                         rStrokeAttributes.DashArray = aDashArray;
     972             :                     }
     973             :                 }
     974           4 :             }
     975             : 
     976           4 :             void Read (SvStream& s, ImplRenderer& rR, sal_Int32, sal_Int32 )
     977             :             {
     978             :                 sal_uInt32 header, unknown, penFlags, unknown2;
     979             :                 int i;
     980             : 
     981           4 :                 s.ReadUInt32( header ).ReadUInt32( unknown ).ReadUInt32( penFlags ).ReadUInt32( unknown2 ).ReadFloat( width );
     982             : 
     983             :                 SAL_INFO("cppcanvas.emf", "EMF+\tpen");
     984             :                 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " unknown: 0x" << unknown <<
     985             :                             " additional flags: 0x" << penFlags << " unknown: 0x" << unknown2 << " width: " << std::dec << width );
     986             : 
     987           4 :                 if (penFlags & 1)
     988           0 :                     ReadXForm( s, transformation );
     989             : 
     990           4 :                 if (penFlags & 2)
     991             :                 {
     992           0 :                     s.ReadInt32( startCap );
     993             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex << startCap);
     994             :                 }
     995             :                 else
     996           4 :                     startCap = 0;
     997             : 
     998           4 :                 if (penFlags & 4)
     999             :                 {
    1000           0 :                     s.ReadInt32( endCap );
    1001             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex << endCap);
    1002             :                 }
    1003             :                 else
    1004           4 :                     endCap = 0;
    1005             : 
    1006           4 :                 if (penFlags & 8)
    1007           4 :                     s.ReadInt32( lineJoin );
    1008             :                 else
    1009           0 :                     lineJoin = 0;
    1010             : 
    1011           4 :                 if (penFlags & 16)
    1012           0 :                     s.ReadFloat( mitterLimit );
    1013             :                 else
    1014           4 :                     mitterLimit = 0;
    1015             : 
    1016           4 :                 if (penFlags & 32)
    1017             :                 {
    1018           0 :                     s.ReadInt32( dashStyle );
    1019             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
    1020             :                 }
    1021             :                 else
    1022           4 :                     dashStyle = 0;
    1023             : 
    1024           4 :                 if (penFlags & 64)
    1025           0 :                     s.ReadInt32( dashCap );
    1026             :                 else
    1027           4 :                     dashCap = 0;
    1028             : 
    1029           4 :                 if (penFlags & 128)
    1030           4 :                     s.ReadFloat( dashOffset );
    1031             :                 else
    1032           0 :                     dashOffset = 0;
    1033             : 
    1034           4 :                 if (penFlags & 256)
    1035             :                 {
    1036           0 :                     dashStyle = EmfPlusLineStyleCustom;
    1037             : 
    1038           0 :                     s.ReadInt32( dashPatternLen );
    1039             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen);
    1040             : 
    1041           0 :                     if( dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32/sizeof(float) )
    1042           0 :                         dashPatternLen = SAL_MAX_INT32/sizeof(float);
    1043           0 :                     dashPattern = new float [dashPatternLen];
    1044           0 :                     for (i = 0; i < dashPatternLen; i++)
    1045             :                     {
    1046           0 :                         s.ReadFloat( dashPattern [i] );
    1047             :                         SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
    1048             :                     }
    1049             :                 }
    1050             :                 else
    1051           4 :                     dashPatternLen = 0;
    1052             : 
    1053           4 :                 if (penFlags & 512)
    1054           0 :                     s.ReadInt32( alignment );
    1055             :                 else
    1056           4 :                     alignment = 0;
    1057             : 
    1058           4 :                 if (penFlags & 1024) {
    1059           4 :                     s.ReadInt32( compoundArrayLen );
    1060           4 :                     if( compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32/sizeof(float) )
    1061           0 :                         compoundArrayLen = SAL_MAX_INT32/sizeof(float);
    1062           4 :                     compoundArray = new float [compoundArrayLen];
    1063          12 :                     for (i = 0; i < compoundArrayLen; i++)
    1064           8 :                         s.ReadFloat( compoundArray [i] );
    1065             :                 } else
    1066           0 :                     compoundArrayLen = 0;
    1067             : 
    1068           4 :                 if (penFlags & 2048)
    1069             :                 {
    1070           0 :                     s.ReadInt32( customStartCapLen );
    1071             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen);
    1072           0 :                     sal_Size pos = s.Tell();
    1073             : 
    1074           0 :                     customStartCap = new EMFPCustomLineCap();
    1075           0 :                     customStartCap->Read(s, rR);
    1076             : 
    1077             :                     // maybe we don't read everything yet, play it safe ;-)
    1078           0 :                     s.Seek(pos + customStartCapLen);
    1079             :                 }
    1080             :                 else
    1081           4 :                     customStartCapLen = 0;
    1082             : 
    1083           4 :                 if (penFlags & 4096)
    1084             :                 {
    1085           0 :                     s.ReadInt32( customEndCapLen );
    1086             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen);
    1087           0 :                     sal_Size pos = s.Tell();
    1088             : 
    1089           0 :                     customEndCap = new EMFPCustomLineCap();
    1090           0 :                     customEndCap->Read(s, rR);
    1091             : 
    1092             :                     // maybe we don't read everything yet, play it safe ;-)
    1093           0 :                     s.Seek(pos + customEndCapLen);
    1094             :                 }
    1095             :                 else
    1096           4 :                     customEndCapLen = 0;
    1097             : 
    1098           4 :                 EMFPBrush::Read (s, rR);
    1099           4 :             }
    1100             :         };
    1101             : 
    1102           6 :         struct EMFPImage : public EMFPObject
    1103             :         {
    1104             :             sal_uInt32 type;
    1105             :             sal_Int32 width;
    1106             :             sal_Int32 height;
    1107             :             sal_Int32 stride;
    1108             :             sal_Int32 pixelFormat;
    1109             :             Graphic graphic;
    1110             : 
    1111             : 
    1112           2 :             void Read (SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream)
    1113             :             {
    1114             :                 sal_uInt32 header, unknown;
    1115             : 
    1116           2 :                 s.ReadUInt32( header ).ReadUInt32( type );
    1117             : 
    1118             :                 SAL_INFO("cppcanvas.emf", "EMF+\timage\nEMF+\theader: 0x" << std::hex << header << " type: " << type << std::dec );
    1119             : 
    1120           2 :                 if (type == 1) { // bitmap
    1121           2 :                     s.ReadInt32( width ).ReadInt32( height ).ReadInt32( stride ).ReadInt32( pixelFormat ).ReadUInt32( unknown );
    1122             :                     SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: " << width << " height: " << height << " stride: " << stride << " pixelFormat: 0x" << std::hex << pixelFormat << std::dec);
    1123           2 :                     if (width == 0) { // non native formats
    1124           2 :                         GraphicFilter filter;
    1125             : 
    1126           2 :                         filter.ImportGraphic (graphic, OUString(), s);
    1127           2 :                         SAL_INFO("cppcanvas.emf", "EMF+\tbitmap width: "  << graphic.GetBitmap().GetSizePixel().Width() << " height: " << graphic.GetBitmap().GetSizePixel().Height());
    1128             :                     }
    1129             : 
    1130           0 :                 } else if (type == 2) {
    1131             :                     sal_Int32 mfType, mfSize;
    1132             : 
    1133           0 :                     s.ReadInt32( mfType ).ReadInt32( mfSize );
    1134             :                     SAL_INFO("cppcanvas.emf", "EMF+\tmetafile type: " << mfType << " dataSize: " << mfSize << " real size calculated from record dataSize: " << dataSize - 16);
    1135             : 
    1136           0 :                     GraphicFilter filter;
    1137             :                     // workaround buggy metafiles, which have wrong mfSize set (n#705956 for example)
    1138           0 :                     SvMemoryStream mfStream (const_cast<char *>(static_cast<char const *>(s.GetData()) + s.Tell()), bUseWholeStream ? s.remainingSize() : dataSize - 16, StreamMode::READ);
    1139             : 
    1140           0 :                     filter.ImportGraphic (graphic, OUString(), mfStream);
    1141             : 
    1142             :                     // debug code - write the stream to debug file /tmp/emf-stream.emf
    1143             : #if OSL_DEBUG_LEVEL > 1
    1144             :                         mfStream.Seek(0);
    1145             :                         static sal_Int32 emfp_debug_stream_number = 0;
    1146             :                         OUString emfp_debug_filename = "/tmp/emf-embedded-stream" +
    1147             :                             OUString::number(emfp_debug_stream_number++) + ".emf";
    1148             : 
    1149             :                         SvFileStream file( emfp_debug_filename, StreamMode::WRITE | StreamMode::TRUNC );
    1150             : 
    1151             :                         mfStream.WriteStream(file);
    1152             :                         file.Flush();
    1153             :                         file.Close();
    1154             : #endif
    1155             :                 }
    1156           2 :             }
    1157             :         };
    1158             : 
    1159           0 :         struct EMFPFont : public EMFPObject
    1160             :         {
    1161             :             sal_uInt32 version;
    1162             :             float emSize;
    1163             :             sal_uInt32 sizeUnit;
    1164             :             sal_Int32 fontFlags;
    1165             :             OUString family;
    1166             : 
    1167           0 :             void Read (SvMemoryStream &s)
    1168             :             {
    1169             :                 sal_uInt32 header;
    1170             :                 sal_uInt32 reserved;
    1171             :                 sal_uInt32 length;
    1172             : 
    1173           0 :                 s.ReadUInt32( header ).ReadFloat( emSize ).ReadUInt32( sizeUnit ).ReadInt32( fontFlags ).ReadUInt32( reserved ).ReadUInt32( length );
    1174             : 
    1175             :                 OSL_ASSERT( ( header >> 12 ) == 0xdbc01 );
    1176             : 
    1177             :                 SAL_INFO("cppcanvas.emf", "EMF+\tfont\nEMF+\theader: 0x" << std::hex << (header >> 12) << " version: 0x" << (header & 0x1fff) << " size: " << std::dec << emSize << " unit: 0x" << std::hex << sizeUnit << std::dec);
    1178             :                 SAL_INFO("cppcanvas.emf", "EMF+\tflags: 0x" << std::hex << fontFlags << " reserved: 0x" << reserved << " length: 0x" << std::hex << length << std::dec);
    1179             : 
    1180           0 :                 if( length > 0 && length < 0x4000 ) {
    1181           0 :                     sal_Unicode *chars = static_cast<sal_Unicode *>(alloca( sizeof( sal_Unicode ) * length ));
    1182             : 
    1183           0 :                     for( sal_uInt32 i = 0; i < length; i++ )
    1184           0 :                         s.ReadUInt16( chars[ i ] );
    1185             : 
    1186           0 :                     family = OUString( chars, length );
    1187             :                     SAL_INFO("cppcanvas.emf", "EMF+\tfamily: " << OUStringToOString( family, RTL_TEXTENCODING_UTF8).getStr()); // TODO: can we just use family?
    1188             :                 }
    1189           0 :             }
    1190             :         };
    1191             : 
    1192           6 :         void ImplRenderer::ReadRectangle (SvStream& s, float& x, float& y, float &width, float& height, bool bCompressed)
    1193             :         {
    1194           6 :             if (bCompressed) {
    1195             :                 sal_Int16 ix, iy, iw, ih;
    1196             : 
    1197           0 :                 s.ReadInt16( ix ).ReadInt16( iy ).ReadInt16( iw ).ReadInt16( ih );
    1198             : 
    1199           0 :                 x = ix;
    1200           0 :                 y = iy;
    1201           0 :                 width = iw;
    1202           0 :                 height = ih;
    1203             :             } else
    1204           6 :                 s.ReadFloat( x ).ReadFloat( y ).ReadFloat( width ).ReadFloat( height );
    1205           6 :         }
    1206             : 
    1207           6 :         void ImplRenderer::ReadPoint (SvStream& s, float& x, float& y, sal_uInt32 flags)
    1208             :         {
    1209           6 :             if (flags & 0x4000) {
    1210             :                 sal_Int16 ix, iy;
    1211             : 
    1212           6 :                 s.ReadInt16( ix ).ReadInt16( iy );
    1213             : 
    1214           6 :                 x = ix;
    1215           6 :                 y = iy;
    1216             :             } else
    1217           0 :                 s.ReadFloat( x ).ReadFloat( y );
    1218           6 :         }
    1219             : 
    1220         190 :         void ImplRenderer::MapToDevice (double& x, double& y)
    1221             :         {
    1222             :             // TODO: other units
    1223         190 :             x = 100*nMmX*x/nPixX;
    1224         190 :             y = 100*nMmY*y/nPixY;
    1225         190 :         }
    1226             : 
    1227         180 :         ::basegfx::B2DPoint ImplRenderer::Map (double ix, double iy)
    1228             :         {
    1229             :             double x, y;
    1230             : 
    1231         180 :             x = ix*aWorldTransform.eM11 + iy*aWorldTransform.eM21 + aWorldTransform.eDx;
    1232         180 :             y = ix*aWorldTransform.eM12 + iy*aWorldTransform.eM22 + aWorldTransform.eDy;
    1233             : 
    1234         180 :             MapToDevice (x, y);
    1235             : 
    1236         180 :             x -= nFrameLeft;
    1237         180 :             y -= nFrameTop;
    1238             : 
    1239         180 :             x *= aBaseTransform.eM11;
    1240         180 :             y *= aBaseTransform.eM22;
    1241             : 
    1242         180 :             return ::basegfx::B2DPoint (x, y);
    1243             :         }
    1244             : 
    1245          10 :         ::basegfx::B2DSize ImplRenderer::MapSize (double iwidth, double iheight)
    1246             :         {
    1247             :             double w, h;
    1248             : 
    1249          10 :             w = iwidth*aWorldTransform.eM11 + iheight*aWorldTransform.eM21;
    1250          10 :             h = iwidth*aWorldTransform.eM12 + iheight*aWorldTransform.eM22;
    1251             : 
    1252          10 :             MapToDevice (w, h);
    1253             : 
    1254          10 :             w *= aBaseTransform.eM11;
    1255          10 :             h *= aBaseTransform.eM22;
    1256             : 
    1257          10 :             return ::basegfx::B2DSize (w, h);
    1258             :         }
    1259             : 
    1260             : #define COLOR(x) \
    1261             :     vcl::unotools::colorToDoubleSequence( ::Color (0xff - (x >> 24), \
    1262             :                              (x >> 16) & 0xff, \
    1263             :                              (x >> 8) & 0xff, \
    1264             :                              x & 0xff), \
    1265             :                         rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
    1266             : 
    1267           6 :         void ImplRenderer::EMFPPlusFillPolygon (::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
    1268             :                                                 OutDevState& rState, const CanvasSharedPtr& rCanvas, bool isColor, sal_uInt32 brushIndexOrColor)
    1269             :         {
    1270           6 :             ::basegfx::B2DPolyPolygon localPolygon (polygon);
    1271             : 
    1272             :             SAL_INFO("cppcanvas.emf", "EMF+\tfill polygon");
    1273             : 
    1274           6 :             localPolygon.transform( rState.mapModeTransform );
    1275             : 
    1276          12 :             ActionSharedPtr pPolyAction;
    1277             : 
    1278           6 :             if (isColor) {
    1279             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\tcolor fill:0x" << std::hex << brushIndexOrColor << std::dec);
    1280           6 :                 rState.isFillColorSet = true;
    1281           6 :                 rState.isLineColorSet = false;
    1282             : 
    1283           6 :                 rState.fillColor = COLOR(brushIndexOrColor);
    1284             : 
    1285           6 :                 pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
    1286             : 
    1287             :             } else {
    1288           0 :                 rState.isFillColorSet = true;
    1289             :                 // extract UseBrush
    1290           0 :                 EMFPBrush* brush = static_cast<EMFPBrush*>( aObjects [brushIndexOrColor & 0xff] );
    1291             :                 SAL_INFO("cppcanvas.emf", "EMF+\tbrush fill slot: " << brushIndexOrColor << " (type: " << brush->GetType () << ")");
    1292             : 
    1293             :                 // give up in case something wrong happened
    1294           0 :                 if( !brush )
    1295           0 :                     return;
    1296             : 
    1297           0 :                 rState.isFillColorSet = false;
    1298           0 :                 rState.isLineColorSet = false;
    1299             : 
    1300           0 :                 if (brush->type == 1)
    1301             :                 {
    1302             :                     // EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
    1303             :                     // for the others the hatch "background" color (secondColor in brush) is used.
    1304             : 
    1305           0 :                     bool isHatchBlend = true;
    1306           0 :                     double blendFactor = 0.0;
    1307             : 
    1308           0 :                     switch (brush->hatchStyle)
    1309             :                     {
    1310           0 :                         case HatchStyle05Percent: blendFactor = 0.05; break;
    1311           0 :                         case HatchStyle10Percent: blendFactor = 0.10; break;
    1312           0 :                         case HatchStyle20Percent: blendFactor = 0.20; break;
    1313           0 :                         case HatchStyle25Percent: blendFactor = 0.25; break;
    1314           0 :                         case HatchStyle30Percent: blendFactor = 0.30; break;
    1315           0 :                         case HatchStyle40Percent: blendFactor = 0.40; break;
    1316           0 :                         case HatchStyle50Percent: blendFactor = 0.50; break;
    1317           0 :                         case HatchStyle60Percent: blendFactor = 0.60; break;
    1318           0 :                         case HatchStyle70Percent: blendFactor = 0.70; break;
    1319           0 :                         case HatchStyle75Percent: blendFactor = 0.75; break;
    1320           0 :                         case HatchStyle80Percent: blendFactor = 0.80; break;
    1321           0 :                         case HatchStyle90Percent: blendFactor = 0.90; break;
    1322             :                         default:
    1323           0 :                             isHatchBlend = false;
    1324           0 :                             break;
    1325             :                     }
    1326           0 :                     rState.isFillColorSet = true;
    1327           0 :                     rState.isLineColorSet = false;
    1328           0 :                     ::Color fillColor;
    1329           0 :                     if (isHatchBlend)
    1330             :                     {
    1331           0 :                         fillColor = brush->solidColor;
    1332           0 :                         fillColor.Merge(brush->secondColor, static_cast<sal_uInt8>(255 * blendFactor));
    1333             :                     }
    1334             :                     else
    1335             :                     {
    1336           0 :                         fillColor = brush->secondColor;
    1337             :                     }
    1338           0 :                     rState.fillColor = vcl::unotools::colorToDoubleSequence(fillColor, rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
    1339           0 :                     pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
    1340             :                 }
    1341           0 :                 else if (brush->type == 3 || brush->type == 4)
    1342             :                 {
    1343           0 :                     if (brush->type == 3 && !(brush->additionalFlags & 0x1))
    1344           0 :                         return;  // we are unable to parse these brushes yet
    1345             : 
    1346           0 :                     ::basegfx::B2DHomMatrix aTextureTransformation;
    1347           0 :                     ::basegfx::B2DHomMatrix aWorldTransformation;
    1348           0 :                     ::basegfx::B2DHomMatrix aBaseTransformation;
    1349           0 :                     rendering::Texture aTexture;
    1350             : 
    1351           0 :                     aWorldTransformation.set (0, 0, aWorldTransform.eM11);
    1352           0 :                     aWorldTransformation.set (0, 1, aWorldTransform.eM21);
    1353           0 :                     aWorldTransformation.set (0, 2, aWorldTransform.eDx);
    1354           0 :                     aWorldTransformation.set (1, 0, aWorldTransform.eM12);
    1355           0 :                     aWorldTransformation.set (1, 1, aWorldTransform.eM22);
    1356           0 :                     aWorldTransformation.set (1, 2, aWorldTransform.eDy);
    1357             : 
    1358           0 :                     aBaseTransformation.set (0, 0, aBaseTransform.eM11);
    1359           0 :                     aBaseTransformation.set (0, 1, aBaseTransform.eM21);
    1360           0 :                     aBaseTransformation.set (0, 2, aBaseTransform.eDx);
    1361           0 :                     aBaseTransformation.set (1, 0, aBaseTransform.eM12);
    1362           0 :                     aBaseTransformation.set (1, 1, aBaseTransform.eM22);
    1363           0 :                     aBaseTransformation.set (1, 2, aBaseTransform.eDy);
    1364             : 
    1365           0 :                     if (brush->type == 4) {
    1366           0 :                         aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
    1367           0 :                         aTextureTransformation.translate (brush->areaX, brush->areaY);
    1368             :                     } else {
    1369           0 :                         aTextureTransformation.translate (-0.5, -0.5);
    1370           0 :                         aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
    1371           0 :                         aTextureTransformation.translate (brush->areaX,brush->areaY);
    1372             :                     }
    1373             : 
    1374           0 :                     if (brush->hasTransformation) {
    1375           0 :                         ::basegfx::B2DHomMatrix aTransformation;
    1376             : 
    1377           0 :                         aTransformation.set (0, 0, brush->transformation.eM11);
    1378           0 :                         aTransformation.set (0, 1, brush->transformation.eM21);
    1379           0 :                         aTransformation.set (0, 2, brush->transformation.eDx);
    1380           0 :                         aTransformation.set (1, 0, brush->transformation.eM12);
    1381           0 :                         aTransformation.set (1, 1, brush->transformation.eM22);
    1382           0 :                         aTransformation.set (1, 2, brush->transformation.eDy);
    1383             : 
    1384           0 :                         aTextureTransformation *= aTransformation;
    1385             :                     }
    1386             : 
    1387           0 :                     aTextureTransformation *= aWorldTransformation;
    1388           0 :                     aTextureTransformation.scale (100.0*nMmX/nPixX, 100.0*nMmY/nPixY);
    1389           0 :                     aTextureTransformation.translate (-nFrameLeft, -nFrameTop);
    1390           0 :                     aTextureTransformation *= rState.mapModeTransform;
    1391           0 :                     aTextureTransformation *= aBaseTransformation;
    1392             : 
    1393           0 :                     aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
    1394           0 :                     aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
    1395           0 :                     aTexture.Alpha = 1.0;
    1396             : 
    1397           0 :                     basegfx::ODFGradientInfo aGradInfo;
    1398           0 :                     OUString aGradientService;
    1399             : 
    1400             :                     const uno::Sequence< double > aStartColor(
    1401             :                             vcl::unotools::colorToDoubleSequence( brush->solidColor,
    1402           0 :                                 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
    1403             :                     const uno::Sequence< double > aEndColor(
    1404             :                             vcl::unotools::colorToDoubleSequence( brush->secondColor,
    1405           0 :                                 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() ) );
    1406           0 :                     uno::Sequence< uno::Sequence < double > > aColors (2);
    1407           0 :                     uno::Sequence< double > aStops (2);
    1408             : 
    1409           0 :                     if (brush->blendPositions) {
    1410             :                         SAL_INFO("cppcanvas.emf", "EMF+\t\tuse blend");
    1411           0 :                         aColors.realloc (brush->blendPoints);
    1412           0 :                         aStops.realloc (brush->blendPoints);
    1413           0 :                         int length = aStartColor.getLength ();
    1414           0 :                         uno::Sequence< double > aColor (length);
    1415             : 
    1416             :                         OSL_ASSERT (length == aEndColor.getLength());
    1417             : 
    1418           0 :                         for (int i = 0; i < brush->blendPoints; i++) {
    1419           0 :                             aStops[i] = brush->blendPositions [i];
    1420             : 
    1421           0 :                             for (int j = 0; j < length; j++) {
    1422           0 :                                 if (brush->type == 4) {
    1423           0 :                                     aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
    1424             :                                 } else
    1425           0 :                                     aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
    1426             :                             }
    1427             : 
    1428           0 :                             aColors[i] = aColor;
    1429           0 :                         }
    1430           0 :                     } else if (brush->colorblendPositions) {
    1431             :                         SAL_INFO("cppcanvas.emf", "EMF+\t\tuse color blend");
    1432           0 :                         aColors.realloc (brush->colorblendPoints);
    1433           0 :                         aStops.realloc (brush->colorblendPoints);
    1434             : 
    1435           0 :                         for (int i = 0; i < brush->colorblendPoints; i++) {
    1436           0 :                             aStops[i] = brush->colorblendPositions [i];
    1437           0 :                             aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
    1438           0 :                                     rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
    1439             :                         }
    1440             :                     } else {
    1441           0 :                         aStops[0] = 0.0;
    1442           0 :                         aStops[1] = 1.0;
    1443             : 
    1444           0 :                         if (brush->type == 4) {
    1445           0 :                             aColors[0] = aStartColor;
    1446           0 :                             aColors[1] = aEndColor;
    1447             :                         } else {
    1448           0 :                             aColors[1] = aStartColor;
    1449           0 :                             aColors[0] = aEndColor;
    1450             :                         }
    1451             :                     }
    1452             : 
    1453             :                     SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
    1454           0 :                     basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
    1455           0 :                     if (brush->type == 4) {
    1456           0 :                         aGradientService = "LinearGradient";
    1457           0 :                         aGradInfo = basegfx::tools::createLinearODFGradientInfo(
    1458             :                                 aBoundsRectangle,
    1459           0 :                                 aStops.getLength(),
    1460             :                                 0,
    1461           0 :                                 0);
    1462             : 
    1463             :                     } else {
    1464           0 :                         aGradientService = "EllipticalGradient";
    1465           0 :                         aGradInfo = basegfx::tools::createEllipticalODFGradientInfo(
    1466             :                                 aBoundsRectangle,
    1467             :                                 ::basegfx::B2DVector( 0, 0 ),
    1468           0 :                                 aStops.getLength(),
    1469             :                                 0,
    1470           0 :                                 0);
    1471             :                     }
    1472             : 
    1473             :                     uno::Reference< lang::XMultiServiceFactory > xFactory(
    1474           0 :                             rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
    1475             : 
    1476           0 :                     if( xFactory.is() ) {
    1477           0 :                         uno::Sequence<uno::Any> args( 3 );
    1478           0 :                         beans::PropertyValue aProp;
    1479           0 :                         aProp.Name = "Colors";
    1480           0 :                         aProp.Value <<= aColors;
    1481           0 :                         args[0] <<= aProp;
    1482           0 :                         aProp.Name = "Stops";
    1483           0 :                         aProp.Value <<= aStops;
    1484           0 :                         args[1] <<= aProp;
    1485           0 :                         aProp.Name = "AspectRatio";
    1486           0 :                         aProp.Value <<= static_cast<sal_Int32>(1);
    1487           0 :                         args[2] <<= aProp;
    1488             : 
    1489             :                         aTexture.Gradient.set(
    1490           0 :                                 xFactory->createInstanceWithArguments( aGradientService,
    1491           0 :                                     args ),
    1492           0 :                                 uno::UNO_QUERY);
    1493             :                     }
    1494             : 
    1495             :                     ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
    1496           0 :                             aTextureTransformation );
    1497             : 
    1498           0 :                     if( aTexture.Gradient.is() )
    1499           0 :                         pPolyAction =
    1500             :                             ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon,
    1501             :                                         rParms.mrCanvas,
    1502             :                                         rState,
    1503           0 :                                         aTexture ) );
    1504             :                 }
    1505             :             }
    1506             : 
    1507           6 :             if( pPolyAction )
    1508             :             {
    1509             :                 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd poly action");
    1510             : 
    1511             :                 maActions.push_back(
    1512             :                     MtfAction(
    1513             :                         pPolyAction,
    1514           6 :                         rParms.mrCurrActionIndex ) );
    1515             : 
    1516           6 :                 rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
    1517           6 :             }
    1518             :         }
    1519             : 
    1520           0 :         double ImplRenderer::EMFPPlusDrawLineCap(const ::basegfx::B2DPolygon& rPolygon, double fPolyLength,
    1521             :                 const ::basegfx::B2DPolyPolygon& rLineCap, bool bIsFilled, bool bStart, const rendering::StrokeAttributes& rAttributes,
    1522             :                 const ActionFactoryParameters& rParms, OutDevState& rState)
    1523             :         {
    1524           0 :             if (!rLineCap.count())
    1525           0 :                 return 0.0;
    1526             : 
    1527             :             // createAreaGeometryForLineStartEnd normalises the arrows height
    1528             :             // before scaling (i.e. scales down by rPolygon.height), hence
    1529             :             // we pre-scale it (which means we can avoid changing the logic
    1530             :             // that would affect arrows rendered outside of EMF+).
    1531           0 :             const double fWidth = rAttributes.StrokeWidth*rLineCap.getB2DRange().getWidth();
    1532             : 
    1533             :             // When drawing an outline (as opposed to a filled endCap), we also
    1534             :             // need to take account that the brush width also adds to the area
    1535             :             // of the polygon.
    1536           0 :             const double fShift = bIsFilled ? 0 : rAttributes.StrokeWidth;
    1537           0 :             double fConsumed = 0;
    1538             :             basegfx::B2DPolyPolygon aArrow(basegfx::tools::createAreaGeometryForLineStartEnd(
    1539             :                         rPolygon, rLineCap, bStart,
    1540           0 :                         fWidth, fPolyLength, 0, &fConsumed, fShift));
    1541             : 
    1542             :             // createAreaGeometryForLineStartEnd from some reason always sets
    1543             :             // the path as closed, correct it
    1544           0 :             aArrow.setClosed(rLineCap.isClosed());
    1545             : 
    1546             :             // If the endcap is filled, we draw ONLY the filling, if it isn't
    1547             :             // filled we draw ONLY the outline, but never both.
    1548           0 :             if (bIsFilled)
    1549             :             {
    1550           0 :                 bool bWasFillColorSet = rState.isFillColorSet;
    1551           0 :                 rState.isFillColorSet = true;
    1552           0 :                 rState.fillColor = rState.lineColor;
    1553           0 :                 ActionSharedPtr pAction2(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState));
    1554           0 :                 if (pAction2)
    1555             :                 {
    1556           0 :                     maActions.push_back(MtfAction(pAction2, rParms.mrCurrActionIndex));
    1557           0 :                     rParms.mrCurrActionIndex += pAction2->getActionCount()-1;
    1558             :                 }
    1559           0 :                 rState.isFillColorSet = bWasFillColorSet;
    1560             :             }
    1561             :             else
    1562             :             {
    1563           0 :                 ActionSharedPtr pAction(internal::PolyPolyActionFactory::createPolyPolyAction(aArrow, rParms.mrCanvas, rState, rAttributes));
    1564           0 :                 if (pAction)
    1565             :                 {
    1566           0 :                     maActions.push_back(MtfAction(pAction, rParms.mrCurrActionIndex));
    1567           0 :                     rParms.mrCurrActionIndex += pAction->getActionCount()-1;
    1568           0 :                 }
    1569             :             }
    1570             : 
    1571             :             // There isn't any clear definition of how far the line should extend
    1572             :             // for arrows, however the following values seem to give best results
    1573             :             // (fConsumed/2 draws the line to the center-point of the endcap
    1574             :             // for filled caps -- however it is likely this will need to be
    1575             :             // changed once we start taking baseInset into account).
    1576           0 :             if (bIsFilled)
    1577           0 :                 return fConsumed/2;
    1578             :             else
    1579           0 :                 return rAttributes.StrokeWidth;
    1580             :         }
    1581             : 
    1582           4 :         void ImplRenderer::EMFPPlusDrawPolygon (const ::basegfx::B2DPolyPolygon& polygon, const ActionFactoryParameters& rParms,
    1583             :                                                 OutDevState& rState, const CanvasSharedPtr& rCanvas, sal_uInt32 penIndex)
    1584             :         {
    1585           4 :             EMFPPen* pen = static_cast<EMFPPen*>( aObjects [penIndex & 0xff] );
    1586             : 
    1587             :             SAL_WARN_IF( !pen, "cppcanvas.emf", "emf+ missing pen" );
    1588             : 
    1589           4 :             if (pen)
    1590             :             {
    1591           4 :                 rState.isFillColorSet = false;
    1592           4 :                 rState.isLineColorSet = true;
    1593           8 :                 rState.lineColor = vcl::unotools::colorToDoubleSequence (pen->GetColor (),
    1594          12 :                                                                            rCanvas->getUNOCanvas ()->getDevice()->getDeviceColorSpace());
    1595             : 
    1596           4 :                 basegfx::B2DPolyPolygon aPolyPolygon(polygon);
    1597           4 :                 aPolyPolygon.transform(rState.mapModeTransform);
    1598           8 :                 rendering::StrokeAttributes aCommonAttributes;
    1599             : 
    1600             :                 // some attributes are common for the polygon, and the line
    1601             :                 // starts & ends - like the stroke width
    1602           4 :                 pen->SetStrokeWidth(aCommonAttributes, *this, rState);
    1603             : 
    1604             :                 // but eg. dashing has to be additionally set only on the
    1605             :                 // polygon
    1606           8 :                 rendering::StrokeAttributes aPolygonAttributes(aCommonAttributes);
    1607           4 :                 pen->SetStrokeAttributes(aPolygonAttributes);
    1608             : 
    1609           8 :                 basegfx::B2DPolyPolygon aFinalPolyPolygon;
    1610             : 
    1611             :                 // render line starts & ends if present
    1612           4 :                 if (!pen->customStartCap && !pen->customEndCap)
    1613           4 :                     aFinalPolyPolygon = aPolyPolygon;
    1614             :                 else
    1615             :                 {
    1616           0 :                     for (sal_uInt32 i = 0; i < aPolyPolygon.count(); ++i)
    1617             :                     {
    1618           0 :                         basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(i));
    1619             : 
    1620           0 :                         if (!aPolygon.isClosed())
    1621             :                         {
    1622           0 :                             double fStart = 0.0;
    1623           0 :                             double fEnd = 0.0;
    1624           0 :                             double fPolyLength = basegfx::tools::getLength(aPolygon);
    1625             : 
    1626             :                             // line start
    1627           0 :                             if (pen->customStartCap)
    1628             :                             {
    1629           0 :                                 rendering::StrokeAttributes aAttributes(aCommonAttributes);
    1630           0 :                                 pen->customStartCap->SetAttributes(aAttributes);
    1631             : 
    1632             :                                 fStart = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customStartCap->polygon,
    1633             :                                         pen->customStartCap->mbIsFilled,
    1634           0 :                                         true, aAttributes, rParms, rState);
    1635             :                             }
    1636             : 
    1637             :                             // line end
    1638           0 :                             if (pen->customEndCap)
    1639             :                             {
    1640           0 :                                 rendering::StrokeAttributes aAttributes(aCommonAttributes);
    1641           0 :                                 pen->customEndCap->SetAttributes(aAttributes);
    1642             : 
    1643             :                                 fEnd = EMFPPlusDrawLineCap(aPolygon, fPolyLength, pen->customEndCap->polygon,
    1644             :                                         pen->customEndCap->mbIsFilled,
    1645           0 :                                         false, aAttributes, rParms, rState);
    1646             :                             }
    1647             : 
    1648             :                             // build new poly, consume something from the old poly
    1649           0 :                             if (fStart != 0.0 || fEnd != 0.0)
    1650           0 :                                 aPolygon = basegfx::tools::getSnippetAbsolute(aPolygon, fStart, fPolyLength - fEnd, fPolyLength);
    1651             :                         }
    1652             : 
    1653           0 :                         aFinalPolyPolygon.append(aPolygon);
    1654           0 :                     }
    1655             :                 }
    1656             : 
    1657             :                 // finally render the polygon
    1658           8 :                 ActionSharedPtr pPolyAction(internal::PolyPolyActionFactory::createPolyPolyAction(aFinalPolyPolygon, rParms.mrCanvas, rState, aPolygonAttributes));
    1659           4 :                 if( pPolyAction )
    1660             :                 {
    1661           4 :                     maActions.push_back(MtfAction(pPolyAction, rParms.mrCurrActionIndex));
    1662           4 :                     rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
    1663           4 :                 }
    1664             :             }
    1665           4 :         }
    1666             : 
    1667          18 :         void ImplRenderer::processObjectRecord(SvMemoryStream& rObjectStream, sal_uInt16 flags, sal_uInt32 dataSize, bool bUseWholeStream)
    1668             :         {
    1669             :             sal_uInt32 index;
    1670             : 
    1671             :             SAL_INFO("cppcanvas.emf", "EMF+ Object slot: " << (flags & 0xff) << " flags: " << (flags & 0xff00));
    1672             : 
    1673          18 :             index = flags & 0xff;
    1674          18 :             if (aObjects [index] != NULL) {
    1675           0 :                 delete aObjects [index];
    1676           0 :                 aObjects [index] = NULL;
    1677             :             }
    1678             : 
    1679          18 :             switch (flags & 0x7f00) {
    1680             :             case EmfPlusObjectTypeBrush:
    1681             :                 {
    1682             :                     EMFPBrush *brush;
    1683           0 :                     aObjects [index] = brush = new EMFPBrush ();
    1684           0 :                     brush->Read (rObjectStream, *this);
    1685             : 
    1686           0 :                     break;
    1687             :                 }
    1688             :             case EmfPlusObjectTypePen:
    1689             :                 {
    1690             :                     EMFPPen *pen;
    1691           4 :                     aObjects [index] = pen = new EMFPPen ();
    1692           4 :                     pen->Read (rObjectStream, *this, nHDPI, nVDPI);
    1693             : 
    1694           4 :                     break;
    1695             :                 }
    1696             :             case EmfPlusObjectTypePath:
    1697             :                 sal_uInt32 header, pathFlags;
    1698             :                 sal_Int32 points;
    1699             : 
    1700           6 :                 rObjectStream.ReadUInt32( header ).ReadInt32( points ).ReadUInt32( pathFlags );
    1701             : 
    1702             :                 SAL_INFO("cppcanvas.emf", "EMF+\tpath");
    1703             :                 SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " points: " << std::dec << points << " additional flags: 0x" << std::hex << pathFlags << std::dec);
    1704             : 
    1705             :                 EMFPPath *path;
    1706           6 :                 aObjects [index] = path = new EMFPPath (points);
    1707           6 :                 path->Read (rObjectStream, pathFlags, *this);
    1708             : 
    1709           6 :                 break;
    1710             :             case EmfPlusObjectTypeRegion: {
    1711             :                 EMFPRegion *region;
    1712             : 
    1713           6 :                 aObjects [index] = region = new EMFPRegion ();
    1714           6 :                 region->Read (rObjectStream);
    1715             : 
    1716           6 :                 break;
    1717             :             }
    1718             :             case EmfPlusObjectTypeImage:
    1719             :                 {
    1720             :                     EMFPImage *image;
    1721           2 :                     aObjects [index] = image = new EMFPImage ();
    1722           2 :                     image->Read (rObjectStream, dataSize, bUseWholeStream);
    1723             : 
    1724           2 :                     break;
    1725             :                 }
    1726             :             case EmfPlusObjectTypeFont:
    1727             :                 {
    1728             :                     EMFPFont *font;
    1729           0 :                     aObjects [index] = font = new EMFPFont ();
    1730           0 :                     font->Read (rObjectStream);
    1731             : 
    1732           0 :                     break;
    1733             :                 }
    1734             :             case EmfPlusObjectTypeStringFormat:
    1735             :                 {
    1736             :                     SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'string format' not yet implemented");
    1737           0 :                     break;
    1738             :                 }
    1739             :             case EmfPlusObjectTypeImageAttributes:
    1740             :                 {
    1741             :                     SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'image attributes' not yet implemented");
    1742           0 :                     break;
    1743             :                 }
    1744             :             case EmfPlusObjectTypeCustomLineCap:
    1745             :                 {
    1746             :                     SAL_INFO("cppcanvas.emf", "EMF+\t Object type 'custom line cap' not yet implemented");
    1747           0 :                     break;
    1748             :                 }
    1749             :             default:
    1750             :                 SAL_INFO("cppcanvas.emf", "EMF+\tObject unhandled flags: 0x" << std::hex << (flags & 0xff00) << std::dec);
    1751           0 :                 break;
    1752             :             }
    1753          18 :         }
    1754             : 
    1755           0 :         double ImplRenderer::setFont (sal_uInt8 objectId, const ActionFactoryParameters& rParms, OutDevState& rState)
    1756             :         {
    1757           0 :             EMFPFont *font = static_cast<EMFPFont*>( aObjects[ objectId ] );
    1758             : 
    1759           0 :             rendering::FontRequest aFontRequest;
    1760           0 :             aFontRequest.FontDescription.FamilyName = font->family;
    1761           0 :             double cellSize = font->emSize;
    1762           0 :             aFontRequest.CellSize = (rState.mapModeTransform*MapSize( cellSize, 0 )).getX();
    1763           0 :             rState.xFont = rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
    1764             :                                                uno::Sequence< beans::PropertyValue >(),
    1765           0 :                                                geometry::Matrix2D() );
    1766             : 
    1767           0 :             return cellSize;
    1768             :         }
    1769             : 
    1770           0 :         void ImplRenderer::GraphicStatePush(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
    1771             :         {
    1772           0 :             GraphicStateMap::iterator iter = map.find( index );
    1773             : 
    1774           0 :             if ( iter != map.end() )
    1775             :             {
    1776           0 :                 EmfPlusGraphicState state = iter->second;
    1777           0 :                 map.erase( iter );
    1778             : 
    1779           0 :                 SAL_INFO("cppcanvas.emf", "stack index: " << index << " found and erased");
    1780             :             }
    1781             : 
    1782           0 :             EmfPlusGraphicState state;
    1783             : 
    1784           0 :             state.aWorldTransform = aWorldTransform;
    1785           0 :             state.aDevState = rState;
    1786             : 
    1787           0 :             map[ index ] = state;
    1788           0 :         }
    1789             : 
    1790           0 :         void ImplRenderer::GraphicStatePop(GraphicStateMap& map, sal_Int32 index, OutDevState& rState)
    1791             :         {
    1792           0 :             GraphicStateMap::iterator iter = map.find( index );
    1793             : 
    1794           0 :             if ( iter != map.end() )
    1795             :             {
    1796             :                 SAL_INFO("cppcanvas.emf", "stack index: " << index << " found");
    1797             : 
    1798           0 :                 EmfPlusGraphicState state = iter->second;
    1799             : 
    1800           0 :                 aWorldTransform = state.aWorldTransform;
    1801           0 :                 rState.clip = state.aDevState.clip;
    1802           0 :                 rState.clipRect = state.aDevState.clipRect;
    1803           0 :                 rState.xClipPoly = state.aDevState.xClipPoly;
    1804             :             }
    1805           0 :         }
    1806             : 
    1807          24 :         void ImplRenderer::processEMFPlus( MetaCommentAction* pAct, const ActionFactoryParameters& rFactoryParms,
    1808             :                                            OutDevState& rState, const CanvasSharedPtr& rCanvas )
    1809             :         {
    1810          24 :             sal_uInt32 length = pAct->GetDataSize ();
    1811          24 :             SvMemoryStream rMF (const_cast<sal_uInt8 *>(pAct->GetData ()), length, StreamMode::READ);
    1812             : 
    1813          24 :             length -= 4;
    1814             : 
    1815         308 :             while (length > 0) {
    1816             :                 sal_uInt16 type, flags;
    1817             :                 sal_uInt32 size, dataSize;
    1818             :                 sal_Size next;
    1819             : 
    1820         260 :                 rMF.ReadUInt16( type ).ReadUInt16( flags ).ReadUInt32( size ).ReadUInt32( dataSize );
    1821             : 
    1822         260 :                 next = rMF.Tell() + ( size - 12 );
    1823             : 
    1824         260 :                 if (size < 12) {
    1825             :                     SAL_INFO("cppcanvas.emf", "Size field is less than 12 bytes");
    1826             :                 }
    1827             : 
    1828             :                 SAL_INFO("cppcanvas.emf", "EMF+ record size: " << size << " type: " << emfTypeToName(type) << " flags: " << flags << " data size: " << dataSize);
    1829             : 
    1830         260 :                 if (type == EmfPlusRecordTypeObject && ((mbMultipart && (flags & 0x7fff) == (mMFlags & 0x7fff)) || (flags & 0x8000))) {
    1831           0 :                     if (!mbMultipart) {
    1832           0 :                         mbMultipart = true;
    1833           0 :                         mMFlags = flags;
    1834           0 :                         mMStream.Seek(0);
    1835             :                     }
    1836             : 
    1837             :                     // 1st 4 bytes are unknown
    1838           0 :                     mMStream.Write (static_cast<const char *>(rMF.GetData()) + rMF.Tell() + 4, dataSize - 4);
    1839           0 :                     SAL_INFO("cppcanvas.emf", "EMF+ read next object part size: " << size << " type: " << type << " flags: " << flags << " data size: " << dataSize);
    1840             :                 } else {
    1841         260 :                     if (mbMultipart) {
    1842             :                         SAL_INFO("cppcanvas.emf", "EMF+ multipart record flags: " << mMFlags);
    1843           0 :                         mMStream.Seek (0);
    1844           0 :                         processObjectRecord (mMStream, mMFlags, dataSize, true);
    1845             :                     }
    1846         260 :                     mbMultipart = false;
    1847             :                 }
    1848             : 
    1849         260 :                 if (type != EmfPlusRecordTypeObject || !(flags & 0x8000))
    1850             :                 {
    1851         260 :                     switch (type) {
    1852             :                     case EmfPlusRecordTypeHeader:
    1853             :                         sal_uInt32 header, version;
    1854             : 
    1855           2 :                         rMF.ReadUInt32( header ).ReadUInt32( version ).ReadInt32( nHDPI ).ReadInt32( nVDPI );
    1856             : 
    1857             :                         SAL_INFO("cppcanvas.emf", "EMF+ Header");
    1858             :                         SAL_INFO("cppcanvas.emf", "EMF+\theader: 0x" << std::hex << header << " version: " << std::dec << version << " horizontal DPI: " << nHDPI << " vertical DPI: " << nVDPI << " dual: " << (flags & 1));
    1859             : 
    1860         262 :                         break;
    1861             :                     case EmfPlusRecordTypeEndOfFile:
    1862             :                         SAL_INFO("cppcanvas.emf", "EMF+ EndOfFile");
    1863           2 :                         break;
    1864             :                     case EmfPlusRecordTypeGetDC:
    1865             :                         SAL_INFO("cppcanvas.emf", "EMF+ GetDC");
    1866             :                         SAL_INFO("cppcanvas.emf", "EMF+\talready used in svtools wmf/emf filter parser");
    1867           6 :                         break;
    1868             :                     case EmfPlusRecordTypeObject:
    1869          18 :                         processObjectRecord (rMF, flags, dataSize);
    1870          18 :                         break;
    1871             :                     case EmfPlusRecordTypeFillPie:
    1872             :                         {
    1873             :                             sal_uInt32 brushIndexOrColor;
    1874             :                             float startAngle, sweepAngle;
    1875             : 
    1876           0 :                             rMF.ReadUInt32( brushIndexOrColor ).ReadFloat( startAngle ).ReadFloat( sweepAngle );
    1877             : 
    1878             :                             SAL_INFO("cppcanvas.emf", "EMF+ FillPie colorOrIndex: " << brushIndexOrColor << " startAngle: " << startAngle << " sweepAngle: " << sweepAngle);
    1879             : 
    1880             :                             float dx, dy, dw, dh;
    1881             : 
    1882           0 :                             ReadRectangle (rMF, dx, dy, dw, dh, bool(flags & 0x4000));
    1883             : 
    1884             :                             SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
    1885             : 
    1886           0 :                             startAngle = 2*M_PI*startAngle/360;
    1887           0 :                             sweepAngle = 2*M_PI*sweepAngle/360;
    1888             : 
    1889           0 :                             B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
    1890           0 :                             B2DSize mappedSize( MapSize (dw/2, dh/2));
    1891             : 
    1892           0 :                             float endAngle = startAngle + sweepAngle;
    1893           0 :                             startAngle = fmodf(startAngle, static_cast<float>(M_PI*2));
    1894           0 :                             if (startAngle < 0)
    1895           0 :                                 startAngle += static_cast<float>(M_PI*2);
    1896           0 :                             endAngle = fmodf(endAngle, static_cast<float>(M_PI*2));
    1897           0 :                             if (endAngle < 0)
    1898           0 :                                 endAngle += static_cast<float>(M_PI*2);
    1899             : 
    1900           0 :                             if (sweepAngle < 0)
    1901           0 :                                 std::swap (endAngle, startAngle);
    1902             : 
    1903             :                             SAL_INFO("cppcanvas.emf", "EMF+ adjusted angles: start " <<
    1904             :                                      (360.0*startAngle/M_PI) << ", end: " << (360.0*endAngle/M_PI));
    1905             : 
    1906           0 :                             B2DPolygon polygon = basegfx::tools::createPolygonFromEllipseSegment (mappedCenter, mappedSize.getX (), mappedSize.getY (), startAngle, endAngle);
    1907           0 :                             polygon.append (mappedCenter);
    1908           0 :                             polygon.setClosed (true);
    1909             : 
    1910           0 :                             B2DPolyPolygon polyPolygon (polygon);
    1911           0 :                             EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
    1912             :                         }
    1913           0 :                         break;
    1914             :                     case EmfPlusRecordTypeFillPath:
    1915             :                         {
    1916           4 :                             sal_uInt32 index = flags & 0xff;
    1917             :                             sal_uInt32 brushIndexOrColor;
    1918             : 
    1919           4 :                             rMF.ReadUInt32( brushIndexOrColor );
    1920             : 
    1921             :                             SAL_INFO("cppcanvas.emf", "EMF+ FillPath slot: " << index);
    1922             : 
    1923           4 :                             EMFPPlusFillPolygon( static_cast<EMFPPath*>( aObjects [index])->GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
    1924             :                         }
    1925           4 :                         break;
    1926             :                     case EmfPlusRecordTypeDrawEllipse:
    1927             :                     case EmfPlusRecordTypeFillEllipse:
    1928             :                         {
    1929             :                             // Intentionally very bogus initial value to avoid MSVC complaining about potentially uninitialized local
    1930             :                             // variable. As long as the code stays as intended, this variable will be assigned a (real) value in the case
    1931             :                             // when it is later used.
    1932           0 :                             sal_uInt32 brushIndexOrColor = 1234567;
    1933             : 
    1934           0 :                             if ( type == EmfPlusRecordTypeFillEllipse )
    1935           0 :                                 rMF.ReadUInt32( brushIndexOrColor );
    1936             : 
    1937             :                             SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeFillEllipse ? "Fill" : "Draw") << "Ellipse slot: " << (flags & 0xff));
    1938             : 
    1939             :                             float dx, dy, dw, dh;
    1940             : 
    1941           0 :                             ReadRectangle (rMF, dx, dy, dw, dh, bool(flags & 0x4000));
    1942             : 
    1943             :                             SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
    1944             : 
    1945           0 :                             B2DPoint mappedCenter (Map (dx + dw/2, dy + dh/2));
    1946           0 :                             B2DSize mappedSize( MapSize (dw/2, dh/2));
    1947             : 
    1948           0 :                             ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromEllipse( mappedCenter, mappedSize.getX (), mappedSize.getY () ) ) );
    1949             : 
    1950           0 :                             if ( type == EmfPlusRecordTypeFillEllipse )
    1951             :                                 EMFPPlusFillPolygon( polyPolygon,
    1952           0 :                                                      rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor );
    1953             :                             else
    1954             :                                 EMFPPlusDrawPolygon( polyPolygon,
    1955           0 :                                                      rFactoryParms, rState, rCanvas, flags & 0xff );
    1956             :                         }
    1957           0 :                         break;
    1958             :                     case EmfPlusRecordTypeFillRects:
    1959             :                         {
    1960             :                             SAL_INFO("cppcanvas.emf", "EMF+ FillRects");
    1961             : 
    1962             :                             sal_uInt32 brushIndexOrColor;
    1963             :                             sal_Int32 rectangles;
    1964           2 :                             bool isColor = (flags & 0x8000);
    1965           2 :                             ::basegfx::B2DPolygon polygon;
    1966             : 
    1967           2 :                             rMF.ReadUInt32( brushIndexOrColor ).ReadInt32( rectangles );
    1968             : 
    1969             :                             SAL_INFO("cppcanvas.emf", "EMF+\t" << ((flags & 0x8000) ? "color" : "brush index") << ": 0x" << std::hex << brushIndexOrColor << std::dec);
    1970             : 
    1971           4 :                             for (int i=0; i < rectangles; i++) {
    1972           2 :                                 if (flags & 0x4000) {
    1973             :                                     /* 16bit integers */
    1974             :                                     sal_Int16 x, y, width, height;
    1975             : 
    1976           0 :                                     rMF.ReadInt16( x ).ReadInt16( y ).ReadInt16( width ).ReadInt16( height );
    1977             : 
    1978           0 :                                     polygon.append (Map (x, y));
    1979           0 :                                     polygon.append (Map (x + width, y));
    1980           0 :                                     polygon.append (Map (x + width, y + height));
    1981           0 :                                     polygon.append (Map (x, y + height));
    1982             : 
    1983             :                                     SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << ", " << width << "x" << height);
    1984             :                                 } else {
    1985             :                                     /* Single's */
    1986             :                                     float x, y, width, height;
    1987             : 
    1988           2 :                                     rMF.ReadFloat( x ).ReadFloat( y ).ReadFloat( width ).ReadFloat( height );
    1989             : 
    1990           2 :                                     polygon.append (Map (x, y));
    1991           2 :                                     polygon.append (Map (x + width, y));
    1992           2 :                                     polygon.append (Map (x + width, y + height));
    1993           2 :                                     polygon.append (Map (x, y + height));
    1994             : 
    1995             :                                     SAL_INFO("cppcanvas.emf", "EMF+\trectangle: " << x << ", " << width << "x" << height);
    1996             :                                 }
    1997             : 
    1998           2 :                                 ::basegfx::B2DPolyPolygon polyPolygon (polygon);
    1999             : 
    2000           2 :                                 EMFPPlusFillPolygon (polyPolygon, rFactoryParms, rState, rCanvas, isColor, brushIndexOrColor);
    2001           2 :                             }
    2002           2 :                             break;
    2003             :                         }
    2004             :                     case EmfPlusRecordTypeFillPolygon:
    2005             :                         {
    2006           0 :                             sal_uInt8 index = flags & 0xff;
    2007             :                             sal_uInt32 brushIndexOrColor;
    2008             :                             sal_Int32 points;
    2009             : 
    2010           0 :                             rMF.ReadUInt32( brushIndexOrColor );
    2011           0 :                             rMF.ReadInt32( points );
    2012             : 
    2013             :                             SAL_INFO("cppcanvas.emf", "EMF+ FillPolygon in slot: " << +index << " points: " << points);
    2014             :                             SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
    2015             : 
    2016           0 :                             EMFPPath path (points, true);
    2017           0 :                             path.Read (rMF, flags, *this);
    2018             : 
    2019           0 :                             EMFPPlusFillPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags & 0x8000, brushIndexOrColor);
    2020             : 
    2021           0 :                             break;
    2022             :                         }
    2023             :                     case EmfPlusRecordTypeDrawLines:
    2024             :                         {
    2025             :                             sal_uInt32 points;
    2026             : 
    2027           0 :                             rMF.ReadUInt32( points );
    2028             : 
    2029             :                             SAL_INFO("cppcanvas.emf", "EMF+ DrawLines in slot: " << (flags & 0xff) << " points: " << points);
    2030             : 
    2031           0 :                             EMFPPath path (points, true);
    2032           0 :                             path.Read (rMF, flags, *this);
    2033             : 
    2034           0 :                             EMFPPlusDrawPolygon (path.GetPolygon (*this), rFactoryParms, rState, rCanvas, flags);
    2035             : 
    2036           0 :                             break;
    2037             :                         }
    2038             :                     case EmfPlusRecordTypeDrawPath:
    2039             :                         {
    2040             :                             sal_uInt32 penIndex;
    2041             : 
    2042           4 :                             rMF.ReadUInt32( penIndex );
    2043             : 
    2044             :                             SAL_INFO("cppcanvas.emf", "EMF+ DrawPath");
    2045             :                             SAL_INFO("cppcanvas.emf", "EMF+\tpen: " << penIndex);
    2046             : 
    2047           4 :                             EMFPPath* path = static_cast<EMFPPath*>( aObjects [flags & 0xff] );
    2048             :                             SAL_WARN_IF( !path, "cppcanvas.emf", "EmfPlusRecordTypeDrawPath missing path" );
    2049             : 
    2050           4 :                             EMFPPlusDrawPolygon (path->GetPolygon (*this), rFactoryParms, rState, rCanvas, penIndex);
    2051             : 
    2052           4 :                             break;
    2053             :                         }
    2054             :                     case EmfPlusRecordTypeDrawImage:
    2055             :                     case EmfPlusRecordTypeDrawImagePoints:
    2056             :                         {
    2057             :                             sal_uInt32 attrIndex;
    2058             :                             sal_Int32 sourceUnit;
    2059             : 
    2060           2 :                             rMF.ReadUInt32( attrIndex ).ReadInt32( sourceUnit );
    2061             : 
    2062             :                             SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << "attributes index: " << attrIndex << "source unit: " << sourceUnit);
    2063             :                             SAL_INFO("cppcanvas.emf", "EMF+\tTODO: use image attributes");
    2064             : 
    2065           2 :                             if (sourceUnit == 2 && aObjects [flags & 0xff]) { // we handle only GraphicsUnit.Pixel now
    2066           2 :                                 EMFPImage& image = *static_cast<EMFPImage *>( aObjects [flags & 0xff]);
    2067             :                                 float sx, sy, sw, sh;
    2068             :                                 sal_Int32 aCount;
    2069             : 
    2070           2 :                                 ReadRectangle (rMF, sx, sy, sw, sh);
    2071           2 :                                 Rectangle aSource(Point(sx, sy), Size(sw, sh));
    2072             : 
    2073             :                                 SAL_INFO("cppcanvas.emf", "EMF+ " << (type == EmfPlusRecordTypeDrawImagePoints ? "DrawImagePoints" : "DrawImage") << " source rectangle: " << sx << "," << sy << " " << sw << "x" << sh);
    2074             : 
    2075           2 :                                 ::basegfx::B2DPoint aDstPoint;
    2076           4 :                                 ::basegfx::B2DSize aDstSize;
    2077           2 :                                 bool bValid = false;
    2078             : 
    2079           2 :                                 if (type == EmfPlusRecordTypeDrawImagePoints) {
    2080           2 :                                     rMF.ReadInt32( aCount );
    2081             : 
    2082           2 :                                     if( aCount == 3) { // TODO: now that we now that this value is count we should support it better
    2083             :                                         float x1, y1, x2, y2, x3, y3;
    2084             : 
    2085           2 :                                         ReadPoint (rMF, x1, y1, flags);
    2086           2 :                                         ReadPoint (rMF, x2, y2, flags);
    2087           2 :                                         ReadPoint (rMF, x3, y3, flags);
    2088             : 
    2089             :                                         SAL_INFO("cppcanvas.emf", "EMF+ destination points: " << x1 << "," << y1 << " " << x2 << "," << y2 << " " << x3 << "," << y3);
    2090             :                                         SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << x1 << "," << y1 << " " << x2 - x1 << "x" << y3 - y1);
    2091             : 
    2092           2 :                                         aDstPoint = Map (x1, y1);
    2093           2 :                                         aDstSize = MapSize(x2 - x1, y3 - y1);
    2094             : 
    2095           2 :                                         bValid = true;
    2096             :                                     }
    2097           0 :                                 } else if (type == EmfPlusRecordTypeDrawImage) {
    2098             :                                     float dx, dy, dw, dh;
    2099             : 
    2100           0 :                                     ReadRectangle (rMF, dx, dy, dw, dh, bool(flags & 0x4000));
    2101             : 
    2102             :                                     SAL_INFO("cppcanvas.emf", "EMF+ destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
    2103             : 
    2104           0 :                                     aDstPoint = Map (dx, dy);
    2105           0 :                                     aDstSize = MapSize(dw, dh);
    2106             : 
    2107           0 :                                     bValid = true;
    2108             :                                 }
    2109             : 
    2110           2 :                                 if (bValid) {
    2111           2 :                                     BitmapEx aBmp( image.graphic.GetBitmapEx () );
    2112           2 :                                     aBmp.Crop( aSource );
    2113             : 
    2114           2 :                                     Size aSize( aBmp.GetSizePixel() );
    2115             :                                     SAL_INFO("cppcanvas.emf", "EMF+ bitmap size: " << aSize.Width() << "x" << aSize.Height());
    2116           2 :                                     if( aSize.Width() > 0 && aSize.Height() > 0 ) {
    2117             :                                         ActionSharedPtr pBmpAction (
    2118             :                                             internal::BitmapActionFactory::createBitmapAction (
    2119             :                                                 aBmp,
    2120           4 :                                                 rState.mapModeTransform * aDstPoint,
    2121           4 :                                                 rState.mapModeTransform * aDstSize,
    2122             :                                                 rCanvas,
    2123           4 :                                                 rState));
    2124             : 
    2125           2 :                                         if( pBmpAction ) {
    2126             :                                             maActions.push_back( MtfAction( pBmpAction,
    2127           2 :                                                                             rFactoryParms.mrCurrActionIndex ) );
    2128             : 
    2129           2 :                                             rFactoryParms.mrCurrActionIndex += pBmpAction->getActionCount()-1;
    2130           2 :                                         }
    2131             :                                     } else {
    2132             :                                         SAL_INFO("cppcanvas.emf", "EMF+ warning: empty bitmap");
    2133           2 :                                     }
    2134             :                                 } else {
    2135             :                                     SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme)");
    2136           2 :                                 }
    2137             :                             } else {
    2138             :                                 SAL_INFO("cppcanvas.emf", "EMF+ DrawImage(Points) TODO (fixme) - possibly unsupported source units for crop rectangle");
    2139             :                             }
    2140           2 :                             break;
    2141             :                         }
    2142             :                     case EmfPlusRecordTypeDrawString:
    2143             :                         {
    2144             :                             SAL_INFO("cppcanvas.emf", "EMF+ DrawString");
    2145             : 
    2146             :                             sal_uInt32 brushId;
    2147             :                             sal_uInt32 formatId;
    2148             :                             sal_uInt32 stringLength;
    2149             : 
    2150           0 :                             rMF.ReadUInt32( brushId ).ReadUInt32( formatId ).ReadUInt32( stringLength );
    2151             :                             SAL_INFO("cppcanvas.emf", "EMF+ DrawString brushId: " << brushId << " formatId: " << formatId << " length: " << stringLength);
    2152             : 
    2153           0 :                             if (flags & 0x8000) {
    2154             :                                 float lx, ly, lw, lh;
    2155             : 
    2156           0 :                                 rMF.ReadFloat( lx ).ReadFloat( ly ).ReadFloat( lw ).ReadFloat( lh );
    2157             : 
    2158             :                                 SAL_INFO("cppcanvas.emf", "EMF+ DrawString layoutRect: " << lx << "," << ly << " - " << lw << "x" << lh);
    2159             : 
    2160           0 :                                 OUString text = read_uInt16s_ToOUString(rMF, stringLength);
    2161             : 
    2162           0 :                                 double cellSize = setFont (flags & 0xff, rFactoryParms, rState);
    2163           0 :                                 rState.textColor = COLOR( brushId );
    2164             : 
    2165           0 :                                 ::basegfx::B2DPoint point( Map( lx + 0.15*cellSize, ly + cellSize ) );
    2166             : 
    2167             :                                 ActionSharedPtr pTextAction(
    2168             :                                     TextActionFactory::createTextAction(
    2169             :                                                                         // position is just rough guess for now
    2170             :                                                                         // we should calculate it exactly from layoutRect or font
    2171             :                                         vcl::unotools::pointFromB2DPoint ( point ),
    2172             :                                         ::Size(),
    2173             :                                         ::Color(),
    2174             :                                         ::Size(),
    2175             :                                         ::Color(),
    2176             :                                         text,
    2177             :                                         0,
    2178             :                                         stringLength,
    2179             :                                         NULL,
    2180             :                                         rFactoryParms.mrVDev,
    2181             :                                         rFactoryParms.mrCanvas,
    2182             :                                         rState,
    2183             :                                         rFactoryParms.mrParms,
    2184           0 :                                         false ) );
    2185           0 :                                 if( pTextAction )
    2186             :                                 {
    2187             :                                     SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
    2188             : 
    2189             :                                     maActions.push_back(
    2190             :                                                         MtfAction(
    2191             :                                                                   pTextAction,
    2192           0 :                                                                   rFactoryParms.mrCurrActionIndex ) );
    2193             : 
    2194           0 :                                     rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
    2195           0 :                                 }
    2196             :                             } else {
    2197             :                                 SAL_INFO("cppcanvas.emf", "EMF+ DrawString TODO - drawing with brush not yet supported");
    2198             :                             }
    2199             :                         }
    2200           0 :                         break;
    2201             :                     case EmfPlusRecordTypeSetPageTransform:
    2202           2 :                         rMF.ReadFloat( fPageScale );
    2203             : 
    2204             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetPageTransform");
    2205             :                         SAL_INFO("cppcanvas.emf", "EMF+\tscale: " << fPageScale << " unit: " << flags);
    2206             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2207           2 :                         break;
    2208             :                     case EmfPlusRecordTypeSetRenderingOrigin:
    2209           0 :                         rMF.ReadInt32( nOriginX ).ReadInt32( nOriginY );
    2210             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetRenderingOrigin");
    2211             :                         SAL_INFO("cppcanvas.emf", "EMF+\torigin [x,y]: " << nOriginX << "," << nOriginY);
    2212           0 :                         break;
    2213             :                     case EmfPlusRecordTypeSetTextRenderingHint:
    2214             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetTextRenderingHint");
    2215             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2216           2 :                         break;
    2217             :                     case EmfPlusRecordTypeSetAntiAliasMode:
    2218             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetAntiAliasMode");
    2219             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2220          58 :                         break;
    2221             :                     case EmfPlusRecordTypeSetInterpolationMode:
    2222             :                         SAL_INFO("cppcanvas.emf", "EMF+ InterpolationMode");
    2223             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2224          60 :                         break;
    2225             :                     case EmfPlusRecordTypeSetPixelOffsetMode:
    2226             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetPixelOffsetMode");
    2227             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2228           2 :                         break;
    2229             :                     case EmfPlusRecordTypeSetCompositingQuality:
    2230             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetCompositingQuality");
    2231             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2232           0 :                         break;
    2233             :                     case EmfPlusRecordTypeSave:
    2234             :                     {
    2235             :                         sal_uInt32 stackIndex;
    2236             : 
    2237           0 :                         rMF.ReadUInt32( stackIndex );
    2238             : 
    2239             :                         SAL_INFO("cppcanvas.emf", "EMF+ Save stack index: " << stackIndex);
    2240             : 
    2241           0 :                         GraphicStatePush( mGSStack, stackIndex, rState );
    2242             : 
    2243           0 :                         break;
    2244             :                     }
    2245             :                     case EmfPlusRecordTypeRestore:
    2246             :                     {
    2247             :                         sal_uInt32 stackIndex;
    2248             : 
    2249           0 :                         rMF.ReadUInt32( stackIndex );
    2250             : 
    2251             :                         SAL_INFO("cppcanvas.emf", "EMF+ Restore stack index: " << stackIndex);
    2252             : 
    2253           0 :                         GraphicStatePop( mGSStack, stackIndex, rState );
    2254             : 
    2255           0 :                         break;
    2256             :                     }
    2257             :                     case EmfPlusRecordTypeBeginContainerNoParams:
    2258             :                     {
    2259             :                         sal_uInt32 stackIndex;
    2260             : 
    2261           0 :                         rMF.ReadUInt32( stackIndex );
    2262             : 
    2263             :                         SAL_INFO("cppcanvas.emf", "EMF+ Begin Container No Params stack index: " << stackIndex);
    2264             : 
    2265           0 :                         GraphicStatePush( mGSContainerStack, stackIndex, rState );
    2266             :                     }
    2267           0 :                     break;
    2268             :                     case EmfPlusRecordTypeEndContainer:
    2269             :                     {
    2270             :                         sal_uInt32 stackIndex;
    2271             : 
    2272           0 :                         rMF.ReadUInt32( stackIndex );
    2273             : 
    2274             :                         SAL_INFO("cppcanvas.emf", "EMF+ End Container stack index: " << stackIndex);
    2275             : 
    2276           0 :                         GraphicStatePop( mGSContainerStack, stackIndex, rState );
    2277             :                     }
    2278           0 :                     break;
    2279             :                     case EmfPlusRecordTypeSetWorldTransform: {
    2280             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetWorldTransform");
    2281          46 :                         XForm transform;
    2282          46 :                         ReadXForm( rMF, transform );
    2283          46 :                         aWorldTransform.Set (transform);
    2284             :                         SAL_INFO("cppcanvas.emf",
    2285             :                                 "EMF+\tm11: " << aWorldTransform.eM11 << "\tm12: " << aWorldTransform.eM12 <<
    2286             :                                 "\tm21: " << aWorldTransform.eM21 << "\tm22: " << aWorldTransform.eM22 <<
    2287             :                                 "\tdx: "  << aWorldTransform.eDx  << "\tdy: "  << aWorldTransform.eDy);
    2288          46 :                         break;
    2289             :                     }
    2290             :                     case EmfPlusRecordTypeResetWorldTransform:
    2291             :                         SAL_INFO("cppcanvas.emf", "EMF+ ResetWorldTransform");
    2292          36 :                         aWorldTransform.SetIdentity ();
    2293          36 :                         break;
    2294             :                     case EmfPlusRecordTypeMultiplyWorldTransform: {
    2295             :                         SAL_INFO("cppcanvas.emf", "EMF+ MultiplyWorldTransform");
    2296           0 :                         XForm transform;
    2297           0 :                         ReadXForm( rMF, transform );
    2298             : 
    2299             :                         SAL_INFO("cppcanvas.emf",
    2300             :                                 "EMF+\tmatrix m11: " << transform.eM11 << "m12: " << transform.eM12 <<
    2301             :                                 "EMF+\tm21: "        << transform.eM21 << "m22: " << transform.eM22 <<
    2302             :                                 "EMF+\tdx: "         << transform.eDx  << "dy: "  << transform.eDy);
    2303             : 
    2304           0 :                         if (flags & 0x2000)  // post multiply
    2305           0 :                             aWorldTransform.Multiply (transform);
    2306             :                         else {               // pre multiply
    2307           0 :                             transform.Multiply (aWorldTransform);
    2308           0 :                             aWorldTransform.Set (transform);
    2309             :                         }
    2310             :                         SAL_INFO("cppcanvas.emf",
    2311             :                                 "EMF+\tm11: " << aWorldTransform.eM11 << "m12: " << aWorldTransform.eM12 <<
    2312             :                                 "EMF+\tm21: " << aWorldTransform.eM21 << "m22: " << aWorldTransform.eM22 <<
    2313             :                                 "EMF+\tdx: "  << aWorldTransform.eDx  << "dy: "  << aWorldTransform.eDy);
    2314           0 :                         break;
    2315             :                     }
    2316             :                     case EmfPlusRecordTypeSetClipRect:
    2317             :                         {
    2318           4 :                             int combineMode = (flags >> 8) & 0xf;
    2319             : 
    2320             :                             SAL_INFO("cppcanvas.emf", "EMF+ SetClipRect combine mode: " << combineMode);
    2321             : #if OSL_DEBUG_LEVEL > 1
    2322             :                             if (combineMode > 1) {
    2323             :                                 SAL_INFO ("cppcanvas.emf", "EMF+ TODO combine mode > 1");
    2324             :                             }
    2325             : #endif
    2326             : 
    2327             :                             float dx, dy, dw, dh;
    2328             : 
    2329           4 :                             ReadRectangle (rMF, dx, dy, dw, dh, false);
    2330             : 
    2331             :                             SAL_INFO("cppcanvas.emf", "EMF+ RectData: " << dx << "," << dy << " " << dw << "x" << dh);
    2332             : 
    2333           4 :                             B2DPoint mappedPoint (Map (dx, dy));
    2334           8 :                             B2DSize mappedSize( MapSize (dw, dh));
    2335             : 
    2336             :                             ::basegfx::B2DPolyPolygon polyPolygon( ::basegfx::B2DPolygon( ::basegfx::tools::createPolygonFromRect( ::basegfx::B2DRectangle( mappedPoint.getX(), mappedPoint.getY(),
    2337           4 :                                                                                                                                                             mappedPoint.getX() + mappedSize.getX(),
    2338          12 :                                                                                                                                                             mappedPoint.getY() + mappedSize.getY() ) ) ) );
    2339           4 :                             polyPolygon.transform(rState.mapModeTransform);
    2340             : 
    2341           4 :                             updateClipping (polyPolygon, rFactoryParms, combineMode == 1);
    2342             : 
    2343           8 :                             break;
    2344             :                         }
    2345             :                     case EmfPlusRecordTypeSetClipPath:
    2346             :                         {
    2347           2 :                             int combineMode = (flags >> 8) & 0xf;
    2348             : 
    2349             :                             SAL_INFO("cppcanvas.emf", "EMF+ SetClipPath combine mode: " << combineMode);
    2350             :                             SAL_INFO("cppcanvas.emf", "EMF+\tpath in slot: " << (flags & 0xff));
    2351             : 
    2352           2 :                             EMFPPath& path = *static_cast<EMFPPath*>( aObjects [flags & 0xff] );
    2353           2 :                             ::basegfx::B2DPolyPolygon& clipPoly (path.GetPolygon (*this));
    2354             : 
    2355           2 :                             clipPoly.transform (rState.mapModeTransform);
    2356           2 :                             switch (combineMode)
    2357             :                             {
    2358             :                             case EmfPlusCombineModeReplace:
    2359             :                             case EmfPlusCombineModeIntersect:
    2360             :                             case EmfPlusCombineModeUnion: // Is this, EmfPlusCombineModeXOR and EmfPlusCombineModeComplement correct?
    2361             :                             case EmfPlusCombineModeXOR:
    2362             :                             case EmfPlusCombineModeComplement:
    2363           0 :                                 updateClipping (clipPoly, rFactoryParms, combineMode == 1);
    2364           0 :                                 break;
    2365             :                             case EmfPlusCombineModeExclude:
    2366             :                                 // Not doing anything is better then including exactly what we wanted to exclude.
    2367           2 :                                 break;
    2368             :                             }
    2369             : 
    2370           2 :                             break;
    2371             :                         }
    2372             :                     case EmfPlusRecordTypeSetClipRegion: {
    2373           8 :                         int combineMode = (flags >> 8) & 0xf;
    2374             : 
    2375             :                         SAL_INFO("cppcanvas.emf", "EMF+ SetClipRegion");
    2376             :                         SAL_INFO("cppcanvas.emf", "EMF+\tregion in slot: " << (flags & 0xff) << " combine mode: " << combineMode);
    2377           8 :                         EMFPRegion *region = static_cast<EMFPRegion*>(aObjects [flags & 0xff]);
    2378             : 
    2379             :                         // reset clip
    2380           8 :                         if (region && region->parts == 0 && region->initialState == EmfPlusRegionInitialStateInfinite) {
    2381           4 :                             updateClipping (::basegfx::B2DPolyPolygon (), rFactoryParms, combineMode == 1);
    2382             :                         } else {
    2383             :                             SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2384             :                         }
    2385           8 :                         break;
    2386             :                     }
    2387             :                     case EmfPlusRecordTypeDrawDriverString: {
    2388             :                         SAL_INFO("cppcanvas.emf", "EMF+ DrawDriverString, flags: 0x" << std::hex << flags << std::dec);
    2389             :                         sal_uInt32 brushIndexOrColor;
    2390             :                         sal_uInt32 optionFlags;
    2391             :                         sal_uInt32 hasMatrix;
    2392             :                         sal_uInt32 glyphsCount;
    2393             : 
    2394           0 :                         rMF.ReadUInt32( brushIndexOrColor ).ReadUInt32( optionFlags ).ReadUInt32( hasMatrix ).ReadUInt32( glyphsCount );
    2395             : 
    2396             :                         SAL_INFO("cppcanvas.emf", "EMF+\t: " << ((flags & 0x8000) ? "color" : "brush index") << " 0x" << std::hex << brushIndexOrColor << std::dec);
    2397             :                         SAL_INFO("cppcanvas.emf", "EMF+\toption flags: 0x" << std::hex << optionFlags << std::dec);
    2398             :                         SAL_INFO("cppcanvas.emf", "EMF+\thas matrix: " << hasMatrix);
    2399             :                         SAL_INFO("cppcanvas.emf", "EMF+\tglyphs: " << glyphsCount);
    2400             : 
    2401           0 :                         if( ( optionFlags & 1 ) && glyphsCount > 0 ) {
    2402           0 :                             float *charsPosX = new float[glyphsCount];
    2403           0 :                             float *charsPosY = new float[glyphsCount];
    2404             : 
    2405           0 :                             OUString text = read_uInt16s_ToOUString(rMF, glyphsCount);
    2406             : 
    2407           0 :                             for( sal_uInt32 i=0; i<glyphsCount; i++) {
    2408           0 :                                 rMF.ReadFloat( charsPosX[i] ).ReadFloat( charsPosY[i] );
    2409             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tglyphPosition[" << i << "]: " << charsPosX[i] << "," << charsPosY[i]);
    2410             :                             }
    2411             : 
    2412           0 :                             XForm transform;
    2413           0 :                             if( hasMatrix ) {
    2414           0 :                                 ReadXForm( rMF, transform );
    2415             :                                 SAL_INFO("cppcanvas.emf", "EMF+\tmatrix: " << transform.eM11 << ", " << transform.eM12 << ", " << transform.eM21 << ", " << transform.eM22 << ", " << transform.eDx << ", " << transform.eDy);
    2416             :                             }
    2417             : 
    2418             :                             // add the text action
    2419           0 :                             setFont (flags & 0xff, rFactoryParms, rState);
    2420             : 
    2421           0 :                             if( flags & 0x8000 )
    2422           0 :                                 rState.textColor = COLOR( brushIndexOrColor );
    2423             : 
    2424           0 :                             ::basegfx::B2DPoint point( Map( charsPosX[0], charsPosY[0] ) );
    2425             : 
    2426             :                             ActionSharedPtr pTextAction(
    2427             :                                     TextActionFactory::createTextAction(
    2428             :                                         vcl::unotools::pointFromB2DPoint ( point ),
    2429             :                                         ::Size(),
    2430             :                                         ::Color(),
    2431             :                                         ::Size(),
    2432             :                                         ::Color(),
    2433             :                                         text,
    2434             :                                         0,
    2435             :                                         glyphsCount,
    2436             :                                         NULL,
    2437             :                                         rFactoryParms.mrVDev,
    2438             :                                         rFactoryParms.mrCanvas,
    2439             :                                         rState,
    2440             :                                         rFactoryParms.mrParms,
    2441           0 :                                         false ) );
    2442             : 
    2443           0 :                             if( pTextAction )
    2444             :                             {
    2445             :                                 SAL_INFO("cppcanvas.emf", "EMF+\t\tadd text action");
    2446             : 
    2447             :                                 maActions.push_back(
    2448             :                                         MtfAction(
    2449             :                                             pTextAction,
    2450           0 :                                             rFactoryParms.mrCurrActionIndex ) );
    2451             : 
    2452           0 :                                 rFactoryParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
    2453             :                             }
    2454             : 
    2455           0 :                             delete[] charsPosX;
    2456           0 :                             delete[] charsPosY;
    2457             :                         } else {
    2458             :                             SAL_INFO("cppcanvas.emf", "EMF+\tTODO: fonts (non-unicode glyphs chars)");
    2459             :                         }
    2460             : 
    2461           0 :                         break;
    2462             :                     }
    2463             :                     default:
    2464             :                         SAL_INFO("cppcanvas.emf", "EMF+ unhandled record type: " << type);
    2465             :                         SAL_INFO("cppcanvas.emf", "EMF+\tTODO");
    2466             :                     }
    2467             :                 }
    2468             : 
    2469         260 :                 rMF.Seek (next);
    2470             : 
    2471         260 :                 if (size <= length)
    2472             :                 {
    2473         260 :                     length -= size;
    2474             :                 }
    2475             :                 else
    2476             :                 {
    2477             :                     SAL_WARN("cppcanvas.emf", "ImplRenderer::processEMFPlus: "
    2478             :                             "size " << size << " > length " << length);
    2479           0 :                     length = 0;
    2480             :                 }
    2481          24 :             }
    2482          24 :         }
    2483             :     }
    2484         753 : }
    2485             : 
    2486             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11