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

Generated by: LCOV version 1.10