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