LCOV - code coverage report
Current view: top level - libreoffice/svtools/source/filter/wmf - winwmf.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 260 708 36.7 %
Date: 2012-12-27 Functions: 11 11 100.0 %
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             : 
      21             : #include "winmtf.hxx"
      22             : #include <boost/scoped_array.hpp>
      23             : #include <vcl/gdimtf.hxx>
      24             : #include <svtools/wmf.hxx>
      25             : #include <rtl/crc.h>
      26             : #include <rtl/tencinfo.h>
      27             : #include <osl/endian.h>
      28             : 
      29             : //====================== MS-Windows-defines ===============================
      30             : 
      31             : #define W_META_SETBKCOLOR           0x0201
      32             : #define W_META_SETBKMODE            0x0102
      33             : #define W_META_SETMAPMODE           0x0103
      34             : #define W_META_SETROP2              0x0104
      35             : #define W_META_SETRELABS            0x0105
      36             : #define W_META_SETPOLYFILLMODE      0x0106
      37             : #define W_META_SETSTRETCHBLTMODE    0x0107
      38             : #define W_META_SETTEXTCHAREXTRA     0x0108
      39             : #define W_META_SETTEXTCOLOR         0x0209
      40             : #define W_META_SETTEXTJUSTIFICATION 0x020A
      41             : #define W_META_SETWINDOWORG         0x020B
      42             : #define W_META_SETWINDOWEXT         0x020C
      43             : #define W_META_SETVIEWPORTORG       0x020D
      44             : #define W_META_SETVIEWPORTEXT       0x020E
      45             : #define W_META_OFFSETWINDOWORG      0x020F
      46             : #define W_META_SCALEWINDOWEXT       0x0410
      47             : #define W_META_OFFSETVIEWPORTORG    0x0211
      48             : #define W_META_SCALEVIEWPORTEXT     0x0412
      49             : #define W_META_LINETO               0x0213
      50             : #define W_META_MOVETO               0x0214
      51             : #define W_META_EXCLUDECLIPRECT      0x0415
      52             : #define W_META_INTERSECTCLIPRECT    0x0416
      53             : #define W_META_ARC                  0x0817
      54             : #define W_META_ELLIPSE              0x0418
      55             : #define W_META_FLOODFILL            0x0419
      56             : #define W_META_PIE                  0x081A
      57             : #define W_META_RECTANGLE            0x041B
      58             : #define W_META_ROUNDRECT            0x061C
      59             : #define W_META_PATBLT               0x061D
      60             : #define W_META_SAVEDC               0x001E
      61             : #define W_META_SETPIXEL             0x041F
      62             : #define W_META_OFFSETCLIPRGN        0x0220
      63             : #define W_META_TEXTOUT              0x0521
      64             : #define W_META_BITBLT               0x0922
      65             : #define W_META_STRETCHBLT           0x0B23
      66             : #define W_META_POLYGON              0x0324
      67             : #define W_META_POLYLINE             0x0325
      68             : #define W_META_ESCAPE               0x0626
      69             : #define W_META_RESTOREDC            0x0127
      70             : #define W_META_FILLREGION           0x0228
      71             : #define W_META_FRAMEREGION          0x0429
      72             : #define W_META_INVERTREGION         0x012A
      73             : #define W_META_PAINTREGION          0x012B
      74             : #define W_META_SELECTCLIPREGION     0x012C
      75             : #define W_META_SELECTOBJECT         0x012D
      76             : #define W_META_SETTEXTALIGN         0x012E
      77             : #define W_META_DRAWTEXT             0x062F
      78             : #define W_META_CHORD                0x0830
      79             : #define W_META_SETMAPPERFLAGS       0x0231
      80             : #define W_META_EXTTEXTOUT           0x0a32
      81             : #define W_META_SETDIBTODEV          0x0d33
      82             : #define W_META_SELECTPALETTE        0x0234
      83             : #define W_META_REALIZEPALETTE       0x0035
      84             : #define W_META_ANIMATEPALETTE       0x0436
      85             : #define W_META_SETPALENTRIES        0x0037
      86             : #define W_META_POLYPOLYGON          0x0538
      87             : #define W_META_RESIZEPALETTE        0x0139
      88             : #define W_META_DIBBITBLT            0x0940
      89             : #define W_META_DIBSTRETCHBLT        0x0b41
      90             : #define W_META_DIBCREATEPATTERNBRUSH 0x0142
      91             : #define W_META_STRETCHDIB           0x0f43
      92             : #define W_META_EXTFLOODFILL         0x0548
      93             : #define W_META_RESETDC              0x014C
      94             : #define W_META_STARTDOC             0x014D
      95             : #define W_META_STARTPAGE            0x004F
      96             : #define W_META_ENDPAGE              0x0050
      97             : #define W_META_ABORTDOC             0x0052
      98             : #define W_META_ENDDOC               0x005E
      99             : #define W_META_DELETEOBJECT         0x01f0
     100             : #define W_META_CREATEPALETTE        0x00f7
     101             : #define W_META_CREATEBRUSH          0x00F8
     102             : #define W_META_CREATEPATTERNBRUSH   0x01F9
     103             : #define W_META_CREATEPENINDIRECT    0x02FA
     104             : #define W_META_CREATEFONTINDIRECT   0x02FB
     105             : #define W_META_CREATEBRUSHINDIRECT  0x02FC
     106             : #define W_META_CREATEBITMAPINDIRECT 0x02FD
     107             : #define W_META_CREATEBITMAP         0x06FE
     108             : #define W_META_CREATEREGION         0x06FF
     109             : 
     110       67888 : static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
     111             : {
     112       67888 :     Point aSource( rSource );
     113       67888 :     if ( nMapMode == MM_HIMETRIC )
     114           0 :         aSource.Y() = -rSource.Y();
     115       67888 :     if ( aSource.X() < rPlaceableBound.Left() )
     116          22 :         rPlaceableBound.Left() = aSource.X();
     117       67888 :     if ( aSource.X() > rPlaceableBound.Right() )
     118          14 :         rPlaceableBound.Right() = aSource.X();
     119       67888 :     if ( aSource.Y() < rPlaceableBound.Top() )
     120          20 :         rPlaceableBound.Top() = aSource.Y();
     121       67888 :     if ( aSource.Y() > rPlaceableBound.Bottom() )
     122          15 :         rPlaceableBound.Bottom() = aSource.Y();
     123       67888 : }
     124             : 
     125          70 : static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode )
     126             : {
     127          70 :     GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode );
     128          70 :     GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode );
     129          70 : }
     130             : 
     131             : //=================== Methods of WMFReader ==============================
     132             : 
     133       71901 : inline Point WMFReader::ReadPoint()
     134             : {
     135       71901 :     short nX = 0, nY = 0;
     136       71901 :     *pWMF >> nX >> nY;
     137       71901 :     return Point( nX, nY );
     138             : }
     139             : 
     140             : // ------------------------------------------------------------------------
     141             : 
     142         166 : inline Point WMFReader::ReadYX()
     143             : {
     144         166 :     short nX = 0, nY = 0;
     145         166 :     *pWMF >> nY >> nX;
     146         166 :     return Point( nX, nY );
     147             : }
     148             : 
     149             : // ------------------------------------------------------------------------
     150             : 
     151          70 : Rectangle WMFReader::ReadRectangle()
     152             : {
     153          70 :     Point aBR, aTL;
     154          70 :     aBR = ReadYX();
     155          70 :     aTL = ReadYX();
     156          70 :     aBR.X()--;
     157          70 :     aBR.Y()--;
     158          70 :     return Rectangle( aTL, aBR );
     159             : }
     160             : 
     161             : // ------------------------------------------------------------------------
     162             : 
     163           2 : Size WMFReader::ReadYXExt()
     164             : {
     165           2 :     short nW=0, nH=0;
     166           2 :     *pWMF >> nH >> nW;
     167           2 :     return Size( nW, nH );
     168             : }
     169             : 
     170             : // ------------------------------------------------------------------------
     171             : 
     172         125 : void WMFReader::ReadRecordParams( sal_uInt16 nFunc )
     173             : {
     174         125 :     switch( nFunc )
     175             :     {
     176             :         case W_META_SETBKCOLOR:
     177             :         {
     178           0 :             pOut->SetBkColor( ReadColor() );
     179             :         }
     180           0 :         break;
     181             : 
     182             :         case W_META_SETBKMODE:
     183             :         {
     184           0 :             sal_uInt16 nDat = 0;
     185           0 :             *pWMF >> nDat;
     186           0 :             pOut->SetBkMode( nDat );
     187             :         }
     188           0 :         break;
     189             : 
     190             :         // !!!
     191             :         case W_META_SETMAPMODE:
     192             :         {
     193           6 :             sal_Int16 nMapMode = 0;
     194           6 :             *pWMF >> nMapMode;
     195           6 :             pOut->SetMapMode( nMapMode );
     196             :         }
     197           6 :         break;
     198             : 
     199             :         case W_META_SETROP2:
     200             :         {
     201           0 :             sal_uInt16 nROP2 = 0;
     202           0 :             *pWMF >> nROP2;
     203           0 :             pOut->SetRasterOp( nROP2 );
     204             :         }
     205           0 :         break;
     206             : 
     207             :         case W_META_SETTEXTCOLOR:
     208             :         {
     209           0 :             pOut->SetTextColor( ReadColor() );
     210             :         }
     211           0 :         break;
     212             : 
     213             :         case W_META_SETWINDOWORG:
     214             :         {
     215          12 :             pOut->SetWinOrg( ReadYX() );
     216             :         }
     217          12 :         break;
     218             : 
     219             :         case W_META_SETWINDOWEXT:
     220             :         {
     221          11 :             short nWidth = 0, nHeight = 0;
     222          11 :             *pWMF >> nHeight >> nWidth;
     223          11 :             pOut->SetWinExt( Size( nWidth, nHeight ) );
     224             :         }
     225          11 :         break;
     226             : 
     227             :         case W_META_OFFSETWINDOWORG:
     228             :         {
     229           0 :             short nXAdd = 0, nYAdd = 0;
     230           0 :             *pWMF >> nYAdd >> nXAdd;
     231           0 :             pOut->SetWinOrgOffset( nXAdd, nYAdd );
     232             :         }
     233           0 :         break;
     234             : 
     235             :         case W_META_SCALEWINDOWEXT:
     236             :         {
     237           0 :             short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
     238           0 :             *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum;
     239           0 :             pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
     240             :         }
     241           0 :         break;
     242             : 
     243             :         case W_META_SETVIEWPORTORG:
     244             :         case W_META_SETVIEWPORTEXT:
     245           0 :         break;
     246             : 
     247             :         case W_META_OFFSETVIEWPORTORG:
     248             :         {
     249           0 :             short nXAdd = 0, nYAdd = 0;
     250           0 :             *pWMF >> nYAdd >> nXAdd;
     251           0 :             pOut->SetDevOrgOffset( nXAdd, nYAdd );
     252             :         }
     253           0 :         break;
     254             : 
     255             :         case W_META_SCALEVIEWPORTEXT:
     256             :         {
     257           0 :             short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0;
     258           0 :             *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum;
     259           0 :             pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom );
     260             :         }
     261           0 :         break;
     262             : 
     263             :         case W_META_LINETO:
     264             :         {
     265           0 :             pOut->LineTo( ReadYX() );
     266             :         }
     267           0 :         break;
     268             : 
     269             :         case W_META_MOVETO:
     270             :         {
     271           0 :             pOut->MoveTo( ReadYX() );
     272             :         }
     273           0 :         break;
     274             : 
     275             :         case W_META_INTERSECTCLIPRECT:
     276             :         {
     277           0 :             pOut->IntersectClipRect( ReadRectangle() );
     278             :         }
     279           0 :         break;
     280             : 
     281             :         case W_META_RECTANGLE:
     282             :         {
     283           0 :             pOut->DrawRect( ReadRectangle() );
     284             :         }
     285           0 :         break;
     286             : 
     287             :         case W_META_ROUNDRECT:
     288             :         {
     289           0 :             Size aSize( ReadYXExt() );
     290           0 :             pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) );
     291             :         }
     292           0 :         break;
     293             : 
     294             :         case W_META_ELLIPSE:
     295             :         {
     296           0 :             pOut->DrawEllipse( ReadRectangle() );
     297             :         }
     298           0 :         break;
     299             : 
     300             :         case W_META_ARC:
     301             :         {
     302           0 :             Point aEnd( ReadYX() );
     303           0 :             Point aStart( ReadYX() );
     304           0 :             Rectangle aRect( ReadRectangle() );
     305           0 :             aRect.Justify();
     306           0 :             pOut->DrawArc( aRect, aStart, aEnd );
     307             :         }
     308           0 :         break;
     309             : 
     310             :         case W_META_PIE:
     311             :         {
     312           0 :             Point     aEnd( ReadYX() );
     313           0 :             Point     aStart( ReadYX() );
     314           0 :             Rectangle aRect( ReadRectangle() );
     315           0 :             aRect.Justify();
     316             : 
     317             :             // #i73608# OutputDevice deviates from WMF
     318             :             // semantics. start==end means full ellipse here.
     319           0 :             if( aStart == aEnd )
     320           0 :                 pOut->DrawEllipse( aRect );
     321             :             else
     322           0 :                 pOut->DrawPie( aRect, aStart, aEnd );
     323             :         }
     324           0 :         break;
     325             : 
     326             :         case W_META_CHORD:
     327             :         {
     328           0 :             Point aEnd( ReadYX() );
     329           0 :             Point aStart( ReadYX() );
     330           0 :             Rectangle aRect( ReadRectangle() );
     331           0 :             aRect.Justify();
     332           0 :             pOut->DrawChord( aRect, aStart, aEnd );
     333             :         }
     334           0 :         break;
     335             : 
     336             :         case W_META_POLYGON:
     337             :         {
     338           9 :             sal_uInt16 nPoints = 0;
     339           9 :             *pWMF >> nPoints;
     340           9 :             Polygon aPoly( nPoints );
     341        4162 :             for( sal_uInt16 i = 0; i < nPoints; i++ )
     342        4153 :                 aPoly[ i ] = ReadPoint();
     343           9 :             pOut->DrawPolygon( aPoly );
     344             :         }
     345           9 :         break;
     346             : 
     347             :         case W_META_POLYPOLYGON:
     348             :         {
     349           0 :             bool bRecordOk = true;
     350           0 :             sal_uInt16  nPoly = 0;
     351             :             Point*  pPtAry;
     352             :             // Number of polygons:
     353           0 :             *pWMF >> nPoly;
     354             :             // Number of points of each polygon. Determine total number of points
     355           0 :             boost::scoped_array<sal_uInt16> xPolygonPointCounts(new sal_uInt16[nPoly]);
     356           0 :             sal_uInt16* pnPoints = xPolygonPointCounts.get();
     357           0 :             sal_uInt16 nPoints = 0;
     358           0 :             for(sal_uInt16 i = 0; i < nPoly; i++ )
     359             :             {
     360           0 :                 *pWMF >> pnPoints[i];
     361             : 
     362           0 :                 if (pnPoints[i] > SAL_MAX_UINT16 - nPoints)
     363             :                 {
     364           0 :                     bRecordOk = false;
     365           0 :                     break;
     366             :                 }
     367             : 
     368           0 :                 nPoints += pnPoints[i];
     369             :             }
     370             : 
     371             :             SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle");
     372             : 
     373           0 :             bRecordOk &= pWMF->good();
     374             : 
     375           0 :             if (!bRecordOk)
     376             :             {
     377           0 :                 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
     378             :                 break;
     379             :             }
     380             : 
     381             :             // Polygon points are:
     382           0 :             boost::scoped_array<Point> xPolygonPoints(new Point[nPoints]);
     383           0 :             pPtAry = xPolygonPoints.get();
     384           0 :             for (sal_uInt16 i = 0; i < nPoints; i++ )
     385           0 :                 pPtAry[ i ] = ReadPoint();
     386             : 
     387           0 :             bRecordOk &= pWMF->good();
     388             : 
     389           0 :             if (!bRecordOk)
     390             :             {
     391           0 :                 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
     392             :                 break;
     393             :             }
     394             : 
     395             :             // Produce PolyPolygon Actions
     396           0 :             PolyPolygon aPolyPoly( nPoly, pnPoints, pPtAry );
     397           0 :             pOut->DrawPolyPolygon( aPolyPoly );
     398             :         }
     399           0 :         break;
     400             : 
     401             :         case W_META_POLYLINE:
     402             :         {
     403           0 :             sal_uInt16 nPoints = 0;
     404           0 :             *pWMF >> nPoints;
     405           0 :             Polygon aPoly( nPoints );
     406           0 :             for(sal_uInt16 i = 0; i < nPoints; i++ )
     407           0 :                 aPoly[ i ] = ReadPoint();
     408           0 :             pOut->DrawPolyLine( aPoly );
     409             :         }
     410           0 :         break;
     411             : 
     412             :         case W_META_SAVEDC:
     413             :         {
     414           0 :             pOut->Push();
     415             :         }
     416           0 :         break;
     417             : 
     418             :         case W_META_RESTOREDC:
     419             :         {
     420           0 :             pOut->Pop();
     421             :         }
     422           0 :         break;
     423             : 
     424             :         case W_META_SETPIXEL:
     425             :         {
     426           0 :             const Color aColor = ReadColor();
     427           0 :             pOut->DrawPixel( ReadYX(), aColor );
     428             :         }
     429           0 :         break;
     430             : 
     431             :         case W_META_OFFSETCLIPRGN:
     432             :         {
     433           0 :             pOut->MoveClipRegion( ReadYXExt() );
     434             :         }
     435           0 :         break;
     436             : 
     437             :         case W_META_TEXTOUT:
     438             :         {
     439           0 :             sal_uInt16 nLength = 0;
     440           0 :             *pWMF >> nLength;
     441           0 :             if ( nLength )
     442             :             {
     443           0 :                 char*   pChar = new char[ ( nLength + 1 ) &~ 1 ];
     444           0 :                 pWMF->Read( pChar, ( nLength + 1 ) &~ 1 );
     445           0 :                 String aText( pChar, nLength, pOut->GetCharSet() );
     446           0 :                 delete[] pChar;
     447           0 :                 Point aPosition( ReadYX() );
     448           0 :                 pOut->DrawText( aPosition, aText );
     449             :             }
     450             :         }
     451           0 :         break;
     452             : 
     453             :         case W_META_EXTTEXTOUT:
     454             :         {
     455           0 :             sal_uInt16  nLen = 0, nOptions = 0;
     456           0 :             sal_Int32   nRecordPos, nRecordSize = 0, nOriginalTextLen, nNewTextLen;
     457           0 :             Point       aPosition;
     458           0 :             Rectangle   aRect;
     459           0 :             sal_Int32*  pDXAry = NULL;
     460             : 
     461           0 :             pWMF->SeekRel(-6);
     462           0 :             nRecordPos = pWMF->Tell();
     463           0 :             *pWMF >> nRecordSize;
     464           0 :             pWMF->SeekRel(2);
     465           0 :             aPosition = ReadYX();
     466           0 :             *pWMF >> nLen >> nOptions;
     467             : 
     468           0 :             sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT;
     469           0 :             if ( nOptions & ETO_RTLREADING )
     470           0 :                 nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT;
     471           0 :             pOut->SetTextLayoutMode( nTextLayoutMode );
     472             :             DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
     473             : 
     474             :             // Nur wenn der Text auch Zeichen enthaelt, macht die Ausgabe Sinn
     475           0 :             if( nLen )
     476             :             {
     477           0 :                 nOriginalTextLen = nLen;
     478           0 :                 if( nOptions & ETO_CLIPPED )
     479             :                 {
     480           0 :                     const Point aPt1( ReadPoint() );
     481           0 :                     const Point aPt2( ReadPoint() );
     482           0 :                     aRect = Rectangle( aPt1, aPt2 );
     483             :                 }
     484           0 :                 char* pChar = new char[ ( nOriginalTextLen + 1 ) &~ 1 ];
     485           0 :                 pWMF->Read( pChar, ( nOriginalTextLen + 1 ) &~ 1 );
     486           0 :                 String aText( pChar, (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain
     487           0 :                 nNewTextLen = aText.Len();                                              // less character (japanese version), so the
     488           0 :                 delete[] pChar;                                                         // dxAry will not fit
     489             : 
     490           0 :                 if ( nNewTextLen )
     491             :                 {
     492           0 :                     sal_uInt32  nMaxStreamPos = nRecordPos + ( nRecordSize << 1 );
     493           0 :                     sal_Int32   nDxArySize =  nMaxStreamPos - pWMF->Tell();
     494           0 :                     sal_Int32   nDxAryEntries = nDxArySize >> 1;
     495           0 :                     sal_Bool    bUseDXAry = sal_False;
     496             : 
     497           0 :                     if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) )
     498             :                     {
     499           0 :                         sal_Int16 nDx = 0, nDxTmp = 0;
     500             :                         sal_uInt16 i; //needed just outside the for
     501           0 :                         pDXAry = new sal_Int32[ nNewTextLen ];
     502           0 :                         for (i = 0; i < nNewTextLen; i++ )
     503             :                         {
     504           0 :                             if ( pWMF->Tell() >= nMaxStreamPos )
     505           0 :                                 break;
     506           0 :                             *pWMF >> nDx;
     507           0 :                             if ( nNewTextLen != nOriginalTextLen )
     508             :                             {
     509           0 :                                 sal_Unicode nUniChar = aText.GetChar(i);
     510           0 :                                 rtl::OString aTmp(&nUniChar, 1, pOut->GetCharSet());
     511           0 :                                 if ( aTmp.getLength() > 1 )
     512             :                                 {
     513           0 :                                     sal_Int32 nDxCount = aTmp.getLength() - 1;
     514           0 :                                     if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos )
     515             :                                         break;
     516           0 :                                     while ( nDxCount-- )
     517             :                                     {
     518           0 :                                         *pWMF >> nDxTmp;
     519           0 :                                         nDx = nDx + nDxTmp;
     520             :                                     }
     521           0 :                                 }
     522             :                             }
     523           0 :                             pDXAry[ i ] = nDx;
     524             :                         }
     525           0 :                         if ( i == nNewTextLen )
     526           0 :                             bUseDXAry = sal_True;
     527             :                     }
     528           0 :                     if ( pDXAry && bUseDXAry )
     529           0 :                         pOut->DrawText( aPosition, aText, pDXAry );
     530             :                     else
     531           0 :                         pOut->DrawText( aPosition, aText );
     532           0 :                 }
     533             :             }
     534           0 :             delete[] pDXAry;
     535             : 
     536             :         }
     537           0 :         break;
     538             : 
     539             :         case W_META_SELECTOBJECT:
     540             :         {
     541          38 :             sal_Int16   nObjIndex = 0;
     542          38 :             *pWMF >> nObjIndex;
     543          38 :             pOut->SelectObject( nObjIndex );
     544             :         }
     545          38 :         break;
     546             : 
     547             :         case W_META_SETTEXTALIGN:
     548             :         {
     549           0 :             sal_uInt16  nAlign = 0;
     550           0 :             *pWMF >> nAlign;
     551           0 :             pOut->SetTextAlign( nAlign );
     552             :         }
     553           0 :         break;
     554             : 
     555             :         case W_META_BITBLT:
     556             :         {
     557             :             // 0-3   : nWinROP                      #93454#
     558             :             // 4-5   : y offset of source bitmap
     559             :             // 6-7   : x offset of source bitmap
     560             :             // 8-9   : used height of source bitmap
     561             :             // 10-11 : used width  of source bitmap
     562             :             // 12-13 : destination position y (in pixel)
     563             :             // 14-15 : destination position x (in pixel)
     564             :             // 16-17 : dont know
     565             :             // 18-19 : Width Bitmap in Pixel
     566             :             // 20-21 : Height Bitmap in Pixel
     567             :             // 22-23 : bytes per scanline
     568             :             // 24    : planes
     569             :             // 25    : bitcount
     570             : 
     571           0 :             sal_Int32   nWinROP = 0;
     572           0 :             sal_uInt16  nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0;
     573             :             sal_uInt8   nPlanes, nBitCount;
     574             : 
     575           0 :             *pWMF >> nWinROP
     576           0 :                   >> nSy >> nSx >> nSye >> nSxe;
     577           0 :             Point aPoint( ReadYX() );
     578           0 :             *pWMF >> nDontKnow >> nWidth >> nHeight >> nBytesPerScan >> nPlanes >> nBitCount;
     579             : 
     580           0 :             if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) )
     581             :             {
     582           0 :                 Bitmap aBmp( Size( nWidth, nHeight ), nBitCount );
     583             :                 BitmapWriteAccess* pAcc;
     584           0 :                 pAcc = aBmp.AcquireWriteAccess();
     585           0 :                 if ( pAcc )
     586             :                 {
     587           0 :                     for (sal_uInt16 y = 0; y < nHeight; y++ )
     588             :                     {
     589           0 :                         sal_uInt16 x = 0;
     590           0 :                         for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ )
     591             :                         {
     592           0 :                             sal_Int8 nEightPixels = 0;
     593           0 :                             *pWMF >> nEightPixels;
     594           0 :                             for (sal_Int8 i = 7; i >= 0; i-- )
     595             :                             {
     596           0 :                                 if ( x < nWidth )
     597             :                                 {
     598           0 :                                     pAcc->SetPixel( y, x, (nEightPixels>>i)&1 );
     599             :                                 }
     600           0 :                                 x++;
     601             :                             }
     602             :                         }
     603             :                     }
     604           0 :                     aBmp.ReleaseAccess( pAcc );
     605           0 :                     if ( nSye && nSxe &&
     606           0 :                         ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
     607           0 :                             ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
     608             :                     {
     609           0 :                         Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
     610           0 :                         aBmp.Crop( aCropRect );
     611             :                     }
     612           0 :                     Rectangle aDestRect( aPoint, Size( nSxe, nSye ) );
     613           0 :                     aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
     614           0 :                 }
     615             :             }
     616             :         }
     617           0 :         break;
     618             : 
     619             :         case W_META_STRETCHBLT:
     620             :         case W_META_DIBBITBLT:
     621             :         case W_META_DIBSTRETCHBLT:
     622             :         case W_META_STRETCHDIB:
     623             :         {
     624           0 :             sal_Int32   nWinROP = 0;
     625           0 :             sal_uInt16  nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0;
     626           0 :             Bitmap      aBmp;
     627             : 
     628           0 :             *pWMF >> nWinROP;
     629             : 
     630           0 :             if( nFunc == W_META_STRETCHDIB )
     631           0 :                 *pWMF >> nUsage;
     632             : 
     633             :             // nSye and nSxe is the number of pixels that has to been used
     634             :             // If they are set to zero, it is as indicator not to scale the bitmap later
     635             :             //
     636           0 :             if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT )
     637           0 :                 *pWMF >> nSye >> nSxe;
     638             : 
     639             :             // nSy and nx is the offset of the first pixel
     640           0 :             *pWMF >> nSy >> nSx;
     641             : 
     642           0 :             if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT )
     643             :             {
     644           0 :                 if ( nWinROP == PATCOPY )
     645           0 :                     *pWMF >> nUsage;    // i don't know anything of this parameter, so its called nUsage
     646             :                                         // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False );
     647             : 
     648           0 :                 Size aDestSize( ReadYXExt() );
     649           0 :                 if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
     650             :                 {
     651           0 :                     Rectangle aDestRect( ReadYX(), aDestSize );
     652           0 :                     if ( nWinROP != PATCOPY )
     653           0 :                         aBmp.Read( *pWMF, sal_False );
     654             : 
     655             :                     // test if it is sensible to crop
     656           0 :                     if ( nSye && nSxe &&
     657           0 :                         ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) &&
     658           0 :                             ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) )
     659             :                     {
     660           0 :                         Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) );
     661           0 :                         aBmp.Crop( aCropRect );
     662             :                     }
     663           0 :                     aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) );
     664             :                 }
     665           0 :             }
     666             :         }
     667           0 :         break;
     668             : 
     669             :         case W_META_DIBCREATEPATTERNBRUSH:
     670             :         {
     671           0 :             Bitmap  aBmp;
     672             :             BitmapReadAccess* pBmp;
     673           0 :             sal_uInt32  nRed = 0, nGreen = 0, nBlue = 0, nCount = 1;
     674           0 :             sal_uInt16  nFunction = 0;
     675             : 
     676           0 :             *pWMF >> nFunction >> nFunction;
     677             : 
     678           0 :             aBmp.Read( *pWMF, sal_False );
     679           0 :             pBmp = aBmp.AcquireReadAccess();
     680           0 :             if ( pBmp )
     681             :             {
     682           0 :                 for ( sal_Int32 y = 0; y < pBmp->Height(); y++ )
     683             :                 {
     684           0 :                     for ( sal_Int32 x = 0; x < pBmp->Width(); x++ )
     685             :                     {
     686           0 :                         const BitmapColor aColor( pBmp->GetColor( y, x ) );
     687             : 
     688           0 :                         nRed += aColor.GetRed();
     689           0 :                         nGreen += aColor.GetGreen();
     690           0 :                         nBlue += aColor.GetBlue();
     691           0 :                     }
     692             :                 }
     693           0 :                 nCount = pBmp->Height() * pBmp->Width();
     694           0 :                 if ( !nCount )
     695           0 :                     nCount++;
     696           0 :                 aBmp.ReleaseAccess( pBmp );
     697             :             }
     698           0 :             Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) );
     699           0 :             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, sal_False ) );
     700             :         }
     701           0 :         break;
     702             : 
     703             :         case W_META_DELETEOBJECT:
     704             :         {
     705           9 :             sal_Int16 nIndex = 0;
     706           9 :             *pWMF >> nIndex;
     707           9 :             pOut->DeleteObject( nIndex );
     708             :         }
     709           9 :         break;
     710             : 
     711             :         case W_META_CREATEPALETTE:
     712             :         {
     713           0 :             pOut->CreateObject( GDI_DUMMY );
     714             :         }
     715           0 :         break;
     716             : 
     717             :         case W_META_CREATEBRUSH:
     718             :         {
     719           0 :             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) );
     720             :         }
     721           0 :         break;
     722             : 
     723             :         case W_META_CREATEPATTERNBRUSH:
     724             :         {
     725           0 :             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) );
     726             :         }
     727           0 :         break;
     728             : 
     729             :         case W_META_CREATEPENINDIRECT:
     730             :         {
     731           8 :             LineInfo    aLineInfo;
     732           8 :             sal_uInt16      nStyle = 0, nWidth = 0, nHeight = 0;
     733             : 
     734           8 :             *pWMF >> nStyle >> nWidth >> nHeight;
     735             : 
     736           8 :             if ( nWidth )
     737           1 :                 aLineInfo.SetWidth( nWidth );
     738             : 
     739           8 :             sal_Bool bTransparent = sal_False;
     740           8 :             sal_uInt16 nDashCount = 0;
     741           8 :             sal_uInt16 nDotCount = 0;
     742           8 :             switch( nStyle )
     743             :             {
     744             :                 case PS_DASHDOTDOT :
     745           0 :                     nDotCount++;
     746             :                 case PS_DASHDOT :
     747           0 :                     nDashCount++;
     748             :                 case PS_DOT :
     749           0 :                     nDotCount++;
     750           0 :                 break;
     751             :                 case PS_DASH :
     752           0 :                     nDashCount++;
     753           0 :                 break;
     754             :                 case PS_NULL :
     755           3 :                     bTransparent = sal_True;
     756           3 :                     aLineInfo.SetStyle( LINE_NONE );
     757           3 :                 break;
     758             :                 default :
     759             :                 case PS_INSIDEFRAME :
     760             :                 case PS_SOLID :
     761           5 :                     aLineInfo.SetStyle( LINE_SOLID );
     762             :             }
     763           8 :             if ( nDashCount | nDotCount )
     764             :             {
     765           0 :                 aLineInfo.SetStyle( LINE_DASH );
     766           0 :                 aLineInfo.SetDashCount( nDashCount );
     767           0 :                 aLineInfo.SetDotCount( nDotCount );
     768             :             }
     769           8 :             pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) );
     770             :         }
     771           8 :         break;
     772             : 
     773             :         case W_META_CREATEBRUSHINDIRECT:
     774             :         {
     775          15 :             sal_uInt16  nStyle = 0;
     776          15 :             *pWMF >> nStyle;
     777          15 :             pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_False ) );
     778             :         }
     779          15 :         break;
     780             : 
     781             :         case W_META_CREATEFONTINDIRECT:
     782             :         {
     783           2 :             Size    aFontSize;
     784             :             char    lfFaceName[ LF_FACESIZE ];
     785           2 :             sal_Int16   lfEscapement = 0, lfOrientation = 0, lfWeight = 0;  // ( formerly sal_uInt16 )
     786             : 
     787           2 :             LOGFONTW aLogFont;
     788           2 :             aFontSize = ReadYXExt();
     789           2 :             *pWMF >> lfEscapement >> lfOrientation >> lfWeight
     790           2 :                     >> aLogFont.lfItalic >> aLogFont.lfUnderline >> aLogFont.lfStrikeOut >> aLogFont.lfCharSet >> aLogFont.lfOutPrecision
     791           2 :                         >> aLogFont.lfClipPrecision >> aLogFont.lfQuality >> aLogFont.lfPitchAndFamily;
     792           2 :             pWMF->Read( lfFaceName, LF_FACESIZE );
     793           2 :             aLogFont.lfWidth = aFontSize.Width();
     794           2 :             aLogFont.lfHeight = aFontSize.Height();
     795           2 :             aLogFont.lfEscapement = lfEscapement;
     796           2 :             aLogFont.lfOrientation = lfOrientation;
     797           2 :             aLogFont.lfWeight = lfWeight;
     798             : 
     799             :             CharSet eCharSet;
     800           2 :             if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) )
     801           0 :                 eCharSet = osl_getThreadTextEncoding();
     802             :             else
     803           2 :                 eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet );
     804           2 :             if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
     805           0 :                 eCharSet = osl_getThreadTextEncoding();
     806           2 :             if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
     807           0 :                 eCharSet = RTL_TEXTENCODING_MS_1252;
     808           2 :             aLogFont.alfFaceName = UniString( lfFaceName, eCharSet );
     809             : 
     810           2 :             pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) );
     811             :         }
     812           2 :         break;
     813             : 
     814             :         case W_META_CREATEBITMAPINDIRECT:
     815             :         {
     816           0 :             pOut->CreateObject( GDI_DUMMY );
     817             :         }
     818           0 :         break;
     819             : 
     820             :         case W_META_CREATEBITMAP:
     821             :         {
     822           0 :             pOut->CreateObject( GDI_DUMMY );
     823             :         }
     824           0 :         break;
     825             : 
     826             :         case W_META_CREATEREGION:
     827             :         {
     828           0 :             pOut->CreateObject( GDI_DUMMY );
     829             :         }
     830           0 :         break;
     831             : 
     832             :         case W_META_EXCLUDECLIPRECT :
     833             :         {
     834           0 :             pOut->ExcludeClipRect( ReadRectangle() );
     835             :         }
     836           0 :         break;
     837             : 
     838             :         case W_META_PATBLT:
     839             :         {
     840           0 :             sal_uInt32 nROP = 0, nOldROP = 0;
     841           0 :             *pWMF >> nROP;
     842           0 :             Size aSize = ReadYXExt();
     843           0 :             nOldROP = pOut->SetRasterOp( nROP );
     844           0 :             pOut->DrawRect( Rectangle( ReadYX(), aSize ), sal_False );
     845           0 :             pOut->SetRasterOp( nOldROP );
     846             :         }
     847           0 :         break;
     848             : 
     849             :         case W_META_SELECTCLIPREGION:
     850             :         {
     851           0 :             sal_Int16 nObjIndex = 0;
     852           0 :             *pWMF >> nObjIndex;
     853           0 :             if ( !nObjIndex )
     854             :             {
     855           0 :                 PolyPolygon aEmptyPolyPoly;
     856           0 :                 pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, sal_True );
     857             :             }
     858             :         }
     859           0 :         break;
     860             : 
     861             :         case W_META_ESCAPE :
     862             :         {
     863             :             // nRecSize has been checked previously to be greater than 3
     864           0 :             sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2;
     865           0 :             sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize;
     866             : 
     867             :             // taking care that nRecSize does not exceed the maximal stream position
     868           0 :             if ( nMetaRecEndPos > nEndPos )
     869             :             {
     870           0 :                 pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
     871           0 :                 break;
     872             :             }
     873           0 :             if ( nRecSize >= 4 )    // minimal escape lenght
     874             :             {
     875           0 :                 sal_uInt16  nMode = 0, nLen = 0;
     876           0 :                 *pWMF >> nMode
     877           0 :                       >> nLen;
     878           0 :                 if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) )
     879             :                 {
     880           0 :                     sal_uInt32 nNewMagic = 0; // we have to read int32 for
     881           0 :                     *pWMF >> nNewMagic;   // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
     882             : 
     883           0 :                     if( nNewMagic == 0x2c2a4f4f &&  nLen >= 14 )
     884             :                     {
     885           0 :                         sal_uInt16 nMagic2 = 0;
     886           0 :                         *pWMF >> nMagic2;
     887           0 :                         if( nMagic2 == 0x0a ) // 2nd half of magic
     888             :                         {                     // continue with private escape
     889           0 :                             sal_uInt32 nCheck = 0, nEsc = 0;
     890           0 :                             *pWMF >> nCheck
     891           0 :                                   >> nEsc;
     892             : 
     893           0 :                             sal_uInt32 nEscLen = nLen - 14;
     894           0 :                             if ( nEscLen <= ( nRecSize * 2 ) )
     895             :                             {
     896             : #ifdef OSL_BIGENDIAN
     897             :                                 sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc );
     898             :                                 sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 );
     899             : #else
     900           0 :                                 sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 );
     901             : #endif
     902           0 :                                 sal_Int8* pData = NULL;
     903             : 
     904           0 :                                 if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos )
     905             :                                 {
     906           0 :                                     pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
     907             :                                     break;
     908             :                                 }
     909           0 :                                 if ( nEscLen > 0 )
     910             :                                 {
     911           0 :                                     pData = new sal_Int8[ nEscLen ];
     912           0 :                                     pWMF->Read( pData, nEscLen );
     913           0 :                                     nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen );
     914             :                                 }
     915           0 :                                 if ( nCheck == nCheckSum )
     916             :                                 {
     917           0 :                                     switch( nEsc )
     918             :                                     {
     919             :                                         case PRIVATE_ESCAPE_UNICODE :
     920             :                                         {   // we will use text instead of polygons only if we have the correct font
     921           0 :                                             if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) )
     922             :                                             {
     923           0 :                                                 Point  aPt;
     924           0 :                                                 String aString;
     925             :                                                 sal_uInt32  nStringLen, nDXCount;
     926           0 :                                                 sal_Int32* pDXAry = NULL;
     927           0 :                                                 SvMemoryStream aMemoryStream( nEscLen );
     928           0 :                                                 aMemoryStream.Write( pData, nEscLen );
     929           0 :                                                 aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN );
     930             :                                                 //#fdo39428 SvStream no longer supports operator>>(long&)
     931           0 :                                                 sal_Int32 nTmpX(0), nTmpY(0);
     932           0 :                                                 aMemoryStream >> nTmpX
     933           0 :                                                               >> nTmpY
     934           0 :                                                               >> nStringLen;
     935           0 :                                                  aPt.X() = nTmpX;
     936           0 :                                                  aPt.Y() = nTmpY;
     937             : 
     938           0 :                                                 if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) )
     939             :                                                 {
     940             : 
     941           0 :                                                     aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen);
     942           0 :                                                     aMemoryStream >> nDXCount;
     943           0 :                                                     if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) )
     944           0 :                                                         nDXCount = 0;
     945           0 :                                                     if ( nDXCount )
     946           0 :                                                         pDXAry = new sal_Int32[ nDXCount ];
     947           0 :                                                     for  (sal_uInt32 i = 0; i < nDXCount; i++ )
     948           0 :                                                         aMemoryStream >> pDXAry[ i ];
     949           0 :                                                     aMemoryStream >> nSkipActions;
     950           0 :                                                     pOut->DrawText( aPt, aString, pDXAry );
     951           0 :                                                     delete[] pDXAry;
     952           0 :                                                 }
     953             :                                             }
     954             :                                         }
     955           0 :                                         break;
     956             :                                     }
     957             :                                 }
     958           0 :                                 delete[] pData;
     959             :                             }
     960           0 :                         }
     961             :                     }
     962           0 :                     else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) ))
     963             :                     {
     964           0 :                         sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0,
     965           0 :                                    nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0;
     966           0 :                         sal_uInt16 nCheck = 0;
     967             : 
     968           0 :                         *pWMF >> nComType >> nVersion >> nCheck >> nFlags
     969           0 :                               >> nComRecCount >> nCurRecSize
     970           0 :                               >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation
     971             :                                                                   // but it seems to be required to read in data produced by OLE
     972             : 
     973           0 :                         if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount )
     974             :                         {
     975           0 :                             if( !nEMFRec )
     976             :                             {   // first EMF comment
     977           0 :                                 nEMFRecCount    = nComRecCount;
     978           0 :                                 nEMFSize        = nEMFTotalSize;
     979           0 :                                 pEMFStream = new SvMemoryStream( nEMFSize );
     980             :                             }
     981           0 :                             else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here
     982             :                             {
     983             :                                 // total records should be the same as in previous comments
     984           0 :                                 nEMFRecCount = 0xFFFFFFFF;
     985           0 :                                 delete pEMFStream;
     986           0 :                                 pEMFStream = NULL;
     987             :                             }
     988           0 :                             nEMFRec++;
     989             : 
     990           0 :                             if( pEMFStream && nCurRecSize + 34 > nLen )
     991             :                             {
     992           0 :                                 nEMFRecCount = 0xFFFFFFFF;
     993           0 :                                 delete pEMFStream;
     994           0 :                                 pEMFStream = NULL;
     995             :                             }
     996             : 
     997           0 :                             if( pEMFStream )
     998             :                             {
     999           0 :                                 sal_Int8* pBuf = new sal_Int8[ nCurRecSize ];
    1000           0 :                                 sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize );
    1001           0 :                                 if( nCount == nCurRecSize )
    1002           0 :                                     pEMFStream->Write( pBuf, nCount );
    1003           0 :                                 delete[] pBuf;
    1004             :                             }
    1005             :                         }
    1006             :                     }
    1007             :                 }
    1008             :             }
    1009             :         }
    1010           0 :         break;
    1011             : 
    1012             :         case W_META_SETRELABS:
    1013             :         case W_META_SETPOLYFILLMODE:
    1014             :         case W_META_SETSTRETCHBLTMODE:
    1015             :         case W_META_SETTEXTCHAREXTRA:
    1016             :         case W_META_SETTEXTJUSTIFICATION:
    1017             :         case W_META_FLOODFILL :
    1018             :         case W_META_FILLREGION:
    1019             :         case W_META_FRAMEREGION:
    1020             :         case W_META_INVERTREGION:
    1021             :         case W_META_PAINTREGION:
    1022             :         case W_META_DRAWTEXT:
    1023             :         case W_META_SETMAPPERFLAGS:
    1024             :         case W_META_SETDIBTODEV:
    1025             :         case W_META_SELECTPALETTE:
    1026             :         case W_META_REALIZEPALETTE:
    1027             :         case W_META_ANIMATEPALETTE:
    1028             :         case W_META_SETPALENTRIES:
    1029             :         case W_META_RESIZEPALETTE:
    1030             :         case W_META_EXTFLOODFILL:
    1031             :         case W_META_RESETDC:
    1032             :         case W_META_STARTDOC:
    1033             :         case W_META_STARTPAGE:
    1034             :         case W_META_ENDPAGE:
    1035             :         case W_META_ABORTDOC:
    1036             :         case W_META_ENDDOC:
    1037          13 :         break;
    1038             :     }
    1039         125 : }
    1040             : 
    1041             : // ------------------------------------------------------------------------
    1042             : 
    1043          13 : sal_Bool WMFReader::ReadHeader()
    1044             : {
    1045          13 :     sal_Size nStrmPos = pWMF->Tell();
    1046             : 
    1047          13 :     sal_uInt32 nPlaceableMetaKey(0);
    1048             :     // Einlesen des METAFILEHEADER, falls vorhanden
    1049          13 :     *pWMF >> nPlaceableMetaKey;
    1050          13 :     if (!pWMF->good())
    1051           0 :         return false;
    1052             : 
    1053          13 :     Rectangle aPlaceableBound;
    1054             : 
    1055          13 :     if (nPlaceableMetaKey == 0x9ac6cdd7L)
    1056             :     { //TODO do some real error handling here
    1057             :         sal_Int16 nVal;
    1058             : 
    1059             :         // Skip reserved bytes
    1060           3 :         pWMF->SeekRel(2);
    1061             : 
    1062             :         // BoundRect
    1063           3 :         *pWMF >> nVal;
    1064           3 :         aPlaceableBound.Left() = nVal;
    1065           3 :         *pWMF >> nVal;
    1066           3 :         aPlaceableBound.Top() = nVal;
    1067           3 :         *pWMF >> nVal;
    1068           3 :         aPlaceableBound.Right() = nVal;
    1069           3 :         *pWMF >> nVal;
    1070           3 :         aPlaceableBound.Bottom() = nVal;
    1071             : 
    1072             :         // inch
    1073           3 :         *pWMF >> nUnitsPerInch;
    1074             : 
    1075             :         // reserved
    1076           3 :         pWMF->SeekRel( 4 );
    1077             : 
    1078             :         // Skip and don't check the checksum
    1079           3 :         pWMF->SeekRel( 2 );
    1080             :     }
    1081             :     else
    1082             :     {
    1083          10 :         nUnitsPerInch = 96;
    1084          10 :         pWMF->Seek( nStrmPos + 18 );    // set the streampos to the start of the the metaactions
    1085          10 :         GetPlaceableBound( aPlaceableBound, pWMF );
    1086          10 :         pWMF->Seek( nStrmPos );
    1087          10 :         if ( pExternalHeader != NULL && ( pExternalHeader->mapMode == MM_ISOTROPIC
    1088             :                                         || pExternalHeader->mapMode == MM_ANISOTROPIC ) )
    1089             :         {
    1090             :             // #n417818#: If we have an external header then overwrite the bounds!
    1091             :             Rectangle aExtRect(0, 0,
    1092             :                           pExternalHeader->xExt*567*nUnitsPerInch/1440/1000,
    1093           0 :                           pExternalHeader->yExt*567*nUnitsPerInch/1440/1000);
    1094           0 :             GetWinExtMax( aExtRect, aPlaceableBound, pExternalHeader->mapMode );
    1095           0 :             pOut->SetMapMode( pExternalHeader->mapMode );
    1096             :         }
    1097             :     }
    1098             : 
    1099          13 :     pOut->SetUnitsPerInch( nUnitsPerInch );
    1100          13 :     pOut->SetWinOrg( aPlaceableBound.TopLeft() );
    1101          13 :     Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) );
    1102          13 :     pOut->SetWinExt( aWMFSize );
    1103             : 
    1104          13 :     Size aDevExt( 10000, 10000 );
    1105          13 :     if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) )
    1106             :     {
    1107          13 :         const Fraction  aFrac( 1, nUnitsPerInch );
    1108          13 :         MapMode         aWMFMap( MAP_INCH, Point(), aFrac, aFrac );
    1109          13 :         Size            aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) );
    1110          13 :         aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) );
    1111             :     }
    1112          13 :     pOut->SetDevExt( aDevExt );
    1113             : 
    1114             :     // Einlesen des METAHEADER
    1115          13 :     sal_uInt32 nMetaKey(0);
    1116          13 :     *pWMF >> nMetaKey; // Typ und Headergroesse
    1117          13 :     if (!pWMF->good())
    1118           6 :         return false;
    1119           7 :     if (nMetaKey != 0x00090001)
    1120             :     {
    1121           0 :         sal_uInt16 aNextWord(0);
    1122           0 :         *pWMF >> aNextWord;
    1123           0 :         if (nMetaKey != 0x10000 || aNextWord != 0x09)
    1124             :         {
    1125           0 :             pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1126           0 :             return false;
    1127             :         }
    1128             :     }
    1129             : 
    1130           7 :     pWMF->SeekRel( 2 ); // Version (von Windows)
    1131           7 :     pWMF->SeekRel( 4 ); // Size (der Datei in Words)
    1132           7 :     pWMF->SeekRel( 2 ); // NoObjects (Maximale Anzahl der gleichzeitigen Objekte)
    1133           7 :     pWMF->SeekRel( 4 ); // MaxRecord (Groesse des groessten Records in Words)
    1134           7 :     pWMF->SeekRel( 2 ); // NoParameters (Unused
    1135             : 
    1136           7 :     return pWMF->good();
    1137             : }
    1138             : 
    1139          13 : void WMFReader::ReadWMF()
    1140             : {
    1141             :     sal_uInt16  nFunction;
    1142             :     sal_uLong   nPos, nPercent, nLastPercent;
    1143             : 
    1144          13 :     nSkipActions = 0;
    1145          13 :     nCurrentAction = 0;
    1146          13 :     nUnicodeEscapeAction = 0;
    1147             : 
    1148          13 :     pEMFStream      = NULL;
    1149          13 :     nEMFRecCount    = 0;
    1150          13 :     nEMFRec         = 0;
    1151          13 :     nEMFSize        = 0;
    1152             : 
    1153          13 :     sal_Bool bEMFAvailable = sal_False;
    1154             : 
    1155          13 :     pOut->SetMapMode( MM_ANISOTROPIC );
    1156          13 :     pOut->SetWinOrg( Point() );
    1157          13 :     pOut->SetWinExt( Size( 1, 1 ) );
    1158          13 :     pOut->SetDevExt( Size( 10000, 10000 ) );
    1159             : 
    1160          13 :     nEndPos=pWMF->Seek( STREAM_SEEK_TO_END );
    1161          13 :     pWMF->Seek( nStartPos );
    1162          13 :     Callback( (sal_uInt16) ( nLastPercent = 0 ) );
    1163             : 
    1164          13 :     if ( ReadHeader( ) )
    1165             :     {
    1166             : 
    1167           7 :         nPos = pWMF->Tell();
    1168             : 
    1169           7 :         if( nEndPos - nStartPos )
    1170             :         {
    1171         125 :             while( sal_True )
    1172             :             {
    1173         132 :                 nCurrentAction++;
    1174         132 :                 nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos );
    1175             : 
    1176         132 :                 if( nLastPercent + 4 <= nPercent )
    1177             :                 {
    1178          73 :                     Callback( (sal_uInt16) nPercent );
    1179          73 :                     nLastPercent = nPercent;
    1180             :                 }
    1181         132 :                 *pWMF >> nRecSize >> nFunction;
    1182             : 
    1183         257 :                 if(  pWMF->GetError()
    1184             :                   || ( nRecSize < 3 )
    1185             :                   || (  nRecSize  == 3
    1186             :                      && nFunction == 0
    1187             :                      )
    1188         125 :                   || pWMF->IsEof()
    1189             :                   )
    1190             :                 {
    1191           7 :                     if( pWMF->IsEof() )
    1192           1 :                         pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1193             : 
    1194           7 :                     break;
    1195             :                 }
    1196         125 :                 if ( !bEMFAvailable )
    1197             :                 {
    1198         125 :                     if(   !aBmpSaveList.empty()
    1199             :                       && ( nFunction != W_META_STRETCHDIB    )
    1200             :                       && ( nFunction != W_META_DIBBITBLT     )
    1201             :                       && ( nFunction != W_META_DIBSTRETCHBLT )
    1202             :                       )
    1203             :                     {
    1204           0 :                         pOut->ResolveBitmapActions( aBmpSaveList );
    1205             :                     }
    1206             : 
    1207         125 :                     if ( !nSkipActions )
    1208         125 :                         ReadRecordParams( nFunction );
    1209             :                     else
    1210           0 :                         nSkipActions--;
    1211             : 
    1212         125 :                     if( pEMFStream && nEMFRecCount == nEMFRec )
    1213             :                     {
    1214           0 :                         GDIMetaFile aMeta;
    1215           0 :                         pEMFStream->Seek( 0 );
    1216           0 :                         EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta );
    1217           0 :                         bEMFAvailable = pEMFReader->ReadEnhWMF();
    1218           0 :                         delete pEMFReader; // destroy first!!!
    1219             : 
    1220           0 :                         if( bEMFAvailable )
    1221             :                         {
    1222           0 :                             pOut->AddFromGDIMetaFile( aMeta );
    1223           0 :                             pOut->SetrclFrame( Rectangle( Point(0, 0), aMeta.GetPrefSize()));
    1224             : 
    1225             :                             // the stream needs to be set to the wmf end position,
    1226             :                             // otherwise the GfxLink that is created will be incorrect
    1227             :                             // (leading to graphic loss after swapout/swapin).
    1228             :                             // so we will proceed normally, but are ignoring further wmf
    1229             :                             // records
    1230             :                         }
    1231             :                         else
    1232             :                         {
    1233             :                             // something went wrong
    1234             :                             // continue with WMF, don't try this again
    1235           0 :                             delete pEMFStream;
    1236           0 :                             pEMFStream = NULL;
    1237           0 :                         }
    1238             :                     }
    1239             :                 }
    1240         125 :                 nPos += nRecSize * 2;
    1241         125 :                 if ( nPos <= nEndPos )
    1242         124 :                     pWMF->Seek( nPos  );
    1243             :                 else
    1244           1 :                     pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1245             :             }
    1246             :         }
    1247             :         else
    1248           0 :             pWMF->SetError( SVSTREAM_GENERALERROR );
    1249             : 
    1250           7 :         if( !pWMF->GetError() && !aBmpSaveList.empty() )
    1251           0 :             pOut->ResolveBitmapActions( aBmpSaveList );
    1252             :     }
    1253          13 :     if ( pWMF->GetError() )
    1254           8 :         pWMF->Seek( nStartPos );
    1255          13 : }
    1256             : 
    1257             : // ------------------------------------------------------------------------
    1258             : 
    1259          10 : sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm )
    1260             : {
    1261          10 :     sal_Bool bRet = sal_True;
    1262             : 
    1263          10 :     rPlaceableBound.Left()   = (sal_Int32)0x7fffffff;
    1264          10 :     rPlaceableBound.Top()    = (sal_Int32)0x7fffffff;
    1265          10 :     rPlaceableBound.Right()  = (sal_Int32)0x80000000;
    1266          10 :     rPlaceableBound.Bottom() = (sal_Int32)0x80000000;
    1267             : 
    1268          10 :     sal_uInt32 nPos = pStm->Tell();
    1269          10 :     sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END );
    1270             : 
    1271          10 :     pStm->Seek( nPos );
    1272             : 
    1273          10 :     if( nEnd - nPos )
    1274             :     {
    1275          10 :         sal_Int16 nMapMode = MM_ANISOTROPIC;
    1276             :         sal_uInt16 nFunction;
    1277             :         sal_uInt32 nRSize;
    1278             : 
    1279        2234 :         while( bRet )
    1280             :         {
    1281        2218 :             *pStm >> nRSize >> nFunction;
    1282             : 
    1283        2218 :             if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() )
    1284             :             {
    1285           4 :                 if( pStm->IsEof() )
    1286             :                 {
    1287           0 :                     pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1288           0 :                     bRet = sal_False;
    1289             :                 }
    1290           4 :                 break;
    1291             :             }
    1292        2214 :             switch( nFunction )
    1293             :             {
    1294             :                 case W_META_SETWINDOWORG:
    1295             :                 {
    1296          14 :                     Point aWinOrg;
    1297          14 :                     aWinOrg = ReadYX();
    1298          14 :                     rPlaceableBound.SetPos( aWinOrg );
    1299             :                 }
    1300          14 :                 break;
    1301             : 
    1302             :                 case W_META_SETWINDOWEXT:
    1303             :                 {
    1304          12 :                     sal_Int16 nWidth(0), nHeight(0);
    1305          12 :                     *pStm >> nHeight >> nWidth;
    1306          12 :                     rPlaceableBound.SetSize( Size( nWidth, nHeight ) );
    1307             :                 }
    1308          12 :                 break;
    1309             : 
    1310             :                 case W_META_SETMAPMODE :
    1311           6 :                     *pStm >> nMapMode;
    1312           6 :                 break;
    1313             : 
    1314             :                 case W_META_MOVETO:
    1315             :                 case W_META_LINETO:
    1316           0 :                     GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
    1317           0 :                 break;
    1318             : 
    1319             :                 case W_META_RECTANGLE:
    1320             :                 case W_META_INTERSECTCLIPRECT:
    1321             :                 case W_META_EXCLUDECLIPRECT :
    1322             :                 case W_META_ELLIPSE:
    1323          70 :                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
    1324          70 :                 break;
    1325             : 
    1326             :                 case W_META_ROUNDRECT:
    1327           0 :                     ReadYXExt(); // size
    1328           0 :                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
    1329           0 :                 break;
    1330             : 
    1331             :                 case W_META_ARC:
    1332             :                 case W_META_PIE:
    1333             :                 case W_META_CHORD:
    1334           0 :                     ReadYX(); // end
    1335           0 :                     ReadYX(); // start
    1336           0 :                     GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode );
    1337           0 :                 break;
    1338             : 
    1339             :                 case W_META_POLYGON:
    1340             :                 {
    1341             :                     sal_uInt16 nPoints;
    1342           1 :                     *pStm >> nPoints;
    1343           6 :                     for(sal_uInt16 i = 0; i < nPoints; i++ )
    1344           5 :                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
    1345             :                 }
    1346           1 :                 break;
    1347             : 
    1348             :                 case W_META_POLYPOLYGON:
    1349             :                 {
    1350         159 :                     bool bRecordOk = true;
    1351         159 :                     sal_uInt16 nPoly, nPoints = 0;
    1352         159 :                     *pStm >> nPoly;
    1353         415 :                     for(sal_uInt16 i = 0; i < nPoly; i++ )
    1354             :                     {
    1355         258 :                         sal_uInt16 nP = 0;
    1356         258 :                         *pStm >> nP;
    1357         258 :                         if (nP > SAL_MAX_UINT16 - nPoints)
    1358             :                         {
    1359           2 :                             bRecordOk = false;
    1360             :                             break;
    1361             :                         }
    1362         256 :                         nPoints += nP;
    1363             :                     }
    1364             : 
    1365             :                     SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle");
    1366             : 
    1367         159 :                     bRecordOk &= pStm->good();
    1368             : 
    1369         159 :                     if (!bRecordOk)
    1370             :                     {
    1371           2 :                         pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1372           2 :                         bRet = sal_False;
    1373             :                         break;
    1374             :                     }
    1375             : 
    1376       67741 :                     for (sal_uInt16 i = 0; i < nPoints; i++ )
    1377       67584 :                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
    1378             : 
    1379         157 :                     bRecordOk &= pStm->good();
    1380             : 
    1381         157 :                     if (!bRecordOk)
    1382             :                     {
    1383           1 :                         pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1384           1 :                         bRet = sal_False;
    1385             :                         break;
    1386             :                     }
    1387             :                 }
    1388         156 :                 break;
    1389             : 
    1390             :                 case W_META_POLYLINE:
    1391             :                 {
    1392             :                     sal_uInt16 nPoints;
    1393          75 :                     *pStm >> nPoints;
    1394         234 :                     for(sal_uInt16 i = 0; i < nPoints; i++ )
    1395         159 :                         GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode );
    1396             :                 }
    1397          75 :                 break;
    1398             : 
    1399             :                 case W_META_SETPIXEL:
    1400             :                 {
    1401           0 :                     ReadColor();
    1402           0 :                     GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
    1403             :                 }
    1404           0 :                 break;
    1405             : 
    1406             :                 case W_META_TEXTOUT:
    1407             :                 {
    1408             :                     sal_uInt16 nLength;
    1409           0 :                     *pStm >> nLength;
    1410             :                     // todo: we also have to take care of the text width
    1411           0 :                     if ( nLength )
    1412             :                     {
    1413           0 :                         pStm->SeekRel( ( nLength + 1 ) &~ 1 );
    1414           0 :                         GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode );
    1415             :                     }
    1416             :                 }
    1417           0 :                 break;
    1418             : 
    1419             :                 case W_META_EXTTEXTOUT:
    1420             :                 {
    1421             :                     sal_uInt16  nLen, nOptions;
    1422           0 :                     Point       aPosition;
    1423             : 
    1424           0 :                     aPosition = ReadYX();
    1425           0 :                     *pStm >> nLen >> nOptions;
    1426             :                     // todo: we also have to take care of the text width
    1427           0 :                     if( nLen )
    1428           0 :                         GetWinExtMax( aPosition, rPlaceableBound, nMapMode );
    1429             :                 }
    1430           0 :                 break;
    1431             :                 case W_META_BITBLT:
    1432             :                 case W_META_STRETCHBLT:
    1433             :                 case W_META_DIBBITBLT:
    1434             :                 case W_META_DIBSTRETCHBLT:
    1435             :                 case W_META_STRETCHDIB:
    1436             :                 {
    1437             :                     sal_Int32   nWinROP;
    1438             :                     sal_uInt16  nSx, nSy, nSxe, nSye, nUsage;
    1439           0 :                     *pStm >> nWinROP;
    1440             : 
    1441           0 :                     if( nFunction == W_META_STRETCHDIB )
    1442           0 :                         *pStm >> nUsage;
    1443             : 
    1444             :                     // nSye and nSxe is the number of pixels that has to been used
    1445           0 :                     if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT )
    1446           0 :                         *pStm >> nSye >> nSxe;
    1447             :                     else
    1448           0 :                         nSye = nSxe = 0;    // set this to zero as indicator not to scale the bitmap later
    1449             : 
    1450             :                     // nSy and nx is the offset of the first pixel
    1451           0 :                     *pStm >> nSy >> nSx;
    1452             : 
    1453           0 :                     if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT )
    1454             :                     {
    1455           0 :                         if ( nWinROP == PATCOPY )
    1456           0 :                             *pStm >> nUsage;    // i don't know anything of this parameter, so its called nUsage
    1457             :                                                 // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False );
    1458             : 
    1459           0 :                         Size aDestSize( ReadYXExt() );
    1460           0 :                         if ( aDestSize.Width() && aDestSize.Height() )  // #92623# do not try to read buggy bitmaps
    1461             :                         {
    1462           0 :                             Rectangle aDestRect( ReadYX(), aDestSize );
    1463           0 :                             GetWinExtMax( aDestRect, rPlaceableBound, nMapMode );
    1464             :                         }
    1465             :                     }
    1466             :                 }
    1467           0 :                 break;
    1468             : 
    1469             :                 case W_META_PATBLT:
    1470             :                 {
    1471             :                     sal_uInt32 nROP;
    1472           0 :                     *pStm >> nROP;
    1473           0 :                     Size aSize = ReadYXExt();
    1474           0 :                     GetWinExtMax( Rectangle( ReadYX(), aSize ), rPlaceableBound, nMapMode );
    1475             :                 }
    1476           0 :                 break;
    1477             :             }
    1478        2214 :             nPos += nRSize * 2;
    1479        2214 :              if ( nPos <= nEnd )
    1480        2211 :                  pStm->Seek( nPos );
    1481             :              else
    1482             :              {
    1483           3 :                  pStm->SetError( SVSTREAM_FILEFORMAT_ERROR );
    1484           3 :                  bRet = sal_False;
    1485             :              }
    1486             : 
    1487             :         }
    1488             :     }
    1489             :     else
    1490             :     {
    1491           0 :         pStm->SetError( SVSTREAM_GENERALERROR );
    1492           0 :         bRet = sal_False;
    1493             :     }
    1494          10 :     return bRet;
    1495             : }
    1496             : 
    1497          26 : WMFReader::~WMFReader()
    1498             : {
    1499          13 :     if( pEMFStream )
    1500           0 :         delete pEMFStream;
    1501          13 : }
    1502             : 
    1503             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10