xref: /AOO41X/main/svtools/source/filter/wmf/winmtf.cxx (revision 8e8ee8fefdac26d905672cc573c35fd0ae1f9356)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 
27 
28 #include "winmtf.hxx"
29 #include <vcl/metaact.hxx>
30 #include <vcl/metric.hxx>
31 #include <rtl/tencinfo.h>
32 #include <vcl/svapp.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vos/mutex.hxx>
35 
36 // ------------------------------------------------------------------------
37 
38 #define WIN_MTF_MAX_CLIP_DEPTH 16
39 
ImpUpdateType()40 void WinMtfClipPath::ImpUpdateType()
41 {
42     if ( !aPolyPoly.Count() )
43         eType = EMPTY;
44     else if ( aPolyPoly.IsRect() )
45         eType = RECTANGLE;
46     else
47         eType = COMPLEX;
48 
49     bNeedsUpdate = sal_True;
50 }
51 
IntersectClipRect(const Rectangle & rRect)52 void WinMtfClipPath::IntersectClipRect( const Rectangle& rRect )
53 {
54     if ( !aPolyPoly.Count() )
55         aPolyPoly = Polygon( rRect );
56     else if ( nDepth < WIN_MTF_MAX_CLIP_DEPTH )
57     {
58         Polygon aPolygon( rRect );
59         PolyPolygon aIntersection;
60         PolyPolygon aPolyPolyRect( aPolygon );
61         aPolyPoly.GetIntersection( aPolyPolyRect, aIntersection );
62         aPolyPoly = aIntersection;
63         nDepth++;
64     }
65     ImpUpdateType();
66 }
67 
ExcludeClipRect(const Rectangle & rRect)68 void WinMtfClipPath::ExcludeClipRect( const Rectangle& rRect )
69 {
70     if ( aPolyPoly.Count() && ( nDepth < WIN_MTF_MAX_CLIP_DEPTH ) )
71     {
72         Polygon aPolygon( rRect );
73         PolyPolygon aPolyPolyRect( aPolygon );
74         PolyPolygon aDifference;
75         aPolyPoly.GetDifference( aPolyPolyRect, aDifference );
76         aPolyPoly = aDifference;
77         nDepth++;
78     }
79     ImpUpdateType();
80 }
81 
SetClipPath(const PolyPolygon & rPolyPolygon,sal_Int32 nClippingMode)82 void WinMtfClipPath::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode )
83 {
84     PolyPolygon aSimplePoly;
85     if ( rPolyPolygon.Count() && rPolyPolygon[ 0 ].HasFlags() )
86         rPolyPolygon.AdaptiveSubdivide( aSimplePoly, 100 );
87     if ( !aSimplePoly.Count() )
88         aPolyPoly = aSimplePoly;
89     else if ( nDepth < WIN_MTF_MAX_CLIP_DEPTH )
90     {
91         nDepth++;
92 
93         PolyPolygon aNewClipPath;
94 
95         // #115345# Watch out for empty aPolyPoly here - conceptually,
96         // an empty clip path is a rectangle of infinite size, but it
97         // is represented by an empty aPolyPoly. When intersecting
98         // rPolyPolygon with this _empty_ aPolyPoly, set algebra
99         // guarantees wrong results.
100         switch ( nClippingMode )
101         {
102             case RGN_OR :
103                 // #115345# clip stays empty, when ORing an arbitrary
104                 // rPolyPolygon. Thus, we can save us the unnecessary
105                 // clipper call.
106                 if( aPolyPoly.Count() )
107                     aPolyPoly.GetUnion( aSimplePoly, aNewClipPath );
108             break;
109             case RGN_XOR :
110                 // TODO:
111                 // #115345# Cannot handle this case, for the time being
112                 aPolyPoly.GetXOR( aSimplePoly, aNewClipPath );
113             break;
114             case RGN_DIFF :
115                 // TODO:
116                 // #115345# Cannot handle this case, for the time being
117                 aPolyPoly.GetDifference( aSimplePoly, aNewClipPath );
118             break;
119             case RGN_AND :
120                 // #115345# Clip becomes rPolyPolygon, when ANDing
121                 // with an arbitrary rPolyPolygon
122                 if( aPolyPoly.Count() )
123                     aPolyPoly.GetIntersection( aSimplePoly, aNewClipPath );
124                 else
125                     aNewClipPath = aSimplePoly;
126             break;
127             case RGN_COPY :
128                 aNewClipPath = aSimplePoly;
129             break;
130         }
131         aPolyPoly = aNewClipPath;
132     }
133     ImpUpdateType();
134 }
135 
MoveClipRegion(const Size & rSize)136 void WinMtfClipPath::MoveClipRegion( const Size& rSize )
137 {
138     aPolyPoly.Move( rSize.Width(), rSize.Height() );
139     bNeedsUpdate = sal_True;
140 }
141 
142 // ------------------------------------------------------------------------
143 
AddPoint(const Point & rPoint)144 void WinMtfPathObj::AddPoint( const Point& rPoint )
145 {
146     if ( bClosed )
147         Insert( Polygon(), POLYPOLY_APPEND );
148     Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
149     rPoly.Insert( rPoly.GetSize(), rPoint, POLY_NORMAL );
150     bClosed = sal_False;
151 }
152 
AddPolyLine(const Polygon & rPolyLine)153 void WinMtfPathObj::AddPolyLine( const Polygon& rPolyLine )
154 {
155     if ( bClosed )
156         Insert( Polygon(), POLYPOLY_APPEND );
157     Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
158     rPoly.Insert( rPoly.GetSize(), rPolyLine );
159     bClosed = sal_False;
160 }
161 
AddPolygon(const Polygon & rPoly)162 void WinMtfPathObj::AddPolygon( const Polygon& rPoly )
163 {
164     Insert( rPoly, POLYPOLY_APPEND );
165     bClosed = sal_True;
166 }
167 
AddPolyPolygon(const PolyPolygon & rPolyPoly)168 void WinMtfPathObj::AddPolyPolygon( const PolyPolygon& rPolyPoly )
169 {
170     sal_uInt16 i, nCount = rPolyPoly.Count();
171     for ( i = 0; i < nCount; i++ )
172         Insert( rPolyPoly[ i ], POLYPOLY_APPEND );
173     bClosed = sal_True;
174 }
175 
ClosePath()176 void WinMtfPathObj::ClosePath()
177 {
178     if ( Count() )
179     {
180         Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ];
181         if ( rPoly.GetSize() > 2 )
182         {
183             Point aFirst( rPoly[ 0 ] );
184             if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] )
185                 rPoly.Insert( rPoly.GetSize(), aFirst, POLY_NORMAL );
186         }
187     }
188     bClosed = sal_True;
189 }
190 
191 // ------------------------------------------------------------------------
192 
WinMtfFontStyle(LOGFONTW & rFont)193 WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont )
194 {
195     CharSet eCharSet;
196     if ( ( rFont.lfCharSet == OEM_CHARSET ) || ( rFont.lfCharSet == DEFAULT_CHARSET ) )
197         eCharSet = gsl_getSystemTextEncoding();
198     else
199         eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet );
200     if ( eCharSet == RTL_TEXTENCODING_DONTKNOW )
201         eCharSet = gsl_getSystemTextEncoding();
202     aFont.SetCharSet( eCharSet );
203     aFont.SetName( rFont.alfFaceName );
204     FontFamily eFamily;
205     switch ( rFont.lfPitchAndFamily & 0xf0 )
206     {
207         case FF_ROMAN:
208             eFamily = FAMILY_ROMAN;
209         break;
210 
211         case FF_SWISS:
212             eFamily = FAMILY_SWISS;
213         break;
214 
215         case FF_MODERN:
216             eFamily = FAMILY_MODERN;
217         break;
218 
219         case FF_SCRIPT:
220             eFamily = FAMILY_SCRIPT;
221         break;
222 
223         case FF_DECORATIVE:
224              eFamily = FAMILY_DECORATIVE;
225         break;
226 
227         default:
228             eFamily = FAMILY_DONTKNOW;
229         break;
230     }
231     aFont.SetFamily( eFamily );
232 
233     FontPitch ePitch;
234     switch ( rFont.lfPitchAndFamily & 0x0f )
235     {
236         case FIXED_PITCH:
237             ePitch = PITCH_FIXED;
238         break;
239 
240         case DEFAULT_PITCH:
241         case VARIABLE_PITCH:
242         default:
243             ePitch = PITCH_VARIABLE;
244         break;
245     }
246     aFont.SetPitch( ePitch );
247 
248     FontWeight eWeight;
249     if( rFont.lfWeight <= FW_THIN )
250         eWeight = WEIGHT_THIN;
251     else if( rFont.lfWeight <= FW_ULTRALIGHT )
252         eWeight = WEIGHT_ULTRALIGHT;
253     else if( rFont.lfWeight <= FW_LIGHT )
254         eWeight = WEIGHT_LIGHT;
255     else if( rFont.lfWeight <  FW_MEDIUM )
256         eWeight = WEIGHT_NORMAL;
257     else if( rFont.lfWeight == FW_MEDIUM )
258         eWeight = WEIGHT_MEDIUM;
259     else if( rFont.lfWeight <= FW_SEMIBOLD )
260         eWeight = WEIGHT_SEMIBOLD;
261     else if( rFont.lfWeight <= FW_BOLD )
262         eWeight = WEIGHT_BOLD;
263     else if( rFont.lfWeight <= FW_ULTRABOLD )
264         eWeight = WEIGHT_ULTRABOLD;
265     else
266         eWeight = WEIGHT_BLACK;
267     aFont.SetWeight( eWeight );
268 
269     if( rFont.lfItalic )
270         aFont.SetItalic( ITALIC_NORMAL );
271 
272     if( rFont.lfUnderline )
273         aFont.SetUnderline( UNDERLINE_SINGLE );
274 
275     if( rFont.lfStrikeOut )
276         aFont.SetStrikeout( STRIKEOUT_SINGLE );
277 
278     if ( rFont.lfOrientation )
279         aFont.SetOrientation( (short)rFont.lfOrientation );
280     else
281         aFont.SetOrientation( (short)rFont.lfEscapement );
282 
283     Size  aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) );
284     if ( rFont.lfHeight > 0 )
285     {
286         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
287         vos::OGuard aGuard( Application::GetSolarMutex() );
288         VirtualDevice aVDev;
289 
290         // converting the cell height into a font height
291         aFont.SetSize( aFontSize );
292         aVDev.SetFont( aFont );
293         FontMetric aMetric( aVDev.GetFontMetric() );
294         long nHeight = aMetric.GetAscent() + aMetric.GetDescent();
295         if ( nHeight )
296         {
297             double fHeight = ((double)aFontSize.Height() * rFont.lfHeight ) / nHeight;
298             aFontSize.Height() = (sal_Int32)( fHeight + 0.5 );
299         }
300     }
301     else if ( aFontSize.Height() < 0 )
302         aFontSize.Height() *= -1;
303 
304     if ( !rFont.lfWidth )
305     {
306         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
307         vos::OGuard aGuard( Application::GetSolarMutex() );
308         VirtualDevice aVDev;
309 
310         aFont.SetSize( aFontSize );
311         aVDev.SetFont( aFont );
312         FontMetric aMetric( aVDev.GetFontMetric() );
313         aFontSize.Width() = aMetric.GetWidth();
314     }
315 
316     aFont.SetSize( aFontSize );
317 };
318 
319 // ------------------------------------------------------------------------
320 
321 #ifdef WIN_MTF_ASSERT
WinMtfAssertHandler(const sal_Char * pAction,sal_uInt32 nFlags)322 void WinMtfAssertHandler( const sal_Char* pAction, sal_uInt32 nFlags )
323 {
324     static sal_Bool     bOnlyOnce;
325     static sal_Int32    nAssertCount;
326 
327     if ( nFlags & WIN_MTF_ASSERT_INIT )
328         nAssertCount = 0;
329     if ( nFlags & WIN_MTF_ASSERT_ONCE )
330        bOnlyOnce = sal_True;
331     if ( nFlags & WIN_MTF_ASSERT_MIFE )
332     {
333         if ( ( nAssertCount == 0 ) || ( bOnlyOnce == sal_False ) )
334         {
335             ByteString aText( "WMF/EMF Import: " );
336             if ( pAction )
337             {
338                 ByteString aAction( pAction );
339                 aText.Append( aAction );
340             }
341             aText.Append( " needs to be implemented (SJ)" );
342             DBG_ASSERT( 0, aText.GetBuffer() );
343         }
344         nAssertCount++;
345     }
346 }
347 #endif
348 
349 // ------------------------------------------------------------------------
350 
WinMtf(WinMtfOutput * pWinMtfOutput,SvStream & rStreamWMF,FilterConfigItem * pConfigItem)351 WinMtf::WinMtf( WinMtfOutput* pWinMtfOutput, SvStream& rStreamWMF, FilterConfigItem* pConfigItem ) :
352     pOut                ( pWinMtfOutput ),
353     pWMF                ( &rStreamWMF ),
354     pFilterConfigItem   ( pConfigItem )
355 {
356 #ifdef WIN_MTF_ASSERT
357     // we want to assert not implemented features, but we do this
358     // only once, so that nobody is handicaped by getting too much assertions
359     // I hope this will bring more testdocuments, without support of these
360     // testdocuments the implementation of missing features won't be possible. (SJ)
361     WinMtfAssertHandler( NULL, WIN_MTF_ASSERT_INIT | WIN_MTF_ASSERT_ONCE );
362 #endif
363 
364     SvLockBytes *pLB = pWMF->GetLockBytes();
365     if ( pLB )
366         pLB->SetSynchronMode( sal_True );
367 
368     nStartPos = pWMF->Tell();
369 
370     pOut->SetDevOrg( Point() );
371     if ( pFilterConfigItem )
372     {
373         xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
374         if ( xStatusIndicator.is() )
375         {
376             rtl::OUString aMsg;
377             xStatusIndicator->start( aMsg, 100 );
378         }
379     }
380 }
381 
382 // ------------------------------------------------------------------------
383 
~WinMtf()384 WinMtf::~WinMtf()
385 {
386     delete pOut;
387 
388     if ( xStatusIndicator.is() )
389         xStatusIndicator->end();
390 }
391 
392 // ------------------------------------------------------------------------
393 
Callback(sal_uInt16 nPercent)394 void WinMtf::Callback( sal_uInt16 nPercent )
395 {
396     if ( xStatusIndicator.is() )
397         xStatusIndicator->setValue( nPercent );
398 }
399 
400 // ------------------------------------------------------------------------
401 
ReadColor()402 Color WinMtf::ReadColor()
403 {
404     sal_uInt32 nColor;
405     *pWMF >> nColor;
406     return Color( (sal_uInt8)nColor, (sal_uInt8)( nColor >> 8 ), (sal_uInt8)( nColor >> 16 ) );
407 };
408 
409 //-----------------------------------------------------------------------------------
410 //-----------------------------------------------------------------------------------
411 //-----------------------------------------------------------------------------------
412 
ImplMap(const Point & rPt)413 Point WinMtfOutput::ImplMap( const Point& rPt )
414 {
415     if ( mnWinExtX && mnWinExtY )
416     {
417         double fX2, fX = rPt.X();
418         double fY2, fY = rPt.Y();
419 
420         fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx;
421         fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy;
422 
423         if ( mnGfxMode == GM_COMPATIBLE )
424         {
425             switch( mnMapMode )
426             {
427                 case MM_LOENGLISH :
428                 {
429                     fX2 -= mnWinOrgX;
430                     fY2  = mnWinOrgY-fY2;
431                     fX2 *= 25.40;
432                     fY2 *= 25.40;
433                     fX2 += mnDevOrgX;
434                     fY2 += mnDevOrgY;
435                 }
436                 break;
437                 case MM_HIENGLISH :
438                 {
439                     fX2 -= mnWinOrgX;
440                     fY2  = mnWinOrgY-fY2;
441                     fX2 *= 2.540;
442                     fY2 *= 2.540;
443                     fX2 += mnDevOrgX;
444                     fY2 += mnDevOrgY;
445                 }
446                 break;
447                 case MM_LOMETRIC :
448                 {
449                     fX2 -= mnWinOrgX;
450                     fY2  = mnWinOrgY-fY2;
451                     fX2 *= 10;
452                     fY2 *= 10;
453                     fX2 += mnDevOrgX;
454                     fY2 += mnDevOrgY;
455                 }
456                 break;
457                 case MM_HIMETRIC :
458                 {
459                     fX2 -= mnWinOrgX;
460                     fY2  = mnWinOrgY-fY2;
461                     fX2 += mnDevOrgX;
462                     fY2 += mnDevOrgY;
463                 }
464                 break;
465                 default :
466                 {
467                     fX2 -= mnWinOrgX;
468                     fY2 -= mnWinOrgY;
469                     fX2 /= mnWinExtX;
470                     fY2 /= mnWinExtY;
471                     fX2 *= mnDevWidth;
472                     fY2 *= mnDevHeight;
473                     fX2 += mnDevOrgX;
474                     fY2 += mnDevOrgY;   // fX2, fY2 now in device units
475                     fX2 *= (double)mnMillX * 100.0 / (double)mnPixX;
476                     fY2 *= (double)mnMillY * 100.0 / (double)mnPixY;
477                 }
478                 break;
479             }
480             fX2 -= mrclFrame.Left();
481             fY2 -= mrclFrame.Top();
482         }
483         return Point( FRound( fX2 ), FRound( fY2 ) );
484     }
485     else
486         return Point();
487 };
488 
489 // ------------------------------------------------------------------------
490 
ImplMap(const Size & rSz)491 Size WinMtfOutput::ImplMap( const Size& rSz )
492 {
493     if ( mnWinExtX && mnWinExtY )
494     {
495         // #121382# apply the whole WorldTransform, else a rotation will be misinterpreted
496         double fWidth = rSz.Width() * maXForm.eM11 + rSz.Height() * maXForm.eM21;
497         double fHeight = rSz.Width() * maXForm.eM12 + rSz.Height() * maXForm.eM22;
498 
499         if ( mnGfxMode == GM_COMPATIBLE )
500         {
501             switch( mnMapMode )
502             {
503                 case MM_LOENGLISH :
504                 {
505                     fWidth *= 25.40;
506                     fHeight*=-25.40;
507                 }
508                 break;
509                 case MM_HIENGLISH :
510                 {
511                     fWidth *= 2.540;
512                     fHeight*=-2.540;
513                 }
514                 break;
515                 case MM_LOMETRIC :
516                 {
517                     fWidth *= 10;
518                     fHeight*=-10;
519                 }
520                 break;
521                 case MM_HIMETRIC :
522                 {
523                     fHeight *= -1;
524                 }
525                 break;
526                 default :
527                 {
528                     fWidth /= mnWinExtX;
529                     fHeight /= mnWinExtY;
530                     fWidth *= mnDevWidth;
531                     fHeight *= mnDevHeight;
532                     fWidth *= (double)mnMillX * 100 / (double)mnPixX;
533                     fHeight *= (double)mnMillY * 100 / (double)mnPixY;
534                 }
535                 break;
536             }
537         }
538         return Size( FRound( fWidth ), FRound( fHeight ) );
539     }
540     else
541         return Size();
542 }
543 
544 //-----------------------------------------------------------------------------------
545 
ImplMap(const Rectangle & rRect)546 Rectangle WinMtfOutput::ImplMap( const Rectangle& rRect )
547 {
548     return Rectangle( ImplMap( rRect.TopLeft() ), ImplMap( rRect.GetSize() ) );
549 }
550 
551 //-----------------------------------------------------------------------------------
552 
ImplMap(Font & rFont)553 void WinMtfOutput::ImplMap( Font& rFont )
554 {
555     // !!! HACK: Wir setzen die Breite jetzt immer auf Null,
556     // da OS die Breite unterschiedlich interpretieren;
557     // muss spaeter in SV portabel gemacht werden ( KA 08.02.96 )
558     Size  aFontSize = ImplMap ( rFont.GetSize() );
559 
560     if( aFontSize.Height() < 0 )
561         aFontSize.Height() *= -1;
562 
563     rFont.SetSize( aFontSize );
564 
565     if( ( mnWinExtX * mnWinExtY ) < 0 )
566         rFont.SetOrientation( 3600 - rFont.GetOrientation() );
567 }
568 
569 //-----------------------------------------------------------------------------------
570 
ImplMap(Polygon & rPolygon)571 Polygon& WinMtfOutput::ImplMap( Polygon& rPolygon )
572 {
573     sal_uInt16 nPoints = rPolygon.GetSize();
574     for ( sal_uInt16 i = 0; i < nPoints; i++ )
575     {
576         rPolygon[ i ] = ImplMap( rPolygon[ i ] );
577     }
578     return rPolygon;
579 }
580 
581 //-----------------------------------------------------------------------------------
582 
ImplMap(PolyPolygon & rPolyPolygon)583 PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon )
584 {
585     sal_uInt16 nPolys = rPolyPolygon.Count();
586     for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ;
587     return rPolyPolygon;
588 }
589 
590 //-----------------------------------------------------------------------------------
591 
SelectObject(sal_Int32 nIndex)592 void WinMtfOutput::SelectObject( sal_Int32 nIndex )
593 {
594     GDIObj* pGDIObj = NULL;
595 
596     if ( nIndex & ENHMETA_STOCK_OBJECT )
597         pGDIObj = new GDIObj();
598     else
599     {
600         nIndex &= 0xffff;       // zur Sicherheit: mehr als 65535 nicht zulassen
601 
602         if ( (sal_uInt32)nIndex < vGDIObj.size() )
603             pGDIObj = vGDIObj[ nIndex ];
604     }
605 
606     if( pGDIObj == NULL )
607         return;
608 
609     if ( nIndex & ENHMETA_STOCK_OBJECT )
610     {
611         sal_uInt16 nStockId = (sal_uInt8)nIndex;
612         switch( nStockId )
613         {
614             case WHITE_BRUSH :
615             {
616                 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ) ) );
617             }
618             break;
619             case LTGRAY_BRUSH :
620             {
621                 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_LIGHTGRAY ) ) );
622             }
623             break;
624             case GRAY_BRUSH :
625             case DKGRAY_BRUSH :
626             {
627                 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_GRAY ) ) );
628             }
629             break;
630             case BLACK_BRUSH :
631             {
632                 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_BLACK ) ) );
633             }
634             break;
635             case NULL_BRUSH :
636             {
637                 pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True ) );
638             }
639             break;
640             case WHITE_PEN :
641             {
642                 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_WHITE ) ) );
643             }
644             break;
645             case BLACK_PEN :
646             {
647                 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_BLACK ) ) );
648             }
649             break;
650             case NULL_PEN :
651             {
652                 pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True ) );
653             }
654             break;
655             default:
656             break;
657         }
658     }
659     if ( pGDIObj->pStyle )
660     {
661         switch( pGDIObj->eType )
662         {
663             case GDI_PEN :
664                 maLineStyle = (WinMtfLineStyle*)pGDIObj->pStyle;
665             break;
666             case GDI_BRUSH :
667             {
668                 maFillStyle = (WinMtfFillStyle*)pGDIObj->pStyle;
669                 mbFillStyleSelected = sal_True;
670             }
671             break;
672             case GDI_FONT :
673                 maFont = ((WinMtfFontStyle*)pGDIObj->pStyle)->aFont;
674             break;
675             default:
676             break;  //  -Wall many options not handled.
677         }
678     }
679     if ( nIndex & ENHMETA_STOCK_OBJECT )
680         delete pGDIObj;
681 }
682 
683 //-----------------------------------------------------------------------------------
684 
SetFont(const Font & rFont)685 void WinMtfOutput::SetFont( const Font& rFont )
686 {
687     maFont = rFont;
688 }
689 
690 //-----------------------------------------------------------------------------------
691 
GetFont() const692 const Font& WinMtfOutput::GetFont() const
693 {
694     return maFont;
695 }
696 
697 //-----------------------------------------------------------------------------------
698 
SetTextLayoutMode(const sal_uInt32 nTextLayoutMode)699 void WinMtfOutput::SetTextLayoutMode( const sal_uInt32 nTextLayoutMode )
700 {
701     mnTextLayoutMode = nTextLayoutMode;
702 }
703 
704 //-----------------------------------------------------------------------------------
705 
GetTextLayoutMode() const706 sal_uInt32 WinMtfOutput::GetTextLayoutMode() const
707 {
708     return mnTextLayoutMode;
709 }
710 
711 //-----------------------------------------------------------------------------------
712 
SetBkMode(sal_uInt32 nMode)713 void WinMtfOutput::SetBkMode( sal_uInt32 nMode )
714 {
715     mnBkMode = nMode;
716 }
717 
718 //-----------------------------------------------------------------------------------
719 
SetBkColor(const Color & rColor)720 void WinMtfOutput::SetBkColor( const Color& rColor )
721 {
722     maBkColor = rColor;
723 }
724 
725 //-----------------------------------------------------------------------------------
726 
SetTextColor(const Color & rColor)727 void WinMtfOutput::SetTextColor( const Color& rColor )
728 {
729     maTextColor = rColor;
730 }
731 
732 //-----------------------------------------------------------------------------------
733 
SetTextAlign(sal_uInt32 nAlign)734 void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign )
735 {
736     mnTextAlign = nAlign;
737 }
738 
739 //-----------------------------------------------------------------------------------
740 
ImplResizeObjectArry(sal_uInt32 nNewEntrys)741 void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys )
742 {
743     sal_uInt32 i = vGDIObj.size();
744     vGDIObj.resize( nNewEntrys );
745     for ( ; i < nNewEntrys ; i++ )
746         vGDIObj[ i ] = NULL;
747 }
748 
749 //-----------------------------------------------------------------------------------
750 
ImplDrawClippedPolyPolygon(const PolyPolygon & rPolyPoly)751 void WinMtfOutput::ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly )
752 {
753     if ( rPolyPoly.Count() )
754     {
755         ImplSetNonPersistentLineColorTransparenz();
756         if ( rPolyPoly.Count() == 1 )
757         {
758             if ( rPolyPoly.IsRect() )
759                 mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) );
760             else
761             {
762                 Polygon aPoly( rPolyPoly[ 0 ] );
763                 sal_uInt16 nCount = aPoly.GetSize();
764                 if ( nCount )
765                 {
766                     if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] )
767                     {
768                         Point aPoint( aPoly[ 0 ] );
769                         aPoly.Insert( nCount, aPoint );
770                     }
771                     mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
772                 }
773             }
774         }
775         else
776             mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
777     }
778 }
779 
780 
781 //-----------------------------------------------------------------------------------
782 
CreateObject(GDIObjectType eType,void * pStyle)783 void WinMtfOutput::CreateObject( GDIObjectType eType, void* pStyle )
784 {
785     if ( pStyle )
786     {
787         if ( eType == GDI_FONT )
788         {
789             ImplMap( ((WinMtfFontStyle*)pStyle)->aFont );
790             if (!((WinMtfFontStyle*)pStyle)->aFont.GetHeight() )
791                 ((WinMtfFontStyle*)pStyle)->aFont.SetHeight( 423 );     // defaulting to 12pt
792         }
793         else if ( eType == GDI_PEN )
794         {
795             Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 );
796             ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() );
797             if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH )
798             {
799                 aSize.Width() += 1;
800                 long nDotLen = ImplMap( aSize ).Width();
801                 ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen );
802                 ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen );
803                 ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 );
804             }
805         }
806     }
807     sal_uInt32 nIndex;
808     for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ )
809     {
810         if ( vGDIObj[ nIndex ] == NULL )
811             break;
812     }
813     if ( nIndex == vGDIObj.size() )
814         ImplResizeObjectArry( vGDIObj.size() + 16 );
815 
816     vGDIObj[ nIndex ] = new GDIObj( eType, pStyle );
817 }
818 
819 //-----------------------------------------------------------------------------------
820 
CreateObject(sal_Int32 nIndex,GDIObjectType eType,void * pStyle)821 void WinMtfOutput::CreateObject( sal_Int32 nIndex, GDIObjectType eType, void* pStyle )
822 {
823     if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
824     {
825         nIndex &= 0xffff;       // zur Sicherheit: mehr als 65535 nicht zulassen
826         if ( pStyle )
827         {
828             if ( eType == GDI_FONT )
829                 ImplMap( ((WinMtfFontStyle*)pStyle)->aFont );
830             else if ( eType == GDI_PEN )
831             {
832                 Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 );
833                 ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() );
834                 if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH )
835                 {
836                     aSize.Width() += 1;
837                     long nDotLen = ImplMap( aSize ).Width();
838                     ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen );
839                     ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen );
840                     ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 );
841                 }
842             }
843         }
844         if ( (sal_uInt32)nIndex >= vGDIObj.size() )
845             ImplResizeObjectArry( nIndex + 16 );
846 
847         if ( vGDIObj[ nIndex ] != NULL )
848             delete vGDIObj[ nIndex ];
849 
850         vGDIObj[ nIndex ] = new GDIObj( eType, pStyle );
851     }
852     else
853     {
854         switch ( eType )
855         {
856             case GDI_PEN :
857                 delete (WinMtfLineStyle*)pStyle;
858             break;
859             case GDI_BRUSH :
860                 delete (WinMtfFillStyle*)pStyle;
861             break;
862             case GDI_FONT :
863                 delete (WinMtfFontStyle*)pStyle;
864             break;
865 
866             default:
867                 DBG_ERROR( "unsupported style not deleted" );
868                 break;
869         }
870     }
871 }
872 
873 //-----------------------------------------------------------------------------------
874 
DeleteObject(sal_Int32 nIndex)875 void WinMtfOutput::DeleteObject( sal_Int32 nIndex )
876 {
877     if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 )
878     {
879         if ( (sal_uInt32)nIndex < vGDIObj.size() )
880         {
881             delete vGDIObj[ nIndex ];
882             vGDIObj[ nIndex ] = NULL;
883         }
884     }
885 }
886 
887 //-----------------------------------------------------------------------------------
888 
IntersectClipRect(const Rectangle & rRect)889 void WinMtfOutput::IntersectClipRect( const Rectangle& rRect )
890 {
891     aClipPath.IntersectClipRect( ImplMap( rRect ) );
892 }
893 
894 //-----------------------------------------------------------------------------------
895 
ExcludeClipRect(const Rectangle & rRect)896 void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect )
897 {
898     aClipPath.ExcludeClipRect( ImplMap( rRect ) );
899 }
900 
901 //-----------------------------------------------------------------------------------
902 
MoveClipRegion(const Size & rSize)903 void WinMtfOutput::MoveClipRegion( const Size& rSize )
904 {
905     aClipPath.MoveClipRegion( ImplMap( rSize ) );
906 }
907 
SetClipPath(const PolyPolygon & rPolyPolygon,sal_Int32 nClippingMode,sal_Bool bIsMapped)908 void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped )
909 {
910     if ( bIsMapped )
911         aClipPath.SetClipPath( rPolyPolygon, nClippingMode );
912     else
913     {
914         PolyPolygon aPP( rPolyPolygon );
915         aClipPath.SetClipPath( ImplMap( aPP ), nClippingMode );
916     }
917 }
918 
919 //-----------------------------------------------------------------------------------
920 //-----------------------------------------------------------------------------------
921 //-----------------------------------------------------------------------------------
922 
WinMtfOutput(GDIMetaFile & rGDIMetaFile)923 WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) :
924     mnLatestTextAlign   ( 0 ),
925     mnTextAlign         ( TA_LEFT | TA_TOP | TA_NOUPDATECP ),
926     maLatestBkColor     ( 0x12345678 ),
927     maBkColor           ( COL_WHITE ),
928     mnLatestTextLayoutMode( TEXT_LAYOUT_DEFAULT ),
929     mnTextLayoutMode    ( TEXT_LAYOUT_DEFAULT ),
930     mnLatestBkMode      ( 0 ),
931     mnBkMode            ( OPAQUE ),
932     meLatestRasterOp    ( ROP_INVERT ),
933     meRasterOp          ( ROP_OVERPAINT ),
934     maActPos            ( Point() ),
935     mbNopMode           ( sal_False ),
936     mbFillStyleSelected ( sal_False ),
937     mnGfxMode           ( GM_COMPATIBLE ),
938     mnMapMode           ( MM_TEXT ),
939     mnDevOrgX           ( 0 ),
940     mnDevOrgY           ( 0 ),
941     mnDevWidth          ( 1 ),
942     mnDevHeight         ( 1 ),
943     mnWinOrgX           ( 0 ),
944     mnWinOrgY           ( 0 ),
945     mnWinExtX           ( 1 ),
946     mnWinExtY           ( 1 ),
947     mnPixX              ( 100 ),
948     mnPixY              ( 100 ),
949     mnMillX             ( 1 ),
950     mnMillY             ( 1 ),
951     mpGDIMetaFile       ( &rGDIMetaFile )
952 {
953     mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );      // The original clipregion has to be on top
954                                                                             // of the stack so it can always be restored
955                                                                             // this is necessary to be able to support
956                                                                             // SetClipRgn( NULL ) and similar ClipRgn actions (SJ)
957 
958     maFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Arial" )) );  // sj: #i57205#, we do have some scaling problems if using
959     maFont.SetCharSet( gsl_getSystemTextEncoding() );                       // the default font then most times a x11 font is used, we
960     maFont.SetHeight( 423 );                                                // will prevent this defining a font
961 
962     maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 );
963     maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 );
964 
965     mnRop = R2_BLACK + 1;
966     SetRasterOp( R2_BLACK );
967 };
968 
969 //-----------------------------------------------------------------------------------
970 
~WinMtfOutput()971 WinMtfOutput::~WinMtfOutput()
972 {
973     mpGDIMetaFile->AddAction( new MetaPopAction() );
974     mpGDIMetaFile->SetPrefMapMode( MAP_100TH_MM );
975     if ( mrclFrame.IsEmpty() )
976         mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) );
977     else
978         mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() );
979 
980     for ( sal_uInt32 i = 0; i < vGDIObj.size(); i++ )
981         delete vGDIObj[ i ];
982 };
983 
984 //-----------------------------------------------------------------------------------
985 
UpdateClipRegion()986 void WinMtfOutput::UpdateClipRegion()
987 {
988     if ( aClipPath.bNeedsUpdate )
989     {
990         aClipPath.bNeedsUpdate = sal_False;
991 
992         mpGDIMetaFile->AddAction( new MetaPopAction() );                    // taking the orignal clipregion
993         mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) );  //
994 
995         switch ( aClipPath.GetType() )
996         {
997             case RECTANGLE :
998             case COMPLEX :
999             {
1000 //              we will not generate a RegionClipRegion Action, because this action
1001 //              cannot be saved to the wmf format - saving to wmf always happens
1002 //              if the placeholder graphic for ole objects is generated. (SJ)
1003 
1004 //              Region aClipRegion( aClipPath.GetClipPath() );
1005 //              mpGDIMetaFile->AddAction( new MetaISectRegionClipRegionAction( aClipRegion ) );
1006 
1007                 Rectangle aClipRect( aClipPath.GetClipPath().GetBoundRect() );
1008                 mpGDIMetaFile->AddAction( new MetaISectRectClipRegionAction( aClipRect ) );
1009             }
1010             break;
1011             case EMPTY:
1012             break;  // -Wall not handled.
1013         }
1014     }
1015 }
1016 
1017 //-----------------------------------------------------------------------------------
1018 
ImplSetNonPersistentLineColorTransparenz()1019 void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz()
1020 {
1021     Color aColor(  COL_TRANSPARENT);
1022     WinMtfLineStyle aTransparentLine( aColor, sal_True );
1023     if ( ! ( maLatestLineStyle == aTransparentLine ) )
1024     {
1025         maLatestLineStyle = aTransparentLine;
1026         mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) );
1027     }
1028 }
1029 
1030 //-----------------------------------------------------------------------------------
1031 
UpdateLineStyle()1032 void WinMtfOutput::UpdateLineStyle()
1033 {
1034     if (!( maLatestLineStyle == maLineStyle ) )
1035     {
1036         maLatestLineStyle = maLineStyle;
1037         mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) );
1038     }
1039 }
1040 
1041 //-----------------------------------------------------------------------------------
1042 
UpdateFillStyle()1043 void WinMtfOutput::UpdateFillStyle()
1044 {
1045     if ( !mbFillStyleSelected )     // SJ: #i57205# taking care of bkcolor if no brush is selected
1046         maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == TRANSPARENT );
1047     if (!( maLatestFillStyle == maFillStyle ) )
1048     {
1049         maLatestFillStyle = maFillStyle;
1050         mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) );
1051     }
1052 }
1053 
1054 //-----------------------------------------------------------------------------------
1055 
SetRasterOp(sal_uInt32 nRasterOp)1056 sal_uInt32 WinMtfOutput::SetRasterOp( sal_uInt32 nRasterOp )
1057 {
1058     sal_uInt32 nRetROP = mnRop;
1059     if ( nRasterOp != mnRop )
1060     {
1061         mnRop = nRasterOp;
1062         static WinMtfFillStyle aNopFillStyle;
1063         static WinMtfLineStyle aNopLineStyle;
1064 
1065         if ( mbNopMode && ( nRasterOp != R2_NOP ) )
1066         {   // beim uebergang von R2_NOP auf anderen Modus
1067             // gesetzten Pen und Brush aktivieren
1068             maFillStyle = aNopFillStyle;
1069             maLineStyle = aNopLineStyle;
1070             mbNopMode = sal_False;
1071         }
1072         switch( nRasterOp )
1073         {
1074             case R2_NOT:
1075                 meRasterOp = ROP_INVERT;
1076             break;
1077 
1078             case R2_XORPEN:
1079                 meRasterOp = ROP_XOR;
1080             break;
1081 
1082             case R2_NOP:
1083             {
1084                 meRasterOp = ROP_OVERPAINT;
1085                 if( mbNopMode == sal_False )
1086                 {
1087                     aNopFillStyle = maFillStyle;
1088                     aNopLineStyle = maLineStyle;
1089                     maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True );
1090                     maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True );
1091                     mbNopMode = sal_True;
1092                 }
1093             }
1094             break;
1095 
1096             default:
1097                 meRasterOp = ROP_OVERPAINT;
1098             break;
1099         }
1100     }
1101     if ( nRetROP != nRasterOp )
1102         mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
1103     return nRetROP;
1104 };
1105 
1106 //-----------------------------------------------------------------------------------
1107 
StrokeAndFillPath(sal_Bool bStroke,sal_Bool bFill)1108 void WinMtfOutput::StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill )
1109 {
1110     if ( aPathObj.Count() )
1111     {
1112         UpdateClipRegion();
1113         UpdateLineStyle();
1114         UpdateFillStyle();
1115         if ( bFill )
1116         {
1117             if ( !bStroke )
1118             {
1119                 mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_LINECOLOR ) );
1120                 mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) );
1121             }
1122             if ( aPathObj.Count() == 1 )
1123                 mpGDIMetaFile->AddAction( new MetaPolygonAction( aPathObj.GetObject( 0 ) ) );
1124             else
1125                 mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) );
1126 
1127             if ( !bStroke )
1128                 mpGDIMetaFile->AddAction( new MetaPopAction() );
1129         }
1130         else
1131         {
1132             sal_uInt16 i, nCount = aPathObj.Count();
1133             for ( i = 0; i < nCount; i++ )
1134                 mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) );
1135         }
1136         ClearPath();
1137     }
1138 }
1139 
1140 //-----------------------------------------------------------------------------------
1141 
DrawPixel(const Point & rSource,const Color & rColor)1142 void WinMtfOutput::DrawPixel( const Point& rSource, const Color& rColor )
1143 {
1144     mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) );
1145 }
1146 
1147 //-----------------------------------------------------------------------------------
1148 
MoveTo(const Point & rPoint,sal_Bool bRecordPath)1149 void WinMtfOutput::MoveTo( const Point& rPoint, sal_Bool bRecordPath )
1150 {
1151     Point aDest( ImplMap( rPoint ) );
1152     if ( bRecordPath )
1153         aPathObj.AddPoint( aDest );
1154     maActPos = aDest;
1155 }
1156 
1157 //-----------------------------------------------------------------------------------
1158 
LineTo(const Point & rPoint,sal_Bool bRecordPath)1159 void WinMtfOutput::LineTo( const Point& rPoint, sal_Bool bRecordPath )
1160 {
1161     UpdateClipRegion();
1162 
1163     Point aDest( ImplMap( rPoint ) );
1164     if ( bRecordPath )
1165         aPathObj.AddPoint( aDest );
1166     else
1167     {
1168         UpdateLineStyle();
1169         mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) );
1170     }
1171     maActPos = aDest;
1172 }
1173 
1174 //-----------------------------------------------------------------------------------
1175 
DrawLine(const Point & rSource,const Point & rDest)1176 void WinMtfOutput::DrawLine( const Point& rSource, const Point& rDest )
1177 {
1178     UpdateClipRegion();
1179     UpdateLineStyle();
1180     mpGDIMetaFile->AddAction( new MetaLineAction( ImplMap( rSource), ImplMap( rDest ), maLineStyle.aLineInfo ) );
1181 }
1182 
1183 //-----------------------------------------------------------------------------------
1184 
DrawRect(const Rectangle & rRect,sal_Bool bEdge)1185 void WinMtfOutput::DrawRect( const Rectangle& rRect, sal_Bool bEdge )
1186 {
1187     UpdateClipRegion();
1188     UpdateFillStyle();
1189 
1190     if ( aClipPath.GetType() == COMPLEX )
1191     {
1192         Polygon aPoly( ImplMap( rRect ) );
1193         PolyPolygon aPolyPolyRect( aPoly );
1194         PolyPolygon aDest;
1195         aClipPath.GetClipPath().GetIntersection( aPolyPolyRect, aDest );
1196         ImplDrawClippedPolyPolygon( aDest );
1197     }
1198     else
1199     {
1200         if ( bEdge )
1201         {
1202             if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1203             {
1204                 ImplSetNonPersistentLineColorTransparenz();
1205                 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1206                 UpdateLineStyle();
1207                 mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) );
1208             }
1209             else
1210             {
1211                 UpdateLineStyle();
1212                 mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1213             }
1214         }
1215         else
1216         {
1217             ImplSetNonPersistentLineColorTransparenz();
1218             mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) );
1219         }
1220     }
1221 }
1222 
1223 //-----------------------------------------------------------------------------------
1224 
DrawRoundRect(const Rectangle & rRect,const Size & rSize)1225 void WinMtfOutput::DrawRoundRect( const Rectangle& rRect, const Size& rSize )
1226 {
1227     UpdateClipRegion();
1228     UpdateLineStyle();
1229     UpdateFillStyle();
1230     mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) );
1231 }
1232 
1233 //-----------------------------------------------------------------------------------
1234 
DrawEllipse(const Rectangle & rRect)1235 void WinMtfOutput::DrawEllipse( const Rectangle& rRect )
1236 {
1237     UpdateClipRegion();
1238     UpdateFillStyle();
1239 
1240     if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1241     {
1242         Point aCenter( ImplMap( rRect.Center() ) );
1243         Size  aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) );
1244 
1245         ImplSetNonPersistentLineColorTransparenz();
1246         mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1247         UpdateLineStyle();
1248         mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1249     }
1250     else
1251     {
1252         UpdateLineStyle();
1253         mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) );
1254     }
1255 }
1256 
1257 //-----------------------------------------------------------------------------------
1258 
DrawArc(const Rectangle & rRect,const Point & rStart,const Point & rEnd,sal_Bool bTo)1259 void WinMtfOutput::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, sal_Bool bTo )
1260 {
1261     UpdateClipRegion();
1262     UpdateLineStyle();
1263     UpdateFillStyle();
1264 
1265     Rectangle   aRect( ImplMap( rRect ) );
1266     Point       aStart( ImplMap( rStart ) );
1267     Point       aEnd( ImplMap( rEnd ) );
1268 
1269     if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1270     {
1271         if ( aStart == aEnd )
1272         {   // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse
1273             Point aCenter( aRect.Center() );
1274             Size  aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
1275 
1276             mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) );
1277         }
1278         else
1279             mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_ARC ), maLineStyle.aLineInfo ) );
1280     }
1281     else
1282         mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) );
1283 
1284     if ( bTo )
1285         maActPos = aEnd;
1286 }
1287 
1288 //-----------------------------------------------------------------------------------
1289 
DrawPie(const Rectangle & rRect,const Point & rStart,const Point & rEnd)1290 void WinMtfOutput::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1291 {
1292     UpdateClipRegion();
1293     UpdateFillStyle();
1294 
1295     Rectangle   aRect( ImplMap( rRect ) );
1296     Point       aStart( ImplMap( rStart ) );
1297     Point       aEnd( ImplMap( rEnd ) );
1298 
1299     if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1300     {
1301         ImplSetNonPersistentLineColorTransparenz();
1302         mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1303         UpdateLineStyle();
1304         mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_PIE ), maLineStyle.aLineInfo ) );
1305     }
1306     else
1307     {
1308         UpdateLineStyle();
1309         mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) );
1310     }
1311 }
1312 
1313 //-----------------------------------------------------------------------------------
1314 
DrawChord(const Rectangle & rRect,const Point & rStart,const Point & rEnd)1315 void WinMtfOutput::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rEnd )
1316 {
1317     UpdateClipRegion();
1318     UpdateFillStyle();
1319 
1320     Rectangle   aRect( ImplMap( rRect ) );
1321     Point       aStart( ImplMap( rStart ) );
1322     Point       aEnd( ImplMap( rEnd ) );
1323 
1324     if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1325     {
1326         ImplSetNonPersistentLineColorTransparenz();
1327         mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1328         UpdateLineStyle();
1329         mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_CHORD ), maLineStyle.aLineInfo ) );
1330     }
1331     else
1332     {
1333         UpdateLineStyle();
1334         mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) );
1335     }
1336 }
1337 
1338 //-----------------------------------------------------------------------------------
1339 
DrawPolygon(Polygon & rPolygon,sal_Bool bRecordPath)1340 void WinMtfOutput::DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath )
1341 {
1342     UpdateClipRegion();
1343     ImplMap( rPolygon );
1344     if ( bRecordPath )
1345         aPathObj.AddPolygon( rPolygon );
1346     else
1347     {
1348         UpdateFillStyle();
1349 
1350         if ( aClipPath.GetType() == COMPLEX )
1351         {
1352             PolyPolygon aPolyPoly( rPolygon );
1353             PolyPolygon aDest;
1354             aClipPath.GetClipPath().GetIntersection( aPolyPoly, aDest );
1355             ImplDrawClippedPolyPolygon( aDest );
1356         }
1357         else
1358         {
1359             if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) )
1360             {
1361                 sal_uInt16 nCount = rPolygon.GetSize();
1362                 if ( nCount )
1363                 {
1364                     if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] )
1365                     {
1366                         Point aPoint( rPolygon[ 0 ] );
1367                         rPolygon.Insert( nCount, aPoint );
1368                     }
1369                 }
1370                 ImplSetNonPersistentLineColorTransparenz();
1371                 mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1372                 UpdateLineStyle();
1373                 mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1374             }
1375             else
1376             {
1377                 UpdateLineStyle();
1378                 mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) );
1379             }
1380         }
1381     }
1382 }
1383 
1384 //-----------------------------------------------------------------------------------
1385 
DrawPolyPolygon(PolyPolygon & rPolyPolygon,sal_Bool bRecordPath)1386 void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath )
1387 {
1388     UpdateClipRegion();
1389 
1390     ImplMap( rPolyPolygon );
1391 
1392     if ( bRecordPath )
1393         aPathObj.AddPolyPolygon( rPolyPolygon );
1394     else
1395     {
1396         UpdateFillStyle();
1397 
1398         if ( aClipPath.GetType() == COMPLEX )
1399         {
1400             PolyPolygon aDest;
1401             aClipPath.GetClipPath().GetIntersection( rPolyPolygon, aDest );
1402             ImplDrawClippedPolyPolygon( aDest );
1403         }
1404         else
1405         {
1406             UpdateLineStyle();
1407             mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) );
1408         }
1409     }
1410 }
1411 
1412 //-----------------------------------------------------------------------------------
1413 
DrawPolyLine(Polygon & rPolygon,sal_Bool bTo,sal_Bool bRecordPath)1414 void WinMtfOutput::DrawPolyLine( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath )
1415 {
1416     UpdateClipRegion();
1417 
1418     ImplMap( rPolygon );
1419     if ( bTo )
1420     {
1421         rPolygon[ 0 ] = maActPos;
1422         maActPos = rPolygon[ rPolygon.GetSize() - 1 ];
1423     }
1424     if ( bRecordPath )
1425         aPathObj.AddPolyLine( rPolygon );
1426     else
1427     {
1428         UpdateLineStyle();
1429         mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1430     }
1431 }
1432 
1433 //-----------------------------------------------------------------------------------
1434 
DrawPolyBezier(Polygon & rPolygon,sal_Bool bTo,sal_Bool bRecordPath)1435 void WinMtfOutput::DrawPolyBezier( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath )
1436 {
1437     UpdateClipRegion();
1438 
1439     sal_uInt16 nPoints = rPolygon.GetSize();
1440     if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) )
1441     {
1442         ImplMap( rPolygon );
1443         if ( bTo )
1444         {
1445             rPolygon[ 0 ] = maActPos;
1446             maActPos = rPolygon[ nPoints - 1 ];
1447         }
1448         sal_uInt16 i;
1449         for ( i = 0; ( i + 2 ) < nPoints; )
1450         {
1451             rPolygon.SetFlags( i++, POLY_NORMAL );
1452             rPolygon.SetFlags( i++, POLY_CONTROL );
1453             rPolygon.SetFlags( i++, POLY_CONTROL );
1454         }
1455         if ( bRecordPath )
1456             aPathObj.AddPolyLine( rPolygon );
1457         else
1458         {
1459             UpdateLineStyle();
1460             mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) );
1461         }
1462     }
1463 }
1464 
1465 //-----------------------------------------------------------------------------------
1466 
DrawText(Point & rPosition,String & rText,sal_Int32 * pDXArry,sal_Bool bRecordPath,sal_Int32 nGfxMode)1467 void WinMtfOutput::DrawText( Point& rPosition, String& rText, sal_Int32* pDXArry, sal_Bool bRecordPath, sal_Int32 nGfxMode )
1468 {
1469     UpdateClipRegion();
1470     rPosition = ImplMap( rPosition );
1471     sal_Int32 nOldGfxMode = GetGfxMode();
1472     SetGfxMode( GM_COMPATIBLE );
1473 
1474     if ( pDXArry )
1475     {
1476         sal_Int32 i, nSum, nLen = rText.Len();
1477 
1478         for( i = 0, nSum = 0; i < nLen; i++ )
1479         {
1480             // #121382# Map DXArray using WorldTransform
1481             const Size aSize(ImplMap(Size( pDXArry[i], 0)));
1482             const basegfx::B2DVector aVector(aSize.Width(), aSize.Height());
1483             const sal_Int32 nTemp(basegfx::fround(aVector.getLength()));
1484             nSum += nTemp;
1485             pDXArry[ i ] = nSum;
1486         }
1487     }
1488     if ( mnLatestTextLayoutMode != mnTextLayoutMode )
1489     {
1490         mnLatestTextLayoutMode = mnTextLayoutMode;
1491         mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) );
1492     }
1493     SetGfxMode( nGfxMode );
1494     sal_Bool bChangeFont = sal_False;
1495     if ( mnLatestTextAlign != mnTextAlign )
1496     {
1497         bChangeFont = sal_True;
1498         mnLatestTextAlign = mnTextAlign;
1499         TextAlign eTextAlign;
1500         if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
1501             eTextAlign = ALIGN_BASELINE;
1502         else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
1503             eTextAlign = ALIGN_BOTTOM;
1504         else
1505             eTextAlign = ALIGN_TOP;
1506         mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) );
1507     }
1508     if ( maLatestTextColor != maTextColor )
1509     {
1510         bChangeFont = sal_True;
1511         maLatestTextColor = maTextColor;
1512         mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) );
1513     }
1514     sal_Bool bChangeFillColor = sal_False;
1515     if ( maLatestBkColor != maBkColor )
1516     {
1517         bChangeFillColor = sal_True;
1518         maLatestBkColor = maBkColor;
1519     }
1520     if ( mnLatestBkMode != mnBkMode )
1521     {
1522         bChangeFillColor = sal_True;
1523         mnLatestBkMode = mnBkMode;
1524     }
1525     if ( bChangeFillColor )
1526     {
1527         bChangeFont = sal_True;
1528         mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) );
1529     }
1530     Font aTmp( maFont );
1531     aTmp.SetColor( maTextColor );
1532     aTmp.SetFillColor( maBkColor );
1533 
1534     if( mnBkMode == TRANSPARENT )
1535         aTmp.SetTransparent( sal_True );
1536     else
1537         aTmp.SetTransparent( sal_False );
1538 
1539     if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE )
1540         aTmp.SetAlign( ALIGN_BASELINE );
1541     else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM )
1542         aTmp.SetAlign( ALIGN_BOTTOM );
1543     else
1544         aTmp.SetAlign( ALIGN_TOP );
1545 
1546     if ( nGfxMode == GM_ADVANCED )
1547     {
1548         // check whether there is a font rotation applied via transformation
1549         Point aP1( ImplMap( Point() ) );
1550         Point aP2( ImplMap( Point( 0, 100 ) ) );
1551         aP2.X() -= aP1.X();
1552         aP2.Y() -= aP1.Y();
1553         double fX = aP2.X();
1554         double fY = aP2.Y();
1555         if ( fX )
1556         {
1557             double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308;
1558             if ( fY > 0 )
1559                 fOrientation = 360 - fOrientation;
1560             fOrientation += 90;
1561             fOrientation *= 10;
1562             fOrientation += aTmp.GetOrientation();
1563             aTmp.SetOrientation( sal_Int16( fOrientation ) );
1564         }
1565     }
1566 
1567     if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) )
1568     {
1569         // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
1570         vos::OGuard aGuard( Application::GetSolarMutex() );
1571         VirtualDevice aVDev;
1572         sal_Int32 nTextWidth;
1573 
1574         aVDev.SetMapMode( MapMode( MAP_100TH_MM ) );
1575         aVDev.SetFont( maFont );
1576 
1577         if( pDXArry )
1578         {
1579             sal_uInt32 nLen = rText.Len();
1580             nTextWidth = aVDev.GetTextWidth( rText.GetChar( (sal_uInt16)( nLen - 1 ) ) );
1581             if( nLen > 1 )
1582                 nTextWidth += pDXArry[ nLen - 2 ];
1583         }
1584         else
1585             nTextWidth = aVDev.GetTextWidth( rText );
1586 
1587         if( mnTextAlign & TA_UPDATECP )
1588             rPosition = maActPos;
1589 
1590         if ( mnTextAlign & TA_RIGHT_CENTER )
1591         {
1592             double fLenght = ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1;
1593             rPosition.X() -= (sal_Int32)( fLenght * cos( maFont.GetOrientation() * F_PI1800 ) );
1594             rPosition.Y() -= (sal_Int32)(-( fLenght * sin( maFont.GetOrientation() * F_PI1800 ) ) );
1595         }
1596 
1597         if( mnTextAlign & TA_UPDATECP )
1598             maActPos.X() = rPosition.X() + nTextWidth;
1599     }
1600     if ( bChangeFont || ( maLatestFont != aTmp ) )
1601     {
1602         maLatestFont = aTmp;
1603         mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) );
1604         mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlign() ) );
1605         mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) );
1606         mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) );
1607     }
1608     if ( bRecordPath )
1609     {
1610         // ToDo
1611     }
1612     else
1613     {
1614         /* because text without dx array is badly scaled, we
1615            will create such an array if necessary */
1616         sal_Int32* pDX = pDXArry;
1617         if ( !pDXArry )
1618         {
1619             // #117968# VirtualDevice is not thread safe, but filter is used in multithreading
1620             vos::OGuard aGuard( Application::GetSolarMutex() );
1621             VirtualDevice aVDev;
1622 
1623             pDX = new sal_Int32[ rText.Len() ];
1624             aVDev.SetMapMode( MAP_100TH_MM );
1625             aVDev.SetFont( maLatestFont );
1626             aVDev.GetTextArray( rText, pDX, 0, STRING_LEN );
1627         }
1628         mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, STRING_LEN ) );
1629         if ( !pDXArry )     // this means we have created our own array
1630             delete[] pDX;   // which must be deleted
1631     }
1632     SetGfxMode( nOldGfxMode );
1633 }
1634 
1635 //-----------------------------------------------------------------------------------
1636 
ImplDrawBitmap(const Point & rPos,const Size & rSize,const BitmapEx rBitmap)1637 void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap )
1638 {
1639     BitmapEx aBmpEx( rBitmap );
1640     if ( aClipPath.GetType() == COMPLEX )
1641     {
1642         VirtualDevice aVDev;
1643         MapMode aMapMode( MAP_100TH_MM );
1644         aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) );
1645         const Size aOutputSizePixel( aVDev.LogicToPixel( rSize, aMapMode ) );
1646         const Size aSizePixel( rBitmap.GetSizePixel() );
1647         if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() )
1648         {
1649             aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) );
1650             aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) );
1651         }
1652         aVDev.SetMapMode( aMapMode );
1653         aVDev.SetOutputSizePixel( aSizePixel );
1654         aVDev.SetFillColor( Color( COL_BLACK ) );
1655         const PolyPolygon aClip( aClipPath.GetClipPath() );
1656         aVDev.DrawPolyPolygon( aClip );
1657         const Point aEmptyPoint;
1658 
1659         // #i50672# Extract whole VDev content (to match size of rBitmap)
1660         aVDev.EnableMapMode( sal_False );
1661         Bitmap aMask( aVDev.GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) );
1662 
1663         if ( aBmpEx.IsTransparent() )
1664         {
1665             if ( rBitmap.GetTransparentColor() == Color( COL_WHITE ) )
1666                 aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_OR );
1667             else
1668                 aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_AND );
1669             aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1670         }
1671         else
1672             aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask );
1673     }
1674     if ( aBmpEx.IsTransparent() )
1675         mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) );
1676     else
1677         mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) );
1678 }
1679 
1680 //-----------------------------------------------------------------------------------
1681 
ResolveBitmapActions(List & rSaveList)1682 void WinMtfOutput::ResolveBitmapActions( List& rSaveList )
1683 {
1684     UpdateClipRegion();
1685 
1686     sal_uInt32 nObjects     = rSaveList.Count();
1687     sal_uInt32 nObjectsLeft = nObjects;
1688 
1689     while ( nObjectsLeft )
1690     {
1691         sal_uInt32      i, nObjectsOfSameSize = 0;
1692         sal_uInt32      nObjectStartIndex = nObjects - nObjectsLeft;
1693 
1694         BSaveStruct*    pSave = (BSaveStruct*)rSaveList.GetObject( nObjectStartIndex );
1695         Rectangle       aRect( pSave->aOutRect );
1696 
1697         for ( i = nObjectStartIndex; i < nObjects; )
1698         {
1699             nObjectsOfSameSize++;
1700             if ( ++i < nObjects )
1701             {
1702                 pSave = (BSaveStruct*)rSaveList.GetObject( i );
1703                 if ( pSave->aOutRect != aRect )
1704                     break;
1705             }
1706         }
1707         Point   aPos( ImplMap( aRect.TopLeft() ) );
1708         Size    aSize( ImplMap( aRect.GetSize() ) );
1709 
1710         for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ )
1711         {
1712             pSave = (BSaveStruct*)rSaveList.GetObject( i );
1713 
1714             sal_uInt32  nWinRop = pSave->nWinRop;
1715             sal_uInt8   nRasterOperation = (sal_uInt8)( nWinRop >> 16 );
1716 
1717             sal_uInt32  nUsed =  0;
1718             if ( ( nRasterOperation & 0xf )  != ( nRasterOperation >> 4 ) )
1719                 nUsed |= 1;     // pattern is used
1720             if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) )
1721                 nUsed |= 2;     // source is used
1722             if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) )
1723                 nUsed |= 4;     // destination is used
1724 
1725             if ( (nUsed & 1) && (( nUsed & 2 ) == 0) )
1726             {   // patterns aren't well supported yet
1727                 sal_uInt32 nOldRop = SetRasterOp( ROP_OVERPAINT );  // in this case nRasterOperation is either 0 or 0xff
1728                 UpdateFillStyle();
1729                 DrawRect( aRect, sal_False );
1730                 SetRasterOp( nOldRop );
1731             }
1732             else
1733             {
1734                 sal_Bool bDrawn = sal_False;
1735 
1736                 if ( i == nObjectStartIndex )   // optimizing, sometimes it is possible to create just one transparent bitmap
1737                 {
1738                     if ( nObjectsOfSameSize == 2 )
1739                     {
1740                         BSaveStruct* pSave2 = (BSaveStruct*)rSaveList.GetObject( i + 1 );
1741                         if ( ( pSave->aBmp.GetPrefSize() == pSave2->aBmp.GetPrefSize() ) &&
1742                              ( pSave->aBmp.GetPrefMapMode() == pSave2->aBmp.GetPrefMapMode() ) )
1743                         {
1744                             // TODO: Strictly speaking, we should
1745                             // check whether mask is monochrome, and
1746                             // whether image is black (upper branch)
1747                             // or white (lower branch). Otherwise, the
1748                             // effect is not the same as a masked
1749                             // bitmap.
1750                             if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) )
1751                             {
1752                                 Bitmap aMask( pSave->aBmp ); aMask.Invert();
1753                                 BitmapEx aBmpEx( pSave2->aBmp, aMask );
1754                                 ImplDrawBitmap( aPos, aSize, aBmpEx );
1755                                 bDrawn = sal_True;
1756                                 i++;
1757                             }
1758                             // #i20085# This is just the other way
1759                             // around as above. Only difference: mask
1760                             // is inverted
1761                             else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) )
1762                             {
1763                                 Bitmap aMask( pSave->aBmp );
1764                                 BitmapEx aBmpEx( pSave2->aBmp, aMask );
1765                                 ImplDrawBitmap( aPos, aSize, aBmpEx );
1766                                 bDrawn = sal_True;
1767                                 i++;
1768                             }
1769                         }
1770                     }
1771                 }
1772 
1773                 if ( !bDrawn )
1774                 {
1775                     Push();
1776                     sal_uInt32  nOldRop = SetRasterOp( R2_COPYPEN );
1777                     Bitmap      aBitmap( pSave->aBmp );
1778                     sal_uInt32  nOperation = ( nRasterOperation & 0xf );
1779                     switch( nOperation )
1780                     {
1781                         case 0x1 :
1782                         case 0xe :
1783                         {
1784                             SetRasterOp( R2_XORPEN );
1785                             ImplDrawBitmap( aPos, aSize, aBitmap );
1786                             SetRasterOp( R2_COPYPEN );
1787                             Bitmap  aMask( aBitmap );
1788                             aMask.Invert();
1789                             BitmapEx aBmpEx( aBitmap, aMask );
1790                             ImplDrawBitmap( aPos, aSize, aBmpEx );
1791                             if ( nOperation == 0x1 )
1792                             {
1793                                 SetRasterOp( R2_NOT );
1794                                 DrawRect( aRect, sal_False );
1795                             }
1796                         }
1797                         break;
1798                         case 0x7 :
1799                         case 0x8 :
1800                         {
1801                             Bitmap  aMask( aBitmap );
1802                             if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 )     // pattern used
1803                             {
1804                                 aBitmap.Convert( BMP_CONVERSION_24BIT );
1805                                 aBitmap.Erase( maFillStyle.aFillColor );
1806                             }
1807                             BitmapEx aBmpEx( aBitmap, aMask );
1808                             ImplDrawBitmap( aPos, aSize, aBmpEx );
1809                             if ( nOperation == 0x7 )
1810                             {
1811                                 SetRasterOp( R2_NOT );
1812                                 DrawRect( aRect, sal_False );
1813                             }
1814                         }
1815                         break;
1816 
1817                         case 0x4 :
1818                         case 0xb :
1819                         {
1820                             SetRasterOp( R2_NOT );
1821                             DrawRect( aRect, sal_False );
1822                             SetRasterOp( R2_COPYPEN );
1823                             Bitmap  aMask( aBitmap );
1824                             aBitmap.Invert();
1825                             BitmapEx aBmpEx( aBitmap, aMask );
1826                             ImplDrawBitmap( aPos, aSize, aBmpEx );
1827                             SetRasterOp( R2_XORPEN );
1828                             ImplDrawBitmap( aPos, aSize, aBitmap );
1829                             if ( nOperation == 0xb )
1830                             {
1831                                 SetRasterOp( R2_NOT );
1832                                 DrawRect( aRect, sal_False );
1833                             }
1834                         }
1835                         break;
1836 
1837                         case 0x2 :
1838                         case 0xd :
1839                         {
1840                             Bitmap  aMask( aBitmap );
1841                             aMask.Invert();
1842                             BitmapEx aBmpEx( aBitmap, aMask );
1843                             ImplDrawBitmap( aPos, aSize, aBmpEx );
1844                             SetRasterOp( R2_XORPEN );
1845                             ImplDrawBitmap( aPos, aSize, aBitmap );
1846                             if ( nOperation == 0xd )
1847                             {
1848                                 SetRasterOp( R2_NOT );
1849                                 DrawRect( aRect, sal_False );
1850                             }
1851                         }
1852                         break;
1853                         case 0x6 :
1854                         case 0x9 :
1855                         {
1856                             SetRasterOp( R2_XORPEN );
1857                             ImplDrawBitmap( aPos, aSize, aBitmap );
1858                             if ( nOperation == 0x9 )
1859                             {
1860                                 SetRasterOp( R2_NOT );
1861                                 DrawRect( aRect, sal_False );
1862                             }
1863                         }
1864                         break;
1865 
1866                         case 0x0 :  // WHITENESS
1867                         case 0xf :  // BLACKNESS
1868                         {                                                   // in this case nRasterOperation is either 0 or 0xff
1869                             maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) );
1870                             UpdateFillStyle();
1871                             DrawRect( aRect, sal_False );
1872                         }
1873                         break;
1874 
1875                         case 0x3 :  // only source is used
1876                         case 0xc :
1877                         {
1878                             if ( nRasterOperation == 0x33 )
1879                                 aBitmap.Invert();
1880                             ImplDrawBitmap( aPos, aSize, aBitmap );
1881                         }
1882                         break;
1883 
1884                         case 0x5 :  // only destination is used
1885                         {
1886                             SetRasterOp( R2_NOT );
1887                             DrawRect( aRect, sal_False );
1888                         }
1889                         case 0xa :  // no operation
1890                         break;
1891                     }
1892                     SetRasterOp( nOldRop );
1893                     Pop();
1894                 }
1895             }
1896         }
1897         nObjectsLeft -= nObjectsOfSameSize;
1898     }
1899 
1900     void* pPtr;
1901     for ( pPtr = rSaveList.First(); pPtr; pPtr = rSaveList.Next() )
1902         delete (BSaveStruct*)pPtr;
1903     rSaveList.Clear();
1904 }
1905 
1906 //-----------------------------------------------------------------------------------
1907 
SetDevOrg(const Point & rPoint)1908 void WinMtfOutput::SetDevOrg( const Point& rPoint )
1909 {
1910     mnDevOrgX = rPoint.X();
1911     mnDevOrgY = rPoint.Y();
1912 }
1913 
1914 //-----------------------------------------------------------------------------------
1915 
SetDevOrgOffset(sal_Int32 nXAdd,sal_Int32 nYAdd)1916 void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1917 {
1918     mnDevOrgX += nXAdd;
1919     mnDevOrgY += nYAdd;
1920 }
1921 
1922 //-----------------------------------------------------------------------------------
1923 
SetDevExt(const Size & rSize)1924 void WinMtfOutput::SetDevExt( const Size& rSize )
1925 {
1926     if ( rSize.Width() && rSize.Height() )
1927     {
1928         switch( mnMapMode )
1929         {
1930             case MM_ISOTROPIC :
1931             case MM_ANISOTROPIC :
1932             {
1933                 mnDevWidth = rSize.Width();
1934                 mnDevHeight = rSize.Height();
1935             }
1936         }
1937     }
1938 }
1939 
1940 //-----------------------------------------------------------------------------------
1941 
ScaleDevExt(double fX,double fY)1942 void WinMtfOutput::ScaleDevExt( double fX, double fY )
1943 {
1944     mnDevWidth = FRound( mnDevWidth * fX );
1945     mnDevHeight = FRound( mnDevHeight * fY );
1946 }
1947 
1948 //-----------------------------------------------------------------------------------
1949 
SetWinOrg(const Point & rPoint)1950 void WinMtfOutput::SetWinOrg( const Point& rPoint )
1951 {
1952     mnWinOrgX = rPoint.X();
1953     mnWinOrgY = rPoint.Y();
1954 }
1955 
1956 //-----------------------------------------------------------------------------------
1957 
SetWinOrgOffset(sal_Int32 nXAdd,sal_Int32 nYAdd)1958 void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd )
1959 {
1960     mnWinOrgX += nXAdd;
1961     mnWinOrgY += nYAdd;
1962 }
1963 
1964 //-----------------------------------------------------------------------------------
1965 
SetWinExt(const Size & rSize)1966 void WinMtfOutput::SetWinExt( const Size& rSize )
1967 {
1968 
1969     if( rSize.Width() && rSize.Height() )
1970     {
1971         switch( mnMapMode )
1972         {
1973             case MM_ISOTROPIC :
1974             case MM_ANISOTROPIC :
1975             {
1976                 mnWinExtX = rSize.Width();
1977                 mnWinExtY = rSize.Height();
1978             }
1979         }
1980     }
1981 }
1982 
1983 //-----------------------------------------------------------------------------------
1984 
ScaleWinExt(double fX,double fY)1985 void WinMtfOutput::ScaleWinExt( double fX, double fY )
1986 {
1987     mnWinExtX = FRound( mnWinExtX * fX );
1988     mnWinExtY = FRound( mnWinExtY * fY );
1989 }
1990 
1991 //-----------------------------------------------------------------------------------
1992 
SetrclBounds(const Rectangle & rRect)1993 void WinMtfOutput::SetrclBounds( const Rectangle& rRect )
1994 {
1995     mrclBounds = rRect;
1996 }
1997 
1998 //-----------------------------------------------------------------------------------
1999 
SetrclFrame(const Rectangle & rRect)2000 void WinMtfOutput::SetrclFrame( const Rectangle& rRect )
2001 {
2002     mrclFrame = rRect;
2003 }
2004 
2005 //-----------------------------------------------------------------------------------
2006 
SetRefPix(const Size & rSize)2007 void WinMtfOutput::SetRefPix( const Size& rSize )
2008 {
2009     mnPixX = rSize.Width();
2010     mnPixY = rSize.Height();
2011 }
2012 
2013 //-----------------------------------------------------------------------------------
2014 
SetRefMill(const Size & rSize)2015 void WinMtfOutput::SetRefMill( const Size& rSize )
2016 {
2017     mnMillX = rSize.Width();
2018     mnMillY = rSize.Height();
2019 }
2020 
2021 //-----------------------------------------------------------------------------------
2022 
SetMapMode(sal_uInt32 nMapMode)2023 void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode )
2024 {
2025     mnMapMode = nMapMode;
2026     if ( nMapMode == MM_TEXT )
2027     {
2028         mnWinExtX = mnDevWidth;
2029         mnWinExtY = mnDevHeight;
2030     }
2031     else if ( mnMapMode == MM_HIMETRIC )
2032     {
2033         mnWinExtX = mnMillX * 100;
2034         mnWinExtY = mnMillY * 100;
2035     }
2036 }
2037 
2038 //-----------------------------------------------------------------------------------
2039 
SetWorldTransform(const XForm & rXForm)2040 void WinMtfOutput::SetWorldTransform( const XForm& rXForm )
2041 {
2042     maXForm.eM11 = rXForm.eM11;
2043     maXForm.eM12 = rXForm.eM12;
2044     maXForm.eM21 = rXForm.eM21;
2045     maXForm.eM22 = rXForm.eM22;
2046     maXForm.eDx = rXForm.eDx;
2047     maXForm.eDy = rXForm.eDy;
2048 }
2049 
2050 //-----------------------------------------------------------------------------------
2051 
ModifyWorldTransform(const XForm & rXForm,sal_uInt32 nMode)2052 void WinMtfOutput::ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode )
2053 {
2054     switch( nMode )
2055     {
2056         case MWT_IDENTITY :
2057         {
2058             maXForm.eM11 = maXForm.eM22 = 1.0f;
2059             maXForm.eM12 = maXForm.eM21 = maXForm.eDx = maXForm.eDy = 0.0f;
2060             break;
2061         }
2062 
2063         case MWT_RIGHTMULTIPLY :
2064         case MWT_LEFTMULTIPLY :
2065         {
2066             const XForm* pLeft;
2067             const XForm* pRight;
2068 
2069             if ( nMode == MWT_LEFTMULTIPLY )
2070             {
2071                 pLeft = &rXForm;
2072                 pRight = &maXForm;
2073             }
2074             else
2075             {
2076                 pLeft = &maXForm;
2077                 pRight = &rXForm;
2078             }
2079 
2080             float aF[3][3];
2081             float bF[3][3];
2082             float cF[3][3];
2083 
2084             aF[0][0] = pLeft->eM11;
2085             aF[0][1] = pLeft->eM12;
2086             aF[0][2] = 0;
2087             aF[1][0] = pLeft->eM21;
2088             aF[1][1] = pLeft->eM22;
2089             aF[1][2] = 0;
2090             aF[2][0] = pLeft->eDx;
2091             aF[2][1] = pLeft->eDy;
2092             aF[2][2] = 1;
2093 
2094             bF[0][0] = pRight->eM11;
2095             bF[0][1] = pRight->eM12;
2096             bF[0][2] = 0;
2097             bF[1][0] = pRight->eM21;
2098             bF[1][1] = pRight->eM22;
2099             bF[1][2] = 0;
2100             bF[2][0] = pRight->eDx;
2101             bF[2][1] = pRight->eDy;
2102             bF[2][2] = 1;
2103 
2104             int i, j, k;
2105             for ( i = 0; i < 3; i++ )
2106             {
2107               for ( j = 0; j < 3; j++ )
2108               {
2109                  cF[i][j] = 0;
2110                  for ( k = 0; k < 3; k++ )
2111                     cF[i][j] += aF[i][k] * bF[k][j];
2112               }
2113             }
2114             maXForm.eM11 = cF[0][0];
2115             maXForm.eM12 = cF[0][1];
2116             maXForm.eM21 = cF[1][0];
2117             maXForm.eM22 = cF[1][1];
2118             maXForm.eDx = cF[2][0];
2119             maXForm.eDy = cF[2][1];
2120             break;
2121         }
2122         case MWT_SET:
2123         {
2124             SetWorldTransform(rXForm);
2125             break;
2126         }
2127     }
2128  }
2129 
2130 //-----------------------------------------------------------------------------------
2131 
Push()2132 void WinMtfOutput::Push()                       // !! to be able to access the original ClipRegion it
2133 {                                               // is not allowed to use the MetaPushAction()
2134     UpdateClipRegion();                         // (the original clip region is on top of the stack) (SJ)
2135     SaveStructPtr pSave( new SaveStruct );
2136 
2137     pSave->aLineStyle = maLineStyle;
2138     pSave->aFillStyle = maFillStyle;
2139 
2140     pSave->aFont = maFont;
2141     pSave->aTextColor = maTextColor;
2142     pSave->nTextAlign = mnTextAlign;
2143     pSave->nTextLayoutMode = mnTextLayoutMode;
2144     pSave->nMapMode = mnMapMode;
2145     pSave->nGfxMode = mnGfxMode;
2146     pSave->nBkMode = mnBkMode;
2147     pSave->aBkColor = maBkColor;
2148     pSave->bFillStyleSelected = mbFillStyleSelected;
2149 
2150     pSave->aActPos = maActPos;
2151     pSave->aXForm = maXForm;
2152     pSave->eRasterOp = meRasterOp;
2153 
2154     pSave->nWinOrgX = mnWinOrgX;
2155     pSave->nWinOrgY = mnWinOrgY;
2156     pSave->nWinExtX = mnWinExtX;
2157     pSave->nWinExtY = mnWinExtY;
2158     pSave->nDevOrgX = mnDevOrgX;
2159     pSave->nDevOrgY = mnDevOrgY;
2160     pSave->nDevWidth = mnDevWidth;
2161     pSave->nDevHeight = mnDevHeight;
2162 
2163     pSave->aPathObj = aPathObj;
2164     pSave->aClipPath = aClipPath;
2165 
2166     vSaveStack.push_back( pSave );
2167 }
2168 
2169 //-----------------------------------------------------------------------------------
2170 
Pop()2171 void WinMtfOutput::Pop()
2172 {
2173     // Die aktuellen Daten vom Stack holen
2174     if( vSaveStack.size() )
2175     {
2176         // Die aktuelle Daten auf dem Stack sichern
2177         SaveStructPtr pSave( vSaveStack.back() );
2178 
2179         maLineStyle = pSave->aLineStyle;
2180         maFillStyle = pSave->aFillStyle;
2181 
2182         maFont = pSave->aFont;
2183         maTextColor = pSave->aTextColor;
2184         mnTextAlign = pSave->nTextAlign;
2185         mnTextLayoutMode = pSave->nTextLayoutMode;
2186         mnBkMode = pSave->nBkMode;
2187         mnGfxMode = pSave->nGfxMode;
2188         mnMapMode = pSave->nMapMode;
2189         maBkColor = pSave->aBkColor;
2190         mbFillStyleSelected = pSave->bFillStyleSelected;
2191 
2192         maActPos = pSave->aActPos;
2193         maXForm = pSave->aXForm;
2194         meRasterOp = pSave->eRasterOp;
2195 
2196         mnWinOrgX = pSave->nWinOrgX;
2197         mnWinOrgY = pSave->nWinOrgY;
2198         mnWinExtX = pSave->nWinExtX;
2199         mnWinExtY = pSave->nWinExtY;
2200         mnDevOrgX = pSave->nDevOrgX;
2201         mnDevOrgY = pSave->nDevOrgY;
2202         mnDevWidth = pSave->nDevWidth;
2203         mnDevHeight = pSave->nDevHeight;
2204 
2205         aPathObj = pSave->aPathObj;
2206         if ( ! ( aClipPath == pSave->aClipPath ) )
2207         {
2208             aClipPath = pSave->aClipPath;
2209             aClipPath.bNeedsUpdate = sal_True;
2210         }
2211         if ( meLatestRasterOp != meRasterOp )
2212             mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) );
2213         vSaveStack.pop_back();
2214     }
2215 }
2216 
AddFromGDIMetaFile(GDIMetaFile & rGDIMetaFile)2217 void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile )
2218 {
2219    rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF );
2220 }
2221