Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name mtftools.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EMFIO_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/emfio/inc -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/emfio/source/reader/mtftools.cxx

/home/maarten/src/libreoffice/core/emfio/source/reader/mtftools.cxx

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

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
30
Calling 'Reference::clear'
37
Returning; memory was released
205 if (aTmp.get()) {
38
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
29
Calling 'VclPtr::disposeAndClear'
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
23
Memory is allocated
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
30.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
30.1
Field 'm_pBody' is non-null
)
31
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
32
Calling 'VclReferenceBase::release'
36
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
39
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
33
Assuming the condition is true
34
Taking true branch
40 delete this;
35
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif