xref: /AOO41X/main/svtools/source/filter/wmf/emfwr.cxx (revision 47148b3bc50811ceb41802e4cc50a5db21535900) !
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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svtools.hxx"
24 
25 #include "emfwr.hxx"
26 #include <vcl/salbtype.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b2dpolypolygon.hxx>
29 #include <vcl/lineinfo.hxx>
30 #include <vcl/dibtools.hxx>
31 
32 // -----------
33 // - Defines -
34 // -----------
35 
36 #define WIN_EMR_HEADER                      1
37 #define WIN_EMR_POLYBEZIER                  2
38 #define WIN_EMR_POLYGON                     3
39 #define WIN_EMR_POLYLINE                    4
40 #define WIN_EMR_POLYBEZIERTO                5
41 #define WIN_EMR_POLYLINETO                  6
42 #define WIN_EMR_POLYPOLYLINE                7
43 #define WIN_EMR_POLYPOLYGON                 8
44 #define WIN_EMR_SETWINDOWEXTEX              9
45 #define WIN_EMR_SETWINDOWORGEX              10
46 #define WIN_EMR_SETVIEWPORTEXTEX            11
47 #define WIN_EMR_SETVIEWPORTORGEX            12
48 #define WIN_EMR_SETBRUSHORGEX               13
49 #define WIN_EMR_EOF                         14
50 #define WIN_EMR_SETPIXELV                   15
51 #define WIN_EMR_SETMAPPERFLAGS              16
52 #define WIN_EMR_SETMAPMODE                  17
53 #define WIN_EMR_SETBKMODE                   18
54 #define WIN_EMR_SETPOLYFILLMODE             19
55 #define WIN_EMR_SETROP2                     20
56 #define WIN_EMR_SETSTRETCHBLTMODE           21
57 #define WIN_EMR_SETTEXTALIGN                22
58 #define WIN_EMR_SETCOLORADJUSTMENT          23
59 #define WIN_EMR_SETTEXTCOLOR                24
60 #define WIN_EMR_SETBKCOLOR                  25
61 #define WIN_EMR_OFFSETCLIPRGN               26
62 #define WIN_EMR_MOVETOEX                    27
63 #define WIN_EMR_SETMETARGN                  28
64 #define WIN_EMR_EXCLUDECLIPRECT             29
65 #define WIN_EMR_INTERSECTCLIPRECT           30
66 #define WIN_EMR_SCALEVIEWPORTEXTEX          31
67 #define WIN_EMR_SCALEWINDOWEXTEX            32
68 #define WIN_EMR_SAVEDC                      33
69 #define WIN_EMR_RESTOREDC                   34
70 #define WIN_EMR_SETWORLDTRANSFORM           35
71 #define WIN_EMR_MODIFYWORLDTRANSFORM        36
72 #define WIN_EMR_SELECTOBJECT                37
73 #define WIN_EMR_CREATEPEN                   38
74 #define WIN_EMR_CREATEBRUSHINDIRECT         39
75 #define WIN_EMR_DELETEOBJECT                40
76 #define WIN_EMR_ANGLEARC                    41
77 #define WIN_EMR_ELLIPSE                     42
78 #define WIN_EMR_RECTANGLE                   43
79 #define WIN_EMR_ROUNDRECT                   44
80 #define WIN_EMR_ARC                         45
81 #define WIN_EMR_CHORD                       46
82 #define WIN_EMR_PIE                         47
83 #define WIN_EMR_SELECTPALETTE               48
84 #define WIN_EMR_CREATEPALETTE               49
85 #define WIN_EMR_SETPALETTEENTRIES           50
86 #define WIN_EMR_RESIZEPALETTE               51
87 #define WIN_EMR_REALIZEPALETTE              52
88 #define WIN_EMR_EXTFLOODFILL                53
89 #define WIN_EMR_LINETO                      54
90 #define WIN_EMR_ARCTO                       55
91 #define WIN_EMR_POLYDRAW                    56
92 #define WIN_EMR_SETARCDIRECTION             57
93 #define WIN_EMR_SETMITERLIMIT               58
94 #define WIN_EMR_BEGINPATH                   59
95 #define WIN_EMR_ENDPATH                     60
96 #define WIN_EMR_CLOSEFIGURE                 61
97 #define WIN_EMR_FILLPATH                    62
98 #define WIN_EMR_STROKEANDFILLPATH           63
99 #define WIN_EMR_STROKEPATH                  64
100 #define WIN_EMR_FLATTENPATH                 65
101 #define WIN_EMR_WIDENPATH                   66
102 #define WIN_EMR_SELECTCLIPPATH              67
103 #define WIN_EMR_ABORTPATH                   68
104 
105 #define WIN_EMR_GDICOMMENT                  70
106 #define WIN_EMR_FILLRGN                     71
107 #define WIN_EMR_FRAMERGN                    72
108 #define WIN_EMR_INVERTRGN                   73
109 #define WIN_EMR_PAINTRGN                    74
110 #define WIN_EMR_EXTSELECTCLIPRGN            75
111 #define WIN_EMR_BITBLT                      76
112 #define WIN_EMR_STRETCHBLT                  77
113 #define WIN_EMR_MASKBLT                     78
114 #define WIN_EMR_PLGBLT                      79
115 #define WIN_EMR_SETDIBITSTODEVICE           80
116 #define WIN_EMR_STRETCHDIBITS               81
117 #define WIN_EMR_EXTCREATEFONTINDIRECTW      82
118 #define WIN_EMR_EXTTEXTOUTA                 83
119 #define WIN_EMR_EXTTEXTOUTW                 84
120 #define WIN_EMR_POLYBEZIER16                85
121 #define WIN_EMR_POLYGON16                   86
122 #define WIN_EMR_POLYLINE16                  87
123 #define WIN_EMR_POLYBEZIERTO16              88
124 #define WIN_EMR_POLYLINETO16                89
125 #define WIN_EMR_POLYPOLYLINE16              90
126 #define WIN_EMR_POLYPOLYGON16               91
127 #define WIN_EMR_POLYDRAW16                  92
128 #define WIN_EMR_CREATEMONOBRUSH             93
129 #define WIN_EMR_CREATEDIBPATTERNBRUSHPT     94
130 #define WIN_EMR_EXTCREATEPEN                95
131 #define WIN_EMR_POLYTEXTOUTA                96
132 #define WIN_EMR_POLYTEXTOUTW                97
133 
134 #define WIN_SRCCOPY                         0x00CC0020L
135 #define WIN_SRCPAINT                        0x00EE0086L
136 #define WIN_SRCAND                          0x008800C6L
137 #define WIN_SRCINVERT                       0x00660046L
138 
139 #define HANDLE_INVALID                      0xffffffff
140 #define MAXHANDLES                          65000
141 
142 #define LINE_SELECT                         0x00000001
143 #define FILL_SELECT                         0x00000002
144 #define TEXT_SELECT                         0x00000004
145 
146 /* Text Alignment Options */
147 #define TA_NOUPDATECP                       0
148 #define TA_UPDATECP                         1
149 
150 #define TA_LEFT                             0
151 #define TA_RIGHT                            2
152 #define TA_CENTER                           6
153 
154 #define TA_TOP                              0
155 #define TA_BOTTOM                           8
156 #define TA_BASELINE                         24
157 #define TA_RTLREADING                       256
158 #define TA_MASK     (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING)
159 
160 #define MM_ANISOTROPIC                      8
161 
162 // -------------
163 // - EMFWriter -
164 // -------------
165 
WriteEMF(const GDIMetaFile & rMtf,SvStream & rOStm,FilterConfigItem * pFilterConfigItem)166 sal_Bool EMFWriter::WriteEMF( const GDIMetaFile& rMtf, SvStream& rOStm, FilterConfigItem* pFilterConfigItem )
167 {
168     const sal_uLong nHeaderPos = rOStm.Tell();
169 
170     mpHandlesUsed = new sal_Bool[ MAXHANDLES ];
171     memset( mpHandlesUsed, 0, MAXHANDLES * sizeof( sal_Bool ) );
172     mnHorTextAlign = mnHandleCount = mnLastPercent = mnRecordPos = mnRecordCount = 0;
173     mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID;
174     mbRecordOpen = sal_False;
175 
176     mpStm = &rOStm;
177     maVDev.EnableOutput( sal_False );
178     maVDev.SetMapMode( rMtf.GetPrefMapMode() );
179     mpFilterConfigItem = pFilterConfigItem;
180 
181     // don't work with pixel as destination map mode -> higher resolution preferrable
182     maDestMapMode.SetMapUnit( MAP_100TH_MM );
183 
184     const Size aMtfSizePix( maVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
185     const Size aMtfSizeLog( maVDev.LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_100TH_MM ) );
186 
187     // seek over header
188     // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits()
189     rOStm.SeekRel( 108 );
190 
191     // write initial values
192 
193     // set 100th mm map mode in EMF
194     ImplBeginRecord( WIN_EMR_SETMAPMODE );
195     (*mpStm) << (sal_Int32) MM_ANISOTROPIC;
196     ImplEndRecord();
197 
198     ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX );
199     (*mpStm) << (sal_Int32) maVDev.ImplGetDPIX() << (sal_Int32) maVDev.ImplGetDPIY();
200     ImplEndRecord();
201 
202     ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX );
203     (*mpStm) << (sal_Int32) 2540 << (sal_Int32) 2540;
204     ImplEndRecord();
205 
206     ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX );
207     (*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
208     ImplEndRecord();
209 
210     ImplBeginRecord( WIN_EMR_SETWINDOWORGEX );
211     (*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
212     ImplEndRecord();
213 
214     ImplWriteRasterOp( ROP_OVERPAINT );
215 
216     ImplBeginRecord( WIN_EMR_SETBKMODE );
217     (*mpStm) << (sal_uInt32) 1; // TRANSPARENT
218     ImplEndRecord();
219 
220     // write emf data
221     ImplWrite( rMtf );
222 
223     ImplBeginRecord( WIN_EMR_EOF );
224     (*mpStm)<< (sal_uInt32)0        // nPalEntries
225             << (sal_uInt32)0x10     // offPalEntries
226             << (sal_uInt32)0x14;    // nSizeLast
227     ImplEndRecord();
228 
229 
230     // write header
231     const sal_uLong nEndPos = mpStm->Tell(); mpStm->Seek( nHeaderPos );
232 
233     (*mpStm) << (sal_uInt32) 0x00000001 << (sal_uInt32) 108 //use [MS-EMF 2.2.11] HeaderExtension2 Object
234              << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizePix.Width() - 1 ) << (sal_Int32) ( aMtfSizePix.Height() - 1 )
235              << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizeLog.Width() - 1 ) << (sal_Int32) ( aMtfSizeLog.Height() - 1 )
236              << (sal_uInt32) 0x464d4520 << (sal_uInt32) 0x10000 << (sal_uInt32) ( nEndPos - nHeaderPos )
237              << (sal_uInt32) mnRecordCount << (sal_uInt16) ( mnHandleCount + 1 ) << (sal_uInt16) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0
238              << (sal_Int32) aMtfSizePix.Width() << (sal_Int32) aMtfSizePix.Height()
239              << (sal_Int32) ( aMtfSizeLog.Width() / 100 ) << (sal_Int32) ( aMtfSizeLog.Height() / 100 )
240              << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0
241              << (sal_Int32) (  aMtfSizeLog.Width() * 10 ) << (sal_Int32) ( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object
242 
243     mpStm->Seek( nEndPos );
244     delete[] mpHandlesUsed;
245 
246     return( mpStm->GetError() == ERRCODE_NONE );
247 }
248 
249 // -----------------------------------------------------------------------------
250 
ImplAcquireHandle()251 sal_uLong EMFWriter::ImplAcquireHandle()
252 {
253     sal_uLong nHandle = HANDLE_INVALID;
254 
255     for( sal_uLong i = 0; i < MAXHANDLES && ( HANDLE_INVALID == nHandle ); i++ )
256     {
257         if( !mpHandlesUsed[ i ] )
258         {
259             mpHandlesUsed[ i ] = sal_True;
260 
261             if( ( nHandle = i ) == mnHandleCount )
262                 mnHandleCount++;
263         }
264     }
265 
266     DBG_ASSERT( nHandle != HANDLE_INVALID, "No more handles available" );
267     return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID );
268 }
269 
270 // -----------------------------------------------------------------------------
271 
ImplReleaseHandle(sal_uLong nHandle)272 void EMFWriter::ImplReleaseHandle( sal_uLong nHandle )
273 {
274     DBG_ASSERT( nHandle && ( nHandle < MAXHANDLES ), "Handle out of range" );
275     mpHandlesUsed[ nHandle - 1 ] = sal_False;
276 }
277 
278 // -----------------------------------------------------------------------------
279 
ImplBeginRecord(sal_uInt32 nType)280 void EMFWriter::ImplBeginRecord( sal_uInt32 nType )
281 {
282     DBG_ASSERT( !mbRecordOpen, "Another record is already opened!" );
283 
284     if( !mbRecordOpen )
285     {
286         mbRecordOpen = sal_True;
287         mnRecordPos = mpStm->Tell();
288 
289         (*mpStm) << nType;
290         mpStm->SeekRel( 4 );
291     }
292 }
293 
294 // -----------------------------------------------------------------------------
295 
ImplEndRecord()296 void EMFWriter::ImplEndRecord()
297 {
298     DBG_ASSERT( mbRecordOpen, "Record was not opened!" );
299 
300     if( mbRecordOpen )
301     {
302         sal_Int32 nFillBytes, nActPos = mpStm->Tell();
303         mpStm->Seek( mnRecordPos + 4 );
304         nFillBytes = nActPos - mnRecordPos;
305         nFillBytes += 3;    // each record has to be dword aligned
306         nFillBytes ^= 3;
307         nFillBytes &= 3;
308         *mpStm << (sal_uInt32)( ( nActPos - mnRecordPos ) + nFillBytes );
309         mpStm->Seek( nActPos );
310         while( nFillBytes-- )
311             *mpStm << (sal_uInt8)0;
312         mnRecordCount++;
313         mbRecordOpen = sal_False;
314     }
315 }
316 
317 // -----------------------------------------------------------------------------
318 
ImplPrepareHandleSelect(sal_uInt32 & rHandle,sal_uLong nSelectType)319 sal_Bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType )
320 {
321     if( rHandle != HANDLE_INVALID )
322     {
323         sal_uInt32 nStockObject = 0x80000000;
324 
325         if( LINE_SELECT == nSelectType )
326             nStockObject |= 0x00000007;
327         else if( FILL_SELECT == nSelectType )
328             nStockObject |= 0x00000001;
329         else if( TEXT_SELECT == nSelectType )
330             nStockObject |= 0x0000000a;
331 
332         // select stock object first
333         ImplBeginRecord( WIN_EMR_SELECTOBJECT );
334         ( *mpStm ) << nStockObject;
335         ImplEndRecord();
336 
337         // destroy handle of created object
338         ImplBeginRecord( WIN_EMR_DELETEOBJECT );
339         ( *mpStm ) << rHandle;
340         ImplEndRecord();
341 
342         // mark handle as free
343         ImplReleaseHandle( rHandle );
344     }
345 
346     rHandle = ImplAcquireHandle();
347 
348     return( HANDLE_INVALID != rHandle );
349 }
350 
351 // -----------------------------------------------------------------------------
352 
ImplCheckLineAttr()353 void EMFWriter::ImplCheckLineAttr()
354 {
355     if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) )
356     {
357         sal_uInt32 nStyle = maVDev.IsLineColor() ? 0 : 5;
358         sal_uInt32 nWidth = 0, nHeight = 0;
359 
360         ImplBeginRecord( WIN_EMR_CREATEPEN );
361         (*mpStm) << mnLineHandle << nStyle << nWidth << nHeight;
362         ImplWriteColor( maVDev.GetLineColor() );
363         ImplEndRecord();
364 
365         ImplBeginRecord( WIN_EMR_SELECTOBJECT );
366         (*mpStm) << mnLineHandle;
367         ImplEndRecord();
368     }
369 }
370 
371 // -----------------------------------------------------------------------------
372 
ImplCheckFillAttr()373 void EMFWriter::ImplCheckFillAttr()
374 {
375     if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) )
376     {
377         sal_uInt32 nStyle = maVDev.IsFillColor() ? 0 : 1;
378         sal_uInt32 nPatternStyle = 0;
379 
380         ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT );
381         (*mpStm) << mnFillHandle << nStyle;
382         ImplWriteColor( maVDev.GetFillColor() );
383         (*mpStm) << nPatternStyle;
384         ImplEndRecord();
385 
386         ImplBeginRecord( WIN_EMR_SELECTOBJECT );
387         (*mpStm) << mnFillHandle;
388         ImplEndRecord();
389     }
390 }
391 
392 // -----------------------------------------------------------------------------
393 
ImplCheckTextAttr()394 void EMFWriter::ImplCheckTextAttr()
395 {
396     if( mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT ) )
397     {
398         const Font&     rFont = maVDev.GetFont();
399         String          aFontName( rFont.GetName() );
400         sal_Int32       nWeight;
401         sal_uInt16      i;
402         sal_uInt8       nPitchAndFamily;
403 
404         ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW );
405         (*mpStm) << mnTextHandle;
406         ImplWriteExtent( -rFont.GetSize().Height() );
407         ImplWriteExtent( rFont.GetSize().Width() );
408         (*mpStm) << (sal_Int32) rFont.GetOrientation() << (sal_Int32) rFont.GetOrientation();
409 
410         switch( rFont.GetWeight() )
411         {
412             case WEIGHT_THIN:       nWeight = 100; break;
413             case WEIGHT_ULTRALIGHT: nWeight = 200; break;
414             case WEIGHT_LIGHT:      nWeight = 300; break;
415             case WEIGHT_SEMILIGHT:  nWeight = 300; break;
416             case WEIGHT_NORMAL:     nWeight = 400; break;
417             case WEIGHT_MEDIUM:     nWeight = 500; break;
418             case WEIGHT_SEMIBOLD:   nWeight = 600; break;
419             case WEIGHT_BOLD:       nWeight = 700; break;
420             case WEIGHT_ULTRABOLD:  nWeight = 800; break;
421             case WEIGHT_BLACK:      nWeight = 900; break;
422             default:                nWeight = 0; break;
423         }
424 
425         (*mpStm) << nWeight;
426         (*mpStm) << (sal_uInt8) ( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 );
427         (*mpStm) << (sal_uInt8) ( ( UNDERLINE_NONE == rFont.GetUnderline() ) ? 0 : 1 );
428         (*mpStm) << (sal_uInt8) ( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 );
429         (*mpStm) << (sal_uInt8) ( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 );
430         (*mpStm) << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0;
431 
432         switch( rFont.GetPitch() )
433         {
434             case PITCH_FIXED:    nPitchAndFamily = 0x01; break;
435             case PITCH_VARIABLE: nPitchAndFamily = 0x02; break;
436             default:             nPitchAndFamily = 0x00; break;
437         }
438 
439         switch( rFont.GetFamily() )
440         {
441             case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break;
442             case FAMILY_MODERN:     nPitchAndFamily |= 0x30; break;
443             case FAMILY_ROMAN:      nPitchAndFamily |= 0x10; break;
444             case FAMILY_SCRIPT:     nPitchAndFamily |= 0x40; break;
445             case FAMILY_SWISS:      nPitchAndFamily |= 0x20; break;
446             default: break;
447         }
448 
449         (*mpStm) << nPitchAndFamily;
450 
451         for( i = 0; i < 32; i++ )
452             (*mpStm) << (sal_Unicode) ( ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0 );
453 
454         // dummy elfFullName
455         for( i = 0; i < 64; i++ )
456             (*mpStm) << (sal_Unicode) 0;
457 
458         // dummy elfStyle
459         for( i = 0; i < 32; i++ )
460             (*mpStm) << (sal_Unicode) 0;
461 
462         // dummy elfVersion, elfStyleSize, elfMatch, elfReserved
463         (*mpStm) << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 ;
464 
465         // dummy elfVendorId
466         (*mpStm) << (sal_uInt32) 0;
467 
468         // dummy elfCulture
469         (*mpStm) << (sal_uInt32) 0;
470 
471         // dummy elfPanose
472         (*mpStm) << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0;
473 
474         // fill record to get a record size divideable by 4
475         (*mpStm) << (sal_uInt16) 0;
476 
477         ImplEndRecord();
478 
479         // TextAlign
480         sal_uInt32 nTextAlign;
481 
482         switch( rFont.GetAlign() )
483         {
484             case ALIGN_TOP:    nTextAlign = TA_TOP; break;
485             case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break;
486             default:           nTextAlign = TA_BASELINE; break;
487         }
488         nTextAlign |= mnHorTextAlign;
489 
490         ImplBeginRecord( WIN_EMR_SETTEXTALIGN );
491         (*mpStm) << nTextAlign;
492         ImplEndRecord();
493 
494         // Text color
495         ImplBeginRecord( WIN_EMR_SETTEXTCOLOR );
496         ImplWriteColor( maVDev.GetTextColor() );
497         ImplEndRecord();
498 
499         ImplBeginRecord( WIN_EMR_SELECTOBJECT );
500         (*mpStm) << mnTextHandle;
501         ImplEndRecord();
502     }
503 }
504 
505 // -----------------------------------------------------------------------------
506 
ImplWriteColor(const Color & rColor)507 void EMFWriter::ImplWriteColor( const Color& rColor )
508 {
509     sal_uInt32 nCol = rColor.GetRed();
510 
511     nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8;
512     nCol |= ( (sal_uInt32) rColor.GetBlue() ) << 16;
513 
514     (*mpStm) << nCol;
515 }
516 
517 // -----------------------------------------------------------------------------
518 
ImplWriteRasterOp(RasterOp eRop)519 void EMFWriter::ImplWriteRasterOp( RasterOp eRop )
520 {
521     sal_uInt32 nROP2;
522 
523     switch( eRop )
524     {
525         case ROP_INVERT: nROP2 = 6; break;
526         case ROP_XOR:    nROP2 = 7; break;
527         default:         nROP2 = 13;break;
528     }
529 
530     ImplBeginRecord( WIN_EMR_SETROP2 );
531     (*mpStm) << nROP2;
532     ImplEndRecord();
533 }
534 
535 // -----------------------------------------------------------------------------
536 
ImplWriteExtent(long nExtent)537 void EMFWriter::ImplWriteExtent( long nExtent )
538 {
539     nExtent = maVDev.LogicToLogic( Size( nExtent, 0 ), maVDev.GetMapMode(), maDestMapMode ).Width();
540     (*mpStm) << (sal_Int32) nExtent;
541 }
542 
543 // -----------------------------------------------------------------------------
544 
ImplWritePoint(const Point & rPoint)545 void EMFWriter::ImplWritePoint( const Point& rPoint )
546 {
547     const Point aPoint( maVDev.LogicToLogic( rPoint, maVDev.GetMapMode(), maDestMapMode ));
548     (*mpStm) << (sal_Int32) aPoint.X() << (sal_Int32) aPoint.Y();
549 }
550 
551 // -----------------------------------------------------------------------------
552 
ImplWriteSize(const Size & rSize)553 void EMFWriter::ImplWriteSize( const Size& rSize)
554 {
555     const Size aSize( maVDev.LogicToLogic( rSize, maVDev.GetMapMode(), maDestMapMode ));
556     (*mpStm) << (sal_Int32) aSize.Width() << (sal_Int32) aSize.Height();
557 }
558 
559 // -----------------------------------------------------------------------------
560 
ImplWriteRect(const Rectangle & rRect)561 void EMFWriter::ImplWriteRect( const Rectangle& rRect )
562 {
563     const Rectangle aRect( maVDev.LogicToLogic ( rRect, maVDev.GetMapMode(), maDestMapMode ));
564     (*mpStm) << aRect.Left() << aRect.Top() << aRect.Right() << aRect.Bottom();
565 }
566 
567 // -----------------------------------------------------------------------------
568 
ImplWritePolygonRecord(const Polygon & rPoly,sal_Bool bClose)569 void EMFWriter::ImplWritePolygonRecord( const Polygon& rPoly, sal_Bool bClose )
570 {
571     if( rPoly.GetSize() )
572     {
573         if( rPoly.HasFlags() )
574             ImplWritePath( rPoly, bClose );
575         else
576         {
577             if( bClose )
578                 ImplCheckFillAttr();
579 
580             ImplCheckLineAttr();
581 
582             ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE );
583             ImplWriteRect( rPoly.GetBoundRect() );
584             (*mpStm) << (sal_uInt32) rPoly.GetSize();
585 
586             for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ )
587                 ImplWritePoint( rPoly[ i ] );
588 
589             ImplEndRecord();
590         }
591     }
592 }
593 
594 // -----------------------------------------------------------------------------
595 
ImplWritePolyPolygonRecord(const PolyPolygon & rPolyPoly)596 void EMFWriter::ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly )
597 {
598     sal_uInt16 n, i, nPolyCount = rPolyPoly.Count();
599 
600     if( nPolyCount )
601     {
602         if( 1 == nPolyCount )
603             ImplWritePolygonRecord( rPolyPoly[ 0 ], sal_True );
604         else
605         {
606             sal_Bool    bHasFlags = sal_False;
607             sal_uInt32  nTotalPoints = 0;
608 
609             for( i = 0; i < nPolyCount; i++ )
610             {
611                 nTotalPoints += rPolyPoly[ i ].GetSize();
612                 if ( rPolyPoly[ i ].HasFlags() )
613                     bHasFlags = sal_True;
614             }
615             if( nTotalPoints )
616             {
617                 if ( bHasFlags )
618                     ImplWritePath( rPolyPoly, sal_True );
619                 else
620                 {
621                     ImplCheckFillAttr();
622                     ImplCheckLineAttr();
623 
624                     ImplBeginRecord( WIN_EMR_POLYPOLYGON );
625                     ImplWriteRect( rPolyPoly.GetBoundRect() );
626                     (*mpStm) << (sal_uInt32)nPolyCount << nTotalPoints;
627 
628                     for( i = 0; i < nPolyCount; i++ )
629                         (*mpStm) << (sal_uInt32)rPolyPoly[ i ].GetSize();
630 
631                     for( i = 0; i < nPolyCount; i++ )
632                     {
633                         const Polygon& rPoly = rPolyPoly[ i ];
634 
635                         for( n = 0; n < rPoly.GetSize(); n++ )
636                             ImplWritePoint( rPoly[ n ] );
637                     }
638                     ImplEndRecord();
639                 }
640             }
641         }
642     }
643 }
644 
645 // -----------------------------------------------------------------------------
646 
ImplWritePath(const PolyPolygon & rPolyPoly,sal_Bool bClosed)647 void EMFWriter::ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClosed )
648 {
649     if ( bClosed )
650         ImplCheckFillAttr();
651     ImplCheckLineAttr();
652 
653     ImplBeginRecord( WIN_EMR_BEGINPATH );
654     ImplEndRecord();
655 
656     sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count();
657     for ( i = 0; i < nPolyCount; i++ )
658     {
659         n = 0;
660         const Polygon& rPoly = rPolyPoly[ i ];
661         while ( n < rPoly.GetSize() )
662         {
663             if( n == 0 )
664             {
665                 ImplBeginRecord( WIN_EMR_MOVETOEX );
666                 ImplWritePoint( rPoly[ 0 ] );
667                 ImplEndRecord();
668                 n++;
669                 continue;
670             }
671 
672             sal_uInt16 nBezPoints = 0;
673 
674             while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == POLY_CONTROL ) )
675                 nBezPoints += 3;
676 
677             if ( nBezPoints )
678             {
679                 ImplBeginRecord( WIN_EMR_POLYBEZIERTO );
680                 Polygon aNewPoly( nBezPoints + 1 );
681                 aNewPoly[ 0 ] = rPoly[ n - 1 ];
682                 for ( o = 0; o < nBezPoints; o++ )
683                     aNewPoly[ o + 1 ] = rPoly[ n + o ];
684                 ImplWriteRect( aNewPoly.GetBoundRect() );
685                 (*mpStm) << (sal_uInt32)nBezPoints;
686                 for( o = 1; o < aNewPoly.GetSize(); o++ )
687                     ImplWritePoint( aNewPoly[ o ] );
688                 ImplEndRecord();
689                 n = n + nBezPoints;
690             }
691             else
692             {
693                 sal_uInt16 nPoints = 1;
694                 while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != POLY_CONTROL ) )
695                     nPoints++;
696 
697                 if ( nPoints > 1 )
698                 {
699                     ImplBeginRecord( WIN_EMR_POLYLINETO );
700                     Polygon aNewPoly( nPoints + 1 );
701                     aNewPoly[ 0 ] = rPoly[ n - 1];
702                     for ( o = 1; o <= nPoints; o++ )
703                         aNewPoly[ o ] = rPoly[ n - 1 + o ];
704                     ImplWriteRect( aNewPoly.GetBoundRect() );
705                     (*mpStm) << (sal_uInt32)( nPoints );
706                     for( o = 1; o < aNewPoly.GetSize(); o++ )
707                         ImplWritePoint( aNewPoly[ o ] );
708                     ImplEndRecord();
709                 }
710                 else
711                 {
712                     ImplBeginRecord( WIN_EMR_LINETO );
713                     ImplWritePoint( rPoly[ n ] );
714                     ImplEndRecord();
715                 }
716                 n = n + nPoints;
717             }
718             if ( bClosed && ( n == rPoly.GetSize() ) )
719             {
720                 ImplBeginRecord( WIN_EMR_CLOSEFIGURE );
721                 ImplEndRecord();
722             }
723         }
724     }
725     ImplBeginRecord( WIN_EMR_ENDPATH );
726     ImplEndRecord();
727     ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH );
728     ImplWriteRect( rPolyPoly.GetBoundRect() );
729     ImplEndRecord();
730 }
731 
732 // -----------------------------------------------------------------------------
733 
ImplWriteBmpRecord(const Bitmap & rBmp,const Point & rPt,const Size & rSz,sal_uInt32 nROP)734 void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt,
735                                     const Size& rSz, sal_uInt32 nROP )
736 {
737     if( !!rBmp )
738     {
739         SvMemoryStream  aMemStm( 65535, 65535 );
740         const Size      aBmpSizePixel( rBmp.GetSizePixel() );
741 
742         ImplBeginRecord( WIN_EMR_STRETCHDIBITS );
743         ImplWriteRect( Rectangle( rPt, rSz ) );
744         ImplWritePoint( rPt );
745         (*mpStm) << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) aBmpSizePixel.Width() << (sal_Int32) aBmpSizePixel.Height();
746 
747         // write offset positions and sizes later
748         const sal_uLong nOffPos = mpStm->Tell();
749         mpStm->SeekRel( 16 );
750 
751         (*mpStm) << (sal_uInt32) 0 << ( ( ROP_XOR == maVDev.GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP );
752         ImplWriteSize( rSz );
753 
754         WriteDIB(rBmp, aMemStm, true, false);
755 
756         sal_uInt32  nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize;
757         sal_uInt16  nBitCount;
758 
759         // get DIB parameters
760         aMemStm.Seek( 0 );
761         aMemStm >> nHeaderSize;
762         aMemStm.SeekRel( 10 );
763         aMemStm >> nBitCount >> nCompression >> nImageSize;
764         aMemStm.SeekRel( 8 );
765         aMemStm >> nColsUsed;
766 
767         nPalCount = ( nBitCount <= 8 ) ? ( nColsUsed ? nColsUsed : ( 1 << (sal_uInt32) nBitCount ) ) :
768                                          ( ( 3 == nCompression ) ? 12 : 0 );
769 
770         mpStm->Write( aMemStm.GetData(), nDIBSize );
771 
772         const sal_uLong nEndPos = mpStm->Tell();
773         mpStm->Seek( nOffPos );
774         (*mpStm) << (sal_uInt32) 80 << (sal_uInt32)( nHeaderSize + ( nPalCount << 2 ) );
775         (*mpStm) << (sal_uInt32)( 80 + ( nHeaderSize + ( nPalCount << 2 ) ) ) << nImageSize;
776         mpStm->Seek( nEndPos );
777 
778         ImplEndRecord();
779     }
780 }
781 
782 // -----------------------------------------------------------------------------
783 
ImplWriteTextRecord(const Point & rPos,const String rText,const sal_Int32 * pDXArray,sal_uInt32 nWidth)784 void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth )
785 {
786     xub_StrLen nLen = rText.Len(), i;
787 
788     if( nLen )
789     {
790         sal_uInt32  nNormWidth;
791         sal_Int32*  pOwnArray;
792         sal_Int32*  pDX;
793 
794         // get text sizes
795         if( pDXArray )
796         {
797             pOwnArray = NULL;
798             nNormWidth = maVDev.GetTextWidth( rText );
799             pDX = (sal_Int32*) pDXArray;
800         }
801         else
802         {
803             pOwnArray = new sal_Int32[ nLen ];
804             nNormWidth = maVDev.GetTextArray( rText, pOwnArray );
805             pDX = pOwnArray;
806         }
807 
808         if( nLen > 1 )
809         {
810             nNormWidth = pDX[ nLen - 2 ] + maVDev.GetTextWidth( rText.GetChar( nLen - 1 ) );
811 
812             if( nWidth && nNormWidth && ( nWidth != nNormWidth ) )
813             {
814                 const double fFactor = (double) nWidth / nNormWidth;
815 
816                 for( i = 0; i < ( nLen - 1 ); i++ )
817                     pDX[ i ] = FRound( pDX[ i ] * fFactor );
818             }
819         }
820 
821         // write text record
822         ImplBeginRecord( WIN_EMR_EXTTEXTOUTW );
823 
824         ImplWriteRect( Rectangle( rPos, Size( nNormWidth, maVDev.GetTextHeight() ) ) );
825         (*mpStm) << (sal_uInt32)1;
826         (*mpStm) << (sal_Int32) 0 << (sal_Int32) 0;
827         ImplWritePoint( rPos );
828         (*mpStm) << (sal_uInt32) nLen << (sal_uInt32) 76 << (sal_uInt32) 2;
829         (*mpStm) << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0;
830         (*mpStm) << (sal_uInt32) ( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) );
831 
832         // write text
833         for( i = 0; i < nLen; i++ )
834             (*mpStm) << (sal_Unicode)rText.GetChar( i );
835 
836         // padding word
837         if( nLen & 1 )
838             (*mpStm) << (sal_uInt16) 0;
839 
840         // write DX array
841         ImplWriteExtent( pDX[ 0 ] );
842 
843         if( nLen > 1 )
844         {
845             for( i = 1; i < ( nLen - 1 ); i++ )
846                 ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] );
847 
848             ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) );
849         }
850 
851         ImplEndRecord();
852         delete[] pOwnArray;
853     }
854 }
855 
856 // -----------------------------------------------------------------------------
857 
Impl_handleLineInfoPolyPolygons(const LineInfo & rInfo,const basegfx::B2DPolygon & rLinePolygon)858 void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
859 {
860     if(rLinePolygon.count())
861     {
862         basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
863         basegfx::B2DPolyPolygon aFillPolyPolygon;
864 
865         rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
866 
867         if(aLinePolyPolygon.count())
868         {
869             for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
870             {
871                 const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
872                 ImplWritePolygonRecord( Polygon(aCandidate), sal_False );
873             }
874         }
875 
876         if(aFillPolyPolygon.count())
877         {
878             const Color aOldLineColor(maVDev.GetLineColor());
879             const Color aOldFillColor(maVDev.GetFillColor());
880 
881             maVDev.SetLineColor();
882             maVDev.SetFillColor(aOldLineColor);
883 
884             for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
885             {
886                 const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
887                 ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon)));
888             }
889 
890             maVDev.SetLineColor(aOldLineColor);
891             maVDev.SetFillColor(aOldFillColor);
892         }
893     }
894 }
895 
896 // -----------------------------------------------------------------------------
897 
ImplWrite(const GDIMetaFile & rMtf)898 void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
899 {
900     for( sal_uLong j = 0, nActionCount = rMtf.GetActionCount(); j < nActionCount; j++ )
901     {
902         const MetaAction*   pAction = rMtf.GetAction( j );
903         const sal_uInt16        nType = pAction->GetType();
904 
905         switch( nType )
906         {
907             case( META_PIXEL_ACTION ):
908             {
909                 const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
910 
911                 ImplCheckLineAttr();
912                 ImplBeginRecord( WIN_EMR_SETPIXELV );
913                 ImplWritePoint( pA->GetPoint() );
914                 ImplWriteColor( pA->GetColor() );
915                 ImplEndRecord();
916             }
917             break;
918 
919             case( META_POINT_ACTION ):
920             {
921                 if( maVDev.IsLineColor() )
922                 {
923                     const MetaPointAction* pA = (const MetaPointAction*) pAction;
924 
925                     ImplCheckLineAttr();
926                     ImplBeginRecord( WIN_EMR_SETPIXELV );
927                     ImplWritePoint( pA->GetPoint() );
928                     ImplWriteColor( maVDev.GetLineColor() );
929                     ImplEndRecord();
930                 }
931             }
932             break;
933 
934             case( META_LINE_ACTION ):
935             {
936                 if( maVDev.IsLineColor() )
937                 {
938                     const MetaLineAction* pA = (const MetaLineAction*) pAction;
939 
940                     if(pA->GetLineInfo().IsDefault())
941                     {
942                         ImplCheckLineAttr();
943 
944                         ImplBeginRecord( WIN_EMR_MOVETOEX );
945                         ImplWritePoint( pA->GetStartPoint() );
946                         ImplEndRecord();
947 
948                         ImplBeginRecord( WIN_EMR_LINETO );
949                         ImplWritePoint( pA->GetEndPoint() );
950                         ImplEndRecord();
951 
952                         ImplBeginRecord( WIN_EMR_SETPIXELV );
953                         ImplWritePoint( pA->GetEndPoint() );
954                         ImplWriteColor( maVDev.GetLineColor() );
955                         ImplEndRecord();
956                     }
957                     else
958                     {
959                         // LineInfo used; handle Dash/Dot and fat lines
960                         basegfx::B2DPolygon aPolygon;
961                         aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
962                         aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
963                         Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
964                     }
965                 }
966             }
967             break;
968 
969             case( META_RECT_ACTION ):
970             {
971                 if( maVDev.IsLineColor() || maVDev.IsFillColor() )
972                 {
973                     const MetaRectAction* pA = (const MetaRectAction*) pAction;
974 
975                     ImplCheckFillAttr();
976                     ImplCheckLineAttr();
977 
978                     ImplBeginRecord( WIN_EMR_RECTANGLE );
979                     ImplWriteRect( pA->GetRect() );
980                     ImplEndRecord();
981                 }
982             }
983             break;
984 
985             case( META_ROUNDRECT_ACTION ):
986             {
987                 if( maVDev.IsLineColor() || maVDev.IsFillColor() )
988                 {
989                     const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
990 
991                     ImplCheckFillAttr();
992                     ImplCheckLineAttr();
993 
994                     ImplBeginRecord( WIN_EMR_ROUNDRECT );
995                     ImplWriteRect( pA->GetRect() );
996                     ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) );
997                     ImplEndRecord();
998                 }
999             }
1000             break;
1001 
1002             case( META_ELLIPSE_ACTION ):
1003             {
1004                 if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1005                 {
1006                     const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction;
1007 
1008                     ImplCheckFillAttr();
1009                     ImplCheckLineAttr();
1010 
1011                     ImplBeginRecord( WIN_EMR_ELLIPSE );
1012                     ImplWriteRect( pA->GetRect() );
1013                     ImplEndRecord();
1014                 }
1015             }
1016             break;
1017 
1018             case( META_ARC_ACTION ):
1019             case( META_PIE_ACTION ):
1020             case( META_CHORD_ACTION ):
1021             case( META_POLYGON_ACTION ):
1022             {
1023                 if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1024                 {
1025                     Polygon aPoly;
1026 
1027                     switch( nType )
1028                     {
1029                         case( META_ARC_ACTION ):
1030                         {
1031                             const MetaArcAction* pA = (const MetaArcAction*) pAction;
1032                             aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
1033                         }
1034                         break;
1035 
1036                         case( META_PIE_ACTION ):
1037                         {
1038                             const MetaPieAction* pA = (const MetaPieAction*) pAction;
1039                             aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
1040                         }
1041                         break;
1042 
1043                         case( META_CHORD_ACTION ):
1044                         {
1045                             const MetaChordAction* pA = (const MetaChordAction*) pAction;
1046                             aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
1047                         }
1048                         break;
1049 
1050                         case( META_POLYGON_ACTION ):
1051                             aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
1052                         break;
1053                     }
1054 
1055                     ImplWritePolygonRecord( aPoly, nType != META_ARC_ACTION );
1056                 }
1057             }
1058             break;
1059 
1060             case( META_POLYLINE_ACTION ):
1061             {
1062                 if( maVDev.IsLineColor() )
1063                 {
1064                     const MetaPolyLineAction*   pA = (const MetaPolyLineAction*) pAction;
1065                     const Polygon&              rPoly = pA->GetPolygon();
1066 
1067                     if( rPoly.GetSize() )
1068                     {
1069                         if(pA->GetLineInfo().IsDefault())
1070                         {
1071                             ImplWritePolygonRecord( rPoly, sal_False );
1072                         }
1073                         else
1074                         {
1075                             // LineInfo used; handle Dash/Dot and fat lines
1076                             Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
1077                         }
1078                     }
1079                 }
1080             }
1081             break;
1082 
1083             case( META_POLYPOLYGON_ACTION ):
1084             {
1085                 if( maVDev.IsLineColor() || maVDev.IsFillColor() )
1086                     ImplWritePolyPolygonRecord( ( (const MetaPolyPolygonAction*) pAction )->GetPolyPolygon() );
1087             }
1088             break;
1089 
1090             case( META_GRADIENT_ACTION ):
1091             {
1092                 const MetaGradientAction*   pA = (const MetaGradientAction*) pAction;
1093                 GDIMetaFile                 aTmpMtf;
1094 
1095                 maVDev.AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf );
1096                 ImplWrite( aTmpMtf );
1097             }
1098             break;
1099 
1100             case META_HATCH_ACTION:
1101             {
1102                 const MetaHatchAction*  pA = (const MetaHatchAction*) pAction;
1103                 GDIMetaFile             aTmpMtf;
1104 
1105                 maVDev.AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
1106                 ImplWrite( aTmpMtf );
1107             }
1108             break;
1109 
1110             case META_TRANSPARENT_ACTION:
1111             {
1112                 ImplCheckFillAttr();
1113                 ImplCheckLineAttr();
1114                 ImplWritePolyPolygonRecord( ( (MetaTransparentAction*) pAction )->GetPolyPolygon() );
1115             }
1116             break;
1117 
1118             case META_FLOATTRANSPARENT_ACTION:
1119             {
1120                 const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction;
1121 
1122                 GDIMetaFile     aTmpMtf( pA->GetGDIMetaFile() );
1123                 Point           aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1124                 const Size      aSrcSize( aTmpMtf.GetPrefSize() );
1125                 const Point     aDestPt( pA->GetPoint() );
1126                 const Size      aDestSize( pA->GetSize() );
1127                 const double    fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
1128                 const double    fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
1129                 long            nMoveX, nMoveY;
1130 
1131                 if( fScaleX != 1.0 || fScaleY != 1.0 )
1132                 {
1133                     aTmpMtf.Scale( fScaleX, fScaleY );
1134                     aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
1135                 }
1136 
1137                 nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
1138 
1139                 if( nMoveX || nMoveY )
1140                     aTmpMtf.Move( nMoveX, nMoveY );
1141 
1142                 ImplCheckFillAttr();
1143                 ImplCheckLineAttr();
1144                 ImplCheckTextAttr();
1145                 ImplWrite( aTmpMtf );
1146             }
1147             break;
1148 
1149             case( META_EPS_ACTION ):
1150             {
1151                 const MetaEPSAction*    pA = (const MetaEPSAction*) pAction;
1152                 const GDIMetaFile       aSubstitute( pA->GetSubstitute() );
1153 
1154                 for( sal_uLong i = 0, nCount = aSubstitute.GetActionCount(); i < nCount; i++ )
1155                 {
1156                     const MetaAction* pSubstAct = aSubstitute.GetAction( i );
1157                     if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
1158                     {
1159                         maVDev.Push( PUSH_ALL );
1160                         ImplBeginRecord( WIN_EMR_SAVEDC );
1161                         ImplEndRecord();
1162 
1163                         MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1164                         Size aOutSize( maVDev.LogicToLogic( pA->GetSize(), maVDev.GetMapMode(), aMapMode ) );
1165                         aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
1166                         aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
1167                         aMapMode.SetOrigin( maVDev.LogicToLogic( pA->GetPoint(), maVDev.GetMapMode(), aMapMode ) );
1168                         maVDev.SetMapMode( aMapMode );
1169                         ImplWrite( aSubstitute );
1170 
1171                         maVDev.Pop();
1172                         ImplBeginRecord( WIN_EMR_RESTOREDC );
1173                         (*mpStm) << (sal_Int32) -1;
1174                         ImplEndRecord();
1175                         break;
1176                     }
1177                 }
1178             }
1179             break;
1180 
1181             case META_BMP_ACTION:
1182             {
1183                 const MetaBmpAction* pA = (const MetaBmpAction *) pAction;
1184                 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev.PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY );
1185             }
1186             break;
1187 
1188             case META_BMPSCALE_ACTION:
1189             {
1190                 const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
1191                 ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1192             }
1193             break;
1194 
1195             case META_BMPSCALEPART_ACTION:
1196             {
1197                 const MetaBmpScalePartAction*   pA = (const MetaBmpScalePartAction*) pAction;
1198                 Bitmap                          aTmp( pA->GetBitmap() );
1199 
1200                 if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) )
1201                     ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1202             }
1203             break;
1204 
1205             case META_BMPEX_ACTION:
1206             {
1207                 const MetaBmpExAction*  pA = (const MetaBmpExAction *) pAction;
1208                 Bitmap                  aBmp( pA->GetBitmapEx().GetBitmap() );
1209                 Bitmap                  aMsk( pA->GetBitmapEx().GetMask() );
1210 
1211                 if( !!aMsk )
1212                 {
1213                     aBmp.Replace( aMsk, COL_WHITE );
1214                     aMsk.Invert();
1215                     ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev.PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT );
1216                     ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev.PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND );
1217                 }
1218                 else
1219                     ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY );
1220             }
1221             break;
1222 
1223             case META_BMPEXSCALE_ACTION:
1224             {
1225                 const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
1226                 Bitmap                      aBmp( pA->GetBitmapEx().GetBitmap() );
1227                 Bitmap                      aMsk( pA->GetBitmapEx().GetMask() );
1228 
1229                 if( !!aMsk )
1230                 {
1231                     aBmp.Replace( aMsk, COL_WHITE );
1232                     aMsk.Invert();
1233                     ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT );
1234                     ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND );
1235                 }
1236                 else
1237                     ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY );
1238             }
1239             break;
1240 
1241             case META_BMPEXSCALEPART_ACTION:
1242             {
1243                 const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
1244                 BitmapEx                        aBmpEx( pA->GetBitmapEx() );
1245                 aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
1246                 Bitmap                          aBmp( aBmpEx.GetBitmap() );
1247                 Bitmap                          aMsk( aBmpEx.GetMask() );
1248 
1249                 if( !!aMsk )
1250                 {
1251                     aBmp.Replace( aMsk, COL_WHITE );
1252                     aMsk.Invert();
1253                     ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT );
1254                     ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND );
1255                 }
1256                 else
1257                     ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY );
1258             }
1259             break;
1260 
1261             case META_TEXT_ACTION:
1262             {
1263                 const MetaTextAction*   pA = (const MetaTextAction*) pAction;
1264                 const String            aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1265 
1266                 ImplCheckTextAttr();
1267                 ImplWriteTextRecord( pA->GetPoint(), aText, NULL, 0 );
1268             }
1269             break;
1270 
1271             case META_TEXTRECT_ACTION:
1272             {
1273                 const MetaTextRectAction*   pA = (const MetaTextRectAction*) pAction;
1274                 const String                aText( pA->GetText() );
1275 
1276                 ImplCheckTextAttr();
1277                 ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, NULL, 0 );
1278             }
1279             break;
1280 
1281             case META_TEXTARRAY_ACTION:
1282             {
1283                 const MetaTextArrayAction*  pA = (const MetaTextArrayAction*) pAction;
1284                 const String                aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1285 
1286                 ImplCheckTextAttr();
1287                 ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
1288             }
1289             break;
1290 
1291             case META_STRETCHTEXT_ACTION:
1292             {
1293                 const MetaStretchTextAction*    pA = (const MetaStretchTextAction*) pAction;
1294                 const String                    aText( pA->GetText(), pA->GetIndex(), pA->GetLen() );
1295 
1296                 ImplCheckTextAttr();
1297                 ImplWriteTextRecord( pA->GetPoint(), aText, NULL, pA->GetWidth() );
1298             }
1299             break;
1300 
1301             case( META_LINECOLOR_ACTION ):
1302             {
1303                 ( (MetaAction*) pAction )->Execute( &maVDev );
1304                 mbLineChanged = sal_True;
1305             }
1306             break;
1307 
1308             case( META_FILLCOLOR_ACTION ):
1309             {
1310                 ( (MetaAction*) pAction )->Execute( &maVDev );
1311                 mbFillChanged = sal_True;
1312             }
1313             break;
1314 
1315             case( META_TEXTCOLOR_ACTION ):
1316             case( META_TEXTLINECOLOR_ACTION ):
1317             case( META_TEXTFILLCOLOR_ACTION ):
1318             case( META_TEXTALIGN_ACTION ):
1319             case( META_FONT_ACTION ):
1320             {
1321                 ( (MetaAction*) pAction )->Execute( &maVDev );
1322                 mbTextChanged = sal_True;
1323             }
1324             break;
1325 
1326             case( META_ISECTRECTCLIPREGION_ACTION ):
1327             {
1328                 ( (MetaAction*) pAction )->Execute( &maVDev );
1329 
1330                 ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT );
1331                 ImplWriteRect( ( (MetaISectRectClipRegionAction*) pAction )->GetRect() );
1332                 ImplEndRecord();
1333             }
1334             break;
1335 
1336             case( META_CLIPREGION_ACTION ):
1337             case( META_ISECTREGIONCLIPREGION_ACTION ):
1338             case( META_MOVECLIPREGION_ACTION ):
1339             {
1340                 ( (MetaAction*) pAction )->Execute( &maVDev );
1341             }
1342             break;
1343 
1344             case( META_REFPOINT_ACTION ):
1345             case( META_MAPMODE_ACTION ):
1346                 ( (MetaAction*) pAction )->Execute( &maVDev );
1347             break;
1348 
1349             case( META_PUSH_ACTION ):
1350             {
1351                 ( (MetaAction*) pAction )->Execute( &maVDev );
1352 
1353                 ImplBeginRecord( WIN_EMR_SAVEDC );
1354                 ImplEndRecord();
1355             }
1356             break;
1357 
1358             case( META_POP_ACTION ):
1359             {
1360                 ( (MetaAction*) pAction )->Execute( &maVDev );
1361 
1362                 ImplBeginRecord( WIN_EMR_RESTOREDC );
1363                 (*mpStm) << (sal_Int32) -1;
1364                 ImplEndRecord();
1365 
1366                 ImplWriteRasterOp( maVDev.GetRasterOp() );
1367                 mbLineChanged = mbFillChanged = mbTextChanged = sal_True;
1368             }
1369             break;
1370 
1371             case( META_RASTEROP_ACTION ):
1372             {
1373                 ( (MetaAction*) pAction )->Execute( &maVDev );
1374                 ImplWriteRasterOp( ( (MetaRasterOpAction*) pAction )->GetRasterOp() );
1375             }
1376             break;
1377 
1378             case( META_LAYOUTMODE_ACTION ):
1379             {
1380                 sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pAction )->GetLayoutMode();
1381                 mnHorTextAlign = 0;
1382                 if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL)
1383                 {
1384                     mnHorTextAlign = TA_RIGHT | TA_RTLREADING;
1385                 }
1386                 if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT)
1387                     mnHorTextAlign |= TA_RIGHT;
1388                 else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT)
1389                     mnHorTextAlign &= ~TA_RIGHT;
1390                 break;
1391             }
1392 
1393             case( META_MASK_ACTION ):
1394             case( META_MASKSCALE_ACTION ):
1395             case( META_MASKSCALEPART_ACTION ):
1396             case( META_WALLPAPER_ACTION ):
1397             case( META_TEXTLINE_ACTION ):
1398             case( META_COMMENT_ACTION ):
1399             case( META_GRADIENTEX_ACTION ):
1400             {
1401                 // !!! >>> we don't want to support these actions
1402             }
1403             break;
1404 
1405             default:
1406                 DBG_ERROR( ( ByteString( "EMFWriter::ImplWriteActions: unsupported MetaAction #" ) += ByteString::CreateFromInt32( nType ) ).GetBuffer() );
1407             break;
1408         }
1409     }
1410 }
1411