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