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