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 print2.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 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -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 VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -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/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -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/vcl/source/gdi/print2.cxx

/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.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 <utility>
21#include <list>
22#include <vector>
23
24#include <basegfx/polygon/b2dpolygontools.hxx>
25#include <sal/log.hxx>
26#include <officecfg/Office/Common.hxx>
27
28#include <vcl/virdev.hxx>
29#include <vcl/metaact.hxx>
30#include <vcl/gdimtf.hxx>
31#include <vcl/print.hxx>
32#include <vcl/svapp.hxx>
33#include <vcl/bitmapaccess.hxx>
34
35#include "pdfwriter_impl.hxx"
36
37#define MAX_TILE_WIDTH1024 1024
38#define MAX_TILE_HEIGHT1024 1024
39
40typedef ::std::pair< MetaAction*, int > Component; // MetaAction plus index in metafile
41
42namespace {
43
44// List of (intersecting) actions, plus overall bounds
45struct ConnectedComponents
46{
47 ConnectedComponents() :
48 aComponentList(),
49 aBounds(),
50 aBgColor(COL_WHITE),
51 bIsSpecial(false),
52 bIsFullyTransparent(false)
53 {}
54
55 ::std::list< Component > aComponentList;
56 tools::Rectangle aBounds;
57 Color aBgColor;
58 bool bIsSpecial;
59 bool bIsFullyTransparent;
60};
61
62}
63
64namespace {
65
66/** Determines whether the action can handle transparency correctly
67 (i.e. when painted on white background, does the action still look
68 correct)?
69 */
70bool DoesActionHandleTransparency( const MetaAction& rAct )
71{
72 // MetaActionType::FLOATTRANSPARENT can contain a whole metafile,
73 // which is to be rendered with the given transparent gradient. We
74 // currently cannot emulate transparent painting on a white
75 // background reliably.
76
77 // the remainder can handle printing itself correctly on a uniform
78 // white background.
79 switch( rAct.GetType() )
80 {
81 case MetaActionType::Transparent:
82 case MetaActionType::BMPEX:
83 case MetaActionType::BMPEXSCALE:
84 case MetaActionType::BMPEXSCALEPART:
85 return true;
86
87 default:
88 return false;
89 }
90}
91
92bool doesRectCoverWithUniformColor(
93 tools::Rectangle const & rPrevRect,
94 tools::Rectangle const & rCurrRect,
95 OutputDevice const & rMapModeVDev)
96{
97 // shape needs to fully cover previous content, and have uniform
98 // color
99 return (rMapModeVDev.LogicToPixel(rCurrRect).IsInside(rPrevRect) &&
100 rMapModeVDev.IsFillColor());
101}
102
103/** Check whether rCurrRect rectangle fully covers io_rPrevRect - if
104 yes, return true and update o_rBgColor
105 */
106bool checkRect( tools::Rectangle& io_rPrevRect,
107 Color& o_rBgColor,
108 const tools::Rectangle& rCurrRect,
109 OutputDevice const & rMapModeVDev )
110{
111 bool bRet = doesRectCoverWithUniformColor(io_rPrevRect, rCurrRect, rMapModeVDev);
112
113 if( bRet )
114 {
115 io_rPrevRect = rCurrRect;
116 o_rBgColor = rMapModeVDev.GetFillColor();
117 }
118
119 return bRet;
120}
121
122/** #107169# Convert BitmapEx to Bitmap with appropriately blended
123 color. Convert MetaTransparentAction to plain polygon,
124 appropriately colored
125
126 @param o_rMtf
127 Add converted actions to this metafile
128*/
129void ImplConvertTransparentAction( GDIMetaFile& o_rMtf,
130 const MetaAction& rAct,
131 const OutputDevice& rStateOutDev,
132 Color aBgColor )
133{
134 if (rAct.GetType() == MetaActionType::Transparent)
135 {
136 const MetaTransparentAction* pTransAct = static_cast<const MetaTransparentAction*>(&rAct);
137 sal_uInt16 nTransparency( pTransAct->GetTransparence() );
138
139 // #i10613# Respect transparency for draw color
140 if (nTransparency)
141 {
142 o_rMtf.AddAction(new MetaPushAction(PushFlags::LINECOLOR|PushFlags::FILLCOLOR));
143
144 // assume white background for alpha blending
145 Color aLineColor(rStateOutDev.GetLineColor());
146 aLineColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetRed()) / 100));
147 aLineColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetGreen()) / 100));
148 aLineColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetBlue()) / 100));
149 o_rMtf.AddAction(new MetaLineColorAction(aLineColor, true));
150
151 Color aFillColor(rStateOutDev.GetFillColor());
152 aFillColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetRed()) / 100));
153 aFillColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetGreen()) / 100));
154 aFillColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetBlue()) / 100));
155 o_rMtf.AddAction(new MetaFillColorAction(aFillColor, true));
156 }
157
158 o_rMtf.AddAction(new MetaPolyPolygonAction(pTransAct->GetPolyPolygon()));
159
160 if(nTransparency)
161 o_rMtf.AddAction(new MetaPopAction());
162 }
163 else
164 {
165 BitmapEx aBmpEx;
166
167 switch (rAct.GetType())
168 {
169 case MetaActionType::BMPEX:
170 aBmpEx = static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx();
171 break;
172
173 case MetaActionType::BMPEXSCALE:
174 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
175 break;
176
177 case MetaActionType::BMPEXSCALEPART:
178 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
179 break;
180
181 case MetaActionType::Transparent:
182
183 default:
184 OSL_FAIL("Printer::GetPreparedMetafile impossible state reached")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "184" ": "), "%s", "Printer::GetPreparedMetafile impossible state reached"
); } } while (false)
;
185 break;
186 }
187
188 Bitmap aBmp(aBmpEx.GetBitmap());
189 if (!aBmpEx.IsAlpha())
190 {
191 // blend with mask
192 Bitmap::ScopedReadAccess pRA(aBmp);
193
194 if (!pRA)
195 return; // what else should I do?
196
197 Color aActualColor(aBgColor);
198
199 if (pRA->HasPalette())
200 aActualColor = pRA->GetBestPaletteColor(aBgColor);
201
202 pRA.reset();
203
204 // did we get true white?
205 if (aActualColor.GetColorError(aBgColor))
206 {
207 // no, create truecolor bitmap, then
208 aBmp.Convert(BmpConversion::N24Bit);
209
210 // fill masked out areas white
211 aBmp.Replace(aBmpEx.GetMask(), aBgColor);
212 }
213 else
214 {
215 // fill masked out areas white
216 aBmp.Replace(aBmpEx.GetMask(), aActualColor);
217 }
218 }
219 else
220 {
221 // blend with alpha channel
222 aBmp.Convert(BmpConversion::N24Bit);
223 aBmp.Blend(aBmpEx.GetAlpha(), aBgColor);
224 }
225
226 // add corresponding action
227 switch (rAct.GetType())
228 {
229 case MetaActionType::BMPEX:
230 o_rMtf.AddAction(new MetaBmpAction(
231 static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
232 aBmp));
233 break;
234 case MetaActionType::BMPEXSCALE:
235 o_rMtf.AddAction(new MetaBmpScaleAction(
236 static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
237 static_cast<const MetaBmpExScaleAction&>(rAct).GetSize(),
238 aBmp));
239 break;
240 case MetaActionType::BMPEXSCALEPART:
241 o_rMtf.AddAction(new MetaBmpScalePartAction(
242 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
243 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize(),
244 static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcPoint(),
245 static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcSize(),
246 aBmp));
247 break;
248 default:
249 OSL_FAIL("Unexpected case")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "249" ": "), "%s", "Unexpected case"); } } while (false)
;
250 break;
251 }
252 }
253}
254
255// #i10613# Extracted from ImplCheckRect::ImplCreate
256// Returns true, if given action creates visible (i.e. non-transparent) output
257bool ImplIsNotTransparent( const MetaAction& rAct, const OutputDevice& rOut )
258{
259 const bool bLineTransparency( !rOut.IsLineColor() || rOut.GetLineColor().GetTransparency() == 255 );
260 const bool bFillTransparency( !rOut.IsFillColor() || rOut.GetFillColor().GetTransparency() == 255 );
261 bool bRet( false );
262
263 switch( rAct.GetType() )
264 {
265 case MetaActionType::POINT:
266 if( !bLineTransparency )
267 bRet = true;
268 break;
269
270 case MetaActionType::LINE:
271 if( !bLineTransparency )
272 bRet = true;
273 break;
274
275 case MetaActionType::RECT:
276 if( !bLineTransparency || !bFillTransparency )
277 bRet = true;
278 break;
279
280 case MetaActionType::ROUNDRECT:
281 if( !bLineTransparency || !bFillTransparency )
282 bRet = true;
283 break;
284
285 case MetaActionType::ELLIPSE:
286 if( !bLineTransparency || !bFillTransparency )
287 bRet = true;
288 break;
289
290 case MetaActionType::ARC:
291 if( !bLineTransparency || !bFillTransparency )
292 bRet = true;
293 break;
294
295 case MetaActionType::PIE:
296 if( !bLineTransparency || !bFillTransparency )
297 bRet = true;
298 break;
299
300 case MetaActionType::CHORD:
301 if( !bLineTransparency || !bFillTransparency )
302 bRet = true;
303 break;
304
305 case MetaActionType::POLYLINE:
306 if( !bLineTransparency )
307 bRet = true;
308 break;
309
310 case MetaActionType::POLYGON:
311 if( !bLineTransparency || !bFillTransparency )
312 bRet = true;
313 break;
314
315 case MetaActionType::POLYPOLYGON:
316 if( !bLineTransparency || !bFillTransparency )
317 bRet = true;
318 break;
319
320 case MetaActionType::TEXT:
321 {
322 const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
323 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
324 if (!aString.isEmpty())
325 bRet = true;
326 }
327 break;
328
329 case MetaActionType::TEXTARRAY:
330 {
331 const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
332 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
333 if (!aString.isEmpty())
334 bRet = true;
335 }
336 break;
337
338 case MetaActionType::PIXEL:
339 case MetaActionType::BMP:
340 case MetaActionType::BMPSCALE:
341 case MetaActionType::BMPSCALEPART:
342 case MetaActionType::BMPEX:
343 case MetaActionType::BMPEXSCALE:
344 case MetaActionType::BMPEXSCALEPART:
345 case MetaActionType::MASK:
346 case MetaActionType::MASKSCALE:
347 case MetaActionType::MASKSCALEPART:
348 case MetaActionType::GRADIENT:
349 case MetaActionType::GRADIENTEX:
350 case MetaActionType::HATCH:
351 case MetaActionType::WALLPAPER:
352 case MetaActionType::Transparent:
353 case MetaActionType::FLOATTRANSPARENT:
354 case MetaActionType::EPS:
355 case MetaActionType::TEXTRECT:
356 case MetaActionType::STRETCHTEXT:
357 case MetaActionType::TEXTLINE:
358 // all other actions: generate non-transparent output
359 bRet = true;
360 break;
361
362 default:
363 break;
364 }
365
366 return bRet;
367}
368
369// #i10613# Extracted from ImplCheckRect::ImplCreate
370tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevice& rOut )
371{
372 tools::Rectangle aActionBounds;
373
374 switch( rAct.GetType() )
375 {
376 case MetaActionType::PIXEL:
377 aActionBounds = tools::Rectangle( static_cast<const MetaPixelAction&>(rAct).GetPoint(), Size( 1, 1 ) );
378 break;
379
380 case MetaActionType::POINT:
381 aActionBounds = tools::Rectangle( static_cast<const MetaPointAction&>(rAct).GetPoint(), Size( 1, 1 ) );
382 break;
383
384 case MetaActionType::LINE:
385 {
386 const MetaLineAction& rMetaLineAction = static_cast<const MetaLineAction&>(rAct);
387 aActionBounds = tools::Rectangle( rMetaLineAction.GetStartPoint(), rMetaLineAction.GetEndPoint() );
388 aActionBounds.Justify();
389 const long nLineWidth(rMetaLineAction.GetLineInfo().GetWidth());
390 if(nLineWidth)
391 {
392 const long nHalfLineWidth((nLineWidth + 1) / 2);
393 aActionBounds.AdjustLeft( -nHalfLineWidth );
394 aActionBounds.AdjustTop( -nHalfLineWidth );
395 aActionBounds.AdjustRight(nHalfLineWidth );
396 aActionBounds.AdjustBottom(nHalfLineWidth );
397 }
398 break;
399 }
400
401 case MetaActionType::RECT:
402 aActionBounds = static_cast<const MetaRectAction&>(rAct).GetRect();
403 break;
404
405 case MetaActionType::ROUNDRECT:
406 aActionBounds = tools::Polygon( static_cast<const MetaRoundRectAction&>(rAct).GetRect(),
407 static_cast<const MetaRoundRectAction&>(rAct).GetHorzRound(),
408 static_cast<const MetaRoundRectAction&>(rAct).GetVertRound() ).GetBoundRect();
409 break;
410
411 case MetaActionType::ELLIPSE:
412 {
413 const tools::Rectangle& rRect = static_cast<const MetaEllipseAction&>(rAct).GetRect();
414 aActionBounds = tools::Polygon( rRect.Center(),
415 rRect.GetWidth() >> 1,
416 rRect.GetHeight() >> 1 ).GetBoundRect();
417 break;
418 }
419
420 case MetaActionType::ARC:
421 aActionBounds = tools::Polygon( static_cast<const MetaArcAction&>(rAct).GetRect(),
422 static_cast<const MetaArcAction&>(rAct).GetStartPoint(),
423 static_cast<const MetaArcAction&>(rAct).GetEndPoint(), PolyStyle::Arc ).GetBoundRect();
424 break;
425
426 case MetaActionType::PIE:
427 aActionBounds = tools::Polygon( static_cast<const MetaPieAction&>(rAct).GetRect(),
428 static_cast<const MetaPieAction&>(rAct).GetStartPoint(),
429 static_cast<const MetaPieAction&>(rAct).GetEndPoint(), PolyStyle::Pie ).GetBoundRect();
430 break;
431
432 case MetaActionType::CHORD:
433 aActionBounds = tools::Polygon( static_cast<const MetaChordAction&>(rAct).GetRect(),
434 static_cast<const MetaChordAction&>(rAct).GetStartPoint(),
435 static_cast<const MetaChordAction&>(rAct).GetEndPoint(), PolyStyle::Chord ).GetBoundRect();
436 break;
437
438 case MetaActionType::POLYLINE:
439 {
440 const MetaPolyLineAction& rMetaPolyLineAction = static_cast<const MetaPolyLineAction&>(rAct);
441 aActionBounds = rMetaPolyLineAction.GetPolygon().GetBoundRect();
442 const long nLineWidth(rMetaPolyLineAction.GetLineInfo().GetWidth());
443 if(nLineWidth)
444 {
445 const long nHalfLineWidth((nLineWidth + 1) / 2);
446 aActionBounds.AdjustLeft( -nHalfLineWidth );
447 aActionBounds.AdjustTop( -nHalfLineWidth );
448 aActionBounds.AdjustRight(nHalfLineWidth );
449 aActionBounds.AdjustBottom(nHalfLineWidth );
450 }
451 break;
452 }
453
454 case MetaActionType::POLYGON:
455 aActionBounds = static_cast<const MetaPolygonAction&>(rAct).GetPolygon().GetBoundRect();
456 break;
457
458 case MetaActionType::POLYPOLYGON:
459 aActionBounds = static_cast<const MetaPolyPolygonAction&>(rAct).GetPolyPolygon().GetBoundRect();
460 break;
461
462 case MetaActionType::BMP:
463 aActionBounds = tools::Rectangle( static_cast<const MetaBmpAction&>(rAct).GetPoint(),
464 rOut.PixelToLogic( static_cast<const MetaBmpAction&>(rAct).GetBitmap().GetSizePixel() ) );
465 break;
466
467 case MetaActionType::BMPSCALE:
468 aActionBounds = tools::Rectangle( static_cast<const MetaBmpScaleAction&>(rAct).GetPoint(),
469 static_cast<const MetaBmpScaleAction&>(rAct).GetSize() );
470 break;
471
472 case MetaActionType::BMPSCALEPART:
473 aActionBounds = tools::Rectangle( static_cast<const MetaBmpScalePartAction&>(rAct).GetDestPoint(),
474 static_cast<const MetaBmpScalePartAction&>(rAct).GetDestSize() );
475 break;
476
477 case MetaActionType::BMPEX:
478 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
479 rOut.PixelToLogic( static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().GetSizePixel() ) );
480 break;
481
482 case MetaActionType::BMPEXSCALE:
483 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
484 static_cast<const MetaBmpExScaleAction&>(rAct).GetSize() );
485 break;
486
487 case MetaActionType::BMPEXSCALEPART:
488 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
489 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize() );
490 break;
491
492 case MetaActionType::MASK:
493 aActionBounds = tools::Rectangle( static_cast<const MetaMaskAction&>(rAct).GetPoint(),
494 rOut.PixelToLogic( static_cast<const MetaMaskAction&>(rAct).GetBitmap().GetSizePixel() ) );
495 break;
496
497 case MetaActionType::MASKSCALE:
498 aActionBounds = tools::Rectangle( static_cast<const MetaMaskScaleAction&>(rAct).GetPoint(),
499 static_cast<const MetaMaskScaleAction&>(rAct).GetSize() );
500 break;
501
502 case MetaActionType::MASKSCALEPART:
503 aActionBounds = tools::Rectangle( static_cast<const MetaMaskScalePartAction&>(rAct).GetDestPoint(),
504 static_cast<const MetaMaskScalePartAction&>(rAct).GetDestSize() );
505 break;
506
507 case MetaActionType::GRADIENT:
508 aActionBounds = static_cast<const MetaGradientAction&>(rAct).GetRect();
509 break;
510
511 case MetaActionType::GRADIENTEX:
512 aActionBounds = static_cast<const MetaGradientExAction&>(rAct).GetPolyPolygon().GetBoundRect();
513 break;
514
515 case MetaActionType::HATCH:
516 aActionBounds = static_cast<const MetaHatchAction&>(rAct).GetPolyPolygon().GetBoundRect();
517 break;
518
519 case MetaActionType::WALLPAPER:
520 aActionBounds = static_cast<const MetaWallpaperAction&>(rAct).GetRect();
521 break;
522
523 case MetaActionType::Transparent:
524 aActionBounds = static_cast<const MetaTransparentAction&>(rAct).GetPolyPolygon().GetBoundRect();
525 break;
526
527 case MetaActionType::FLOATTRANSPARENT:
528 aActionBounds = tools::Rectangle( static_cast<const MetaFloatTransparentAction&>(rAct).GetPoint(),
529 static_cast<const MetaFloatTransparentAction&>(rAct).GetSize() );
530 break;
531
532 case MetaActionType::EPS:
533 aActionBounds = tools::Rectangle( static_cast<const MetaEPSAction&>(rAct).GetPoint(),
534 static_cast<const MetaEPSAction&>(rAct).GetSize() );
535 break;
536
537 case MetaActionType::TEXT:
538 {
539 const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
540 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
541
542 if (!aString.isEmpty())
543 {
544 const Point aPtLog( rTextAct.GetPoint() );
545
546 // #105987# Use API method instead of Impl* methods
547 // #107490# Set base parameter equal to index parameter
548 rOut.GetTextBoundRect( aActionBounds, rTextAct.GetText(), rTextAct.GetIndex(),
549 rTextAct.GetIndex(), rTextAct.GetLen() );
550 aActionBounds.Move( aPtLog.X(), aPtLog.Y() );
551 }
552 }
553 break;
554
555 case MetaActionType::TEXTARRAY:
556 {
557 const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
558 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
559
560 if( !aString.isEmpty() )
561 {
562 // #105987# ImplLayout takes everything in logical coordinates
563 std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
564 rTextAct.GetLen(), rTextAct.GetPoint(),
565 0, rTextAct.GetDXArray() );
566 if( pSalLayout )
567 {
568 tools::Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
569 aActionBounds = rOut.PixelToLogic( aBoundRect );
570 }
571 }
572 }
573 break;
574
575 case MetaActionType::TEXTRECT:
576 aActionBounds = static_cast<const MetaTextRectAction&>(rAct).GetRect();
577 break;
578
579 case MetaActionType::STRETCHTEXT:
580 {
581 const MetaStretchTextAction& rTextAct = static_cast<const MetaStretchTextAction&>(rAct);
582 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
583
584 // #i16195# Literate copy from TextArray action, the
585 // semantics for the ImplLayout call are copied from the
586 // OutDev::DrawStretchText() code. Unfortunately, also in
587 // this case, public outdev methods such as GetTextWidth()
588 // don't provide enough info.
589 if( !aString.isEmpty() )
590 {
591 // #105987# ImplLayout takes everything in logical coordinates
592 std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
593 rTextAct.GetLen(), rTextAct.GetPoint(),
594 rTextAct.GetWidth() );
595 if( pSalLayout )
596 {
597 tools::Rectangle aBoundRect( const_cast<OutputDevice&>(rOut).ImplGetTextBoundRect( *pSalLayout ) );
598 aActionBounds = rOut.PixelToLogic( aBoundRect );
599 }
600 }
601 }
602 break;
603
604 case MetaActionType::TEXTLINE:
605 OSL_FAIL("MetaActionType::TEXTLINE not supported")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "605" ": "), "%s", "MetaActionType::TEXTLINE not supported"
); } } while (false)
;
606 break;
607
608 default:
609 break;
610 }
611
612 if( !aActionBounds.IsEmpty() )
613 {
614 // fdo#40421 limit current action's output to clipped area
615 if( rOut.IsClipRegion() )
616 return rOut.LogicToPixel(
617 rOut.GetClipRegion().GetBoundRect().Intersection( aActionBounds ) );
618 else
619 return rOut.LogicToPixel( aActionBounds );
620 }
621 else
622 return tools::Rectangle();
623}
624
625} // end anon namespace
626
627bool OutputDevice::RemoveTransparenciesFromMetaFile( const GDIMetaFile& rInMtf, GDIMetaFile& rOutMtf,
628 long nMaxBmpDPIX, long nMaxBmpDPIY,
629 bool bReduceTransparency, bool bTransparencyAutoMode,
630 bool bDownsampleBitmaps,
631 const Color& rBackground
632 )
633{
634 MetaAction* pCurrAct;
635 bool bTransparent( false );
636
637 rOutMtf.Clear();
638
639 if(!bReduceTransparency || bTransparencyAutoMode)
1
Assuming 'bReduceTransparency' is true
2
Assuming 'bTransparencyAutoMode' is true
3
Taking true branch
640 bTransparent = rInMtf.HasTransparentActions();
641
642 // #i10613# Determine set of connected components containing transparent objects. These are
643 // then processed as bitmaps, the original actions are removed from the metafile.
644 if( !bTransparent )
4
Assuming 'bTransparent' is true
5
Taking false branch
645 {
646 // nothing transparent -> just copy
647 rOutMtf = rInMtf;
648 }
649 else
650 {
651 // #i10613#
652 // This works as follows: we want a number of distinct sets of
653 // connected components, where each set contains metafile
654 // actions that are intersecting (note: there are possibly
655 // more actions contained as are directly intersecting,
656 // because we can only produce rectangular bitmaps later
657 // on. Thus, each set of connected components is the smallest
658 // enclosing, axis-aligned rectangle that completely bounds a
659 // number of intersecting metafile actions, plus any action
660 // that would otherwise be cut in two). Therefore, we
661 // iteratively add metafile actions from the original metafile
662 // to this connected components list (aCCList), by checking
663 // each element's bounding box against intersection with the
664 // metaaction at hand.
665 // All those intersecting elements are removed from aCCList
666 // and collected in a temporary list (aCCMergeList). After all
667 // elements have been checked, the aCCMergeList elements are
668 // merged with the metaaction at hand into one resulting
669 // connected component, with one big bounding box, and
670 // inserted into aCCList again.
671 // The time complexity of this algorithm is O(n^3), where n is
672 // the number of metafile actions, and it finds all distinct
673 // regions of rectangle-bounded connected components. This
674 // algorithm was designed by AF.
675
676 // STAGE 1: Detect background
677
678 // Receives uniform background content, and is _not_ merged
679 // nor checked for intersection against other aCCList elements
680 ConnectedComponents aBackgroundComponent;
681
682 // Read the configuration value of minimal object area where transparency will be removed
683 double fReduceTransparencyMinArea = officecfg::Office::Common::VCL::ReduceTransparencyMinArea::get() / 100.0;
684 SAL_WARN_IF(fReduceTransparencyMinArea > 1.0, "vcl",do { if (true && (fReduceTransparencyMinArea > 1.0
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too high"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too high"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too high"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too high"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too high"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too high"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
6
Assuming the condition is false
7
Taking false branch
8
Loop condition is false. Exiting loop
685 "Value of ReduceTransparencyMinArea config option is too high")do { if (true && (fReduceTransparencyMinArea > 1.0
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too high"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too high"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too high"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too high"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too high"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too high"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "685" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
686 SAL_WARN_IF(fReduceTransparencyMinArea < 0.0, "vcl",do { if (true && (fReduceTransparencyMinArea < 0.0
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too low"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too low"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too low"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too low"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too low"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too low"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
9
Assuming the condition is false
10
Taking false branch
11
Loop condition is false. Exiting loop
687 "Value of ReduceTransparencyMinArea config option is too low")do { if (true && (fReduceTransparencyMinArea < 0.0
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too low"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too low"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too low"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Value of ReduceTransparencyMinArea config option is too low"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Value of ReduceTransparencyMinArea config option is too low"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Value of ReduceTransparencyMinArea config option is too low"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "687" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
688 fReduceTransparencyMinArea = std::clamp(fReduceTransparencyMinArea, 0.0, 1.0);
689
690 // create an OutputDevice to record mapmode changes and the like
691 ScopedVclPtrInstance< VirtualDevice > aMapModeVDev;
12
Calling default constructor for 'ScopedVclPtrInstance<VirtualDevice>'
14
Returning from default constructor for 'ScopedVclPtrInstance<VirtualDevice>'
692 aMapModeVDev->mnDPIX = mnDPIX;
693 aMapModeVDev->mnDPIY = mnDPIY;
694 aMapModeVDev->EnableOutput(false);
695
696 int nLastBgAction, nActionNum;
697
698 // weed out page-filling background objects (if they are
699 // uniformly coloured). Keeping them outside the other
700 // connected components often prevents whole-page bitmap
701 // generation.
702 bool bStillBackground=true; // true until first non-bg action
703 nActionNum=0; nLastBgAction=-1;
704 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
705 if( rBackground != COL_TRANSPARENT )
15
Taking true branch
706 {
707 aBackgroundComponent.aBgColor = rBackground;
708 aBackgroundComponent.aBounds = GetBackgroundComponentBounds();
709 }
710 while( pCurrAct && bStillBackground )
16
Assuming 'pCurrAct' is null
711 {
712 switch( pCurrAct->GetType() )
713 {
714 case MetaActionType::RECT:
715 {
716 if( !checkRect(
717 aBackgroundComponent.aBounds,
718 aBackgroundComponent.aBgColor,
719 static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
720 *aMapModeVDev) )
721 bStillBackground=false; // incomplete occlusion of background
722 else
723 nLastBgAction=nActionNum; // this _is_ background
724 break;
725 }
726 case MetaActionType::POLYGON:
727 {
728 const tools::Polygon aPoly(
729 static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
730 if( !basegfx::utils::isRectangle(
731 aPoly.getB2DPolygon()) ||
732 !checkRect(
733 aBackgroundComponent.aBounds,
734 aBackgroundComponent.aBgColor,
735 aPoly.GetBoundRect(),
736 *aMapModeVDev) )
737 bStillBackground=false; // incomplete occlusion of background
738 else
739 nLastBgAction=nActionNum; // this _is_ background
740 break;
741 }
742 case MetaActionType::POLYPOLYGON:
743 {
744 const tools::PolyPolygon aPoly(
745 static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
746 if( aPoly.Count() != 1 ||
747 !basegfx::utils::isRectangle(
748 aPoly[0].getB2DPolygon()) ||
749 !checkRect(
750 aBackgroundComponent.aBounds,
751 aBackgroundComponent.aBgColor,
752 aPoly.GetBoundRect(),
753 *aMapModeVDev) )
754 bStillBackground=false; // incomplete occlusion of background
755 else
756 nLastBgAction=nActionNum; // this _is_ background
757 break;
758 }
759 case MetaActionType::WALLPAPER:
760 {
761 if( !checkRect(
762 aBackgroundComponent.aBounds,
763 aBackgroundComponent.aBgColor,
764 static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
765 *aMapModeVDev) )
766 bStillBackground=false; // incomplete occlusion of background
767 else
768 nLastBgAction=nActionNum; // this _is_ background
769 break;
770 }
771 default:
772 {
773 if( ImplIsNotTransparent( *pCurrAct,
774 *aMapModeVDev ) )
775 bStillBackground=false; // non-transparent action, possibly
776 // not uniform
777 else
778 // extend current bounds (next uniform action
779 // needs to fully cover this area)
780 aBackgroundComponent.aBounds.Union(
781 ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
782 break;
783 }
784 }
785
786 // execute action to get correct MapModes etc.
787 pCurrAct->Execute( aMapModeVDev.get() );
788
789 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
790 ++nActionNum;
791 }
792
793 aMapModeVDev->ClearStack(); // clean up aMapModeVDev
794
795 // fast-forward until one after the last background action
796 // (need to reconstruct map mode vdev state)
797 nActionNum=0;
798 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
799 while( pCurrAct && nActionNum<=nLastBgAction )
17
Assuming 'pCurrAct' is null
800 {
801 // up to and including last ink-generating background
802 // action go to background component
803 aBackgroundComponent.aComponentList.emplace_back(
804 pCurrAct, nActionNum );
805
806 // execute action to get correct MapModes etc.
807 pCurrAct->Execute( aMapModeVDev.get() );
808 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
809 ++nActionNum;
810 }
811
812 // STAGE 2: Generate connected components list
813
814 ::std::vector<ConnectedComponents> aCCList; // contains distinct sets of connected components as elements.
815
816 // iterate over all actions (start where background action
817 // search left off)
818 for( ;
18
Loop condition is false. Execution continues on line 1019
819 pCurrAct;
820 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
821 {
822 // execute action to get correct MapModes etc.
823 pCurrAct->Execute( aMapModeVDev.get() );
824
825 // cache bounds of current action
826 const tools::Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
827
828 // accumulate collected bounds here, initialize with current action
829 tools::Rectangle aTotalBounds( aBBCurrAct ); // thus, aTotalComponents.aBounds is empty
830 // for non-output-generating actions
831 bool bTreatSpecial( false );
832 ConnectedComponents aTotalComponents;
833
834 // STAGE 2.1: Search for intersecting cc entries
835
836 // if aBBCurrAct is empty, it will intersect with no
837 // aCCList member. Thus, we can save the check.
838 // Furthermore, this ensures that non-output-generating
839 // actions get their own aCCList entry, which is necessary
840 // when copying them to the output metafile (see stage 4
841 // below).
842
843 // #107169# Wholly transparent objects need
844 // not be considered for connected components,
845 // too. Just put each of them into a separate
846 // component.
847 aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, *aMapModeVDev);
848
849 if( !aBBCurrAct.IsEmpty() &&
850 !aTotalComponents.bIsFullyTransparent )
851 {
852 if( !aBackgroundComponent.aComponentList.empty() &&
853 !aBackgroundComponent.aBounds.IsInside(aTotalBounds) )
854 {
855 // it seems the background is not large enough. to
856 // be on the safe side, combine with this component.
857 aTotalBounds.Union( aBackgroundComponent.aBounds );
858
859 // extract all aCurr actions to aTotalComponents
860 aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
861 aBackgroundComponent.aComponentList );
862
863 if( aBackgroundComponent.bIsSpecial )
864 bTreatSpecial = true;
865 }
866
867 bool bSomeComponentsChanged;
868
869 // now, this is unfortunate: since changing anyone of
870 // the aCCList elements (e.g. by merging or addition
871 // of an action) might generate new intersection with
872 // other aCCList elements, have to repeat the whole
873 // element scanning, until nothing changes anymore.
874 // Thus, this loop here makes us O(n^3) in the worst
875 // case.
876 do
877 {
878 // only loop here if 'intersects' branch below was hit
879 bSomeComponentsChanged = false;
880
881 // iterate over all current members of aCCList
882 for( auto aCurrCC=aCCList.begin(); aCurrCC != aCCList.end(); )
883 {
884 // first check if current element's bounds are
885 // empty. This ensures that empty actions are not
886 // merged into one component, as a matter of fact,
887 // they have no position.
888
889 // #107169# Wholly transparent objects need
890 // not be considered for connected components,
891 // too. Just put each of them into a separate
892 // component.
893 if( !aCurrCC->aBounds.IsEmpty() &&
894 !aCurrCC->bIsFullyTransparent &&
895 aCurrCC->aBounds.IsOver( aTotalBounds ) )
896 {
897 // union the intersecting aCCList element into aTotalComponents
898
899 // calc union bounding box
900 aTotalBounds.Union( aCurrCC->aBounds );
901
902 // extract all aCurr actions to aTotalComponents
903 aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
904 aCurrCC->aComponentList );
905
906 if( aCurrCC->bIsSpecial )
907 bTreatSpecial = true;
908
909 // remove and delete aCurrCC element from list (we've now merged its content)
910 aCurrCC = aCCList.erase( aCurrCC );
911
912 // at least one component changed, need to rescan everything
913 bSomeComponentsChanged = true;
914 }
915 else
916 {
917 ++aCurrCC;
918 }
919 }
920 }
921 while( bSomeComponentsChanged );
922 }
923
924 // STAGE 2.2: Determine special state for cc element
925
926 // now test whether the whole connected component must be
927 // treated specially (i.e. rendered as a bitmap): if the
928 // added action is the very first action, or all actions
929 // before it are completely transparent, the connected
930 // component need not be treated specially, not even if
931 // the added action contains transparency. This is because
932 // painting of transparent objects on _white background_
933 // works without alpha compositing (you just calculate the
934 // color). Note that for the test "all objects before me
935 // are transparent" no sorting is necessary, since the
936 // added metaaction pCurrAct is always in the order the
937 // metafile is painted. Generally, the order of the
938 // metaactions in the ConnectedComponents are not
939 // guaranteed to be the same as in the metafile.
940 if( bTreatSpecial )
941 {
942 // prev component(s) special -> this one, too
943 aTotalComponents.bIsSpecial = true;
944 }
945 else if(!pCurrAct->IsTransparent())
946 {
947 // added action and none of prev components special ->
948 // this one normal, too
949 aTotalComponents.bIsSpecial = false;
950 }
951 else
952 {
953 // added action is special and none of prev components
954 // special -> do the detailed tests
955
956 // can the action handle transparency correctly
957 // (i.e. when painted on white background, does the
958 // action still look correct)?
959 if( !DoesActionHandleTransparency( *pCurrAct ) )
960 {
961 // no, action cannot handle its transparency on
962 // a printer device, render to bitmap
963 aTotalComponents.bIsSpecial = true;
964 }
965 else
966 {
967 // yes, action can handle its transparency, so
968 // check whether we're on white background
969 if( aTotalComponents.aComponentList.empty() )
970 {
971 // nothing between pCurrAct and page
972 // background -> don't be special
973 aTotalComponents.bIsSpecial = false;
974 }
975 else
976 {
977 // #107169# Fixes above now ensure that _no_
978 // object in the list is fully transparent. Thus,
979 // if the component list is not empty above, we
980 // must assume that we have to treat this
981 // component special.
982
983 // there are non-transparent objects between
984 // pCurrAct and the empty sheet of paper -> be
985 // special, then
986 aTotalComponents.bIsSpecial = true;
987 }
988 }
989 }
990
991 // STAGE 2.3: Add newly generated CC list element
992
993 // set new bounds and add action to list
994 aTotalComponents.aBounds = aTotalBounds;
995 aTotalComponents.aComponentList.emplace_back(
996 pCurrAct, nActionNum );
997
998 // add aTotalComponents as a new entry to aCCList
999 aCCList.push_back( aTotalComponents );
1000
1001 SAL_WARN_IF( aTotalComponents.aComponentList.empty(), "vcl",do { if (true && (aTotalComponents.aComponentList.empty
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile empty component") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile empty component"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile empty component"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile empty component") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile empty component"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile empty component"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1002 "Printer::GetPreparedMetaFile empty component" )do { if (true && (aTotalComponents.aComponentList.empty
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile empty component") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile empty component"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile empty component"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile empty component") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile empty component"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile empty component"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1002" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1003 SAL_WARN_IF( aTotalComponents.aBounds.IsEmpty() && (aTotalComponents.aComponentList.size() != 1), "vcl",do { if (true && (aTotalComponents.aBounds.IsEmpty() &&
(aTotalComponents.aComponentList.size() != 1))) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1004 "Printer::GetPreparedMetaFile non-output generating actions must be solitary")do { if (true && (aTotalComponents.aBounds.IsEmpty() &&
(aTotalComponents.aComponentList.size() != 1))) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile non-output generating actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1004" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1005 SAL_WARN_IF( aTotalComponents.bIsFullyTransparent && (aTotalComponents.aComponentList.size() != 1), "vcl",do { if (true && (aTotalComponents.bIsFullyTransparent
&& (aTotalComponents.aComponentList.size() != 1))) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1006 "Printer::GetPreparedMetaFile fully transparent actions must be solitary")do { if (true && (aTotalComponents.bIsFullyTransparent
&& (aTotalComponents.aComponentList.size() != 1))) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Printer::GetPreparedMetaFile fully transparent actions must be solitary"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
":" "1006" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1007 }
1008
1009 // well now, we've got the list of disjunct connected
1010 // components. Now we've got to create a map, which contains
1011 // the corresponding aCCList element for every
1012 // metaaction. Later on, we always process the complete
1013 // metafile for each bitmap to be generated, but switch on
1014 // output only for actions contained in the then current
1015 // aCCList element. This ensures correct mapmode and attribute
1016 // settings for all cases.
1017
1018 // maps mtf actions to CC list entries
1019 ::std::vector< const ConnectedComponents* > aCCList_MemberMap( rInMtf.GetActionSize() );
1020
1021 // iterate over all aCCList members and their contained metaactions
1022 for (auto const& currentItem : aCCList)
1023 {
1024 for (auto const& currentAction : currentItem.aComponentList)
1025 {
1026 // set pointer to aCCList element for corresponding index
1027 aCCList_MemberMap[ currentAction.second ] = &currentItem;
1028 }
1029 }
1030
1031 // STAGE 3.1: Output background mtf actions (if there are any)
1032
1033 for (auto & component : aBackgroundComponent.aComponentList)
1034 {
1035 // simply add this action (above, we inserted the actions
1036 // starting at index 0 up to and including nLastBgAction)
1037 rOutMtf.AddAction( component.first );
1038 }
1039
1040 // STAGE 3.2: Generate banded bitmaps for special regions
1041
1042 Point aPageOffset;
1043 Size aTmpSize( GetOutputSizePixel() );
1044 if( meOutDevType == OUTDEV_PDF )
19
Assuming field 'meOutDevType' is not equal to OUTDEV_PDF
20
Taking false branch
1045 {
1046 auto pPdfWriter = static_cast<vcl::PDFWriterImpl*>(this);
1047 aTmpSize = LogicToPixel(pPdfWriter->getCurPageSize(), MapMode(MapUnit::MapPoint));
1048
1049 // also add error code to PDFWriter
1050 pPdfWriter->insertError(vcl::PDFWriter::Warning_Transparency_Converted);
1051 }
1052 else if( meOutDevType == OUTDEV_PRINTER )
21
Assuming field 'meOutDevType' is not equal to OUTDEV_PRINTER
22
Taking false branch
1053 {
1054 Printer* pThis = dynamic_cast<Printer*>(this);
1055 assert(pThis)(static_cast <bool> (pThis) ? void (0) : __assert_fail (
"pThis", "/home/maarten/src/libreoffice/core/vcl/source/gdi/print2.cxx"
, 1055, __extension__ __PRETTY_FUNCTION__))
;
1056 aPageOffset = pThis->GetPageOffsetPixel();
1057 aPageOffset = Point( 0, 0 ) - aPageOffset;
1058 aTmpSize = pThis->GetPaperSizePixel();
1059 }
1060 const tools::Rectangle aOutputRect( aPageOffset, aTmpSize );
1061 bool bTiling = dynamic_cast<Printer*>(this) != nullptr;
1062
1063 // iterate over all aCCList members and generate bitmaps for the special ones
1064 for (auto & currentItem : aCCList)
1065 {
1066 if( currentItem.bIsSpecial )
1067 {
1068 tools::Rectangle aBoundRect( currentItem.aBounds );
1069 aBoundRect.Intersection( aOutputRect );
1070
1071 const double fBmpArea( static_cast<double>(aBoundRect.GetWidth()) * aBoundRect.GetHeight() );
1072 const double fOutArea( static_cast<double>(aOutputRect.GetWidth()) * aOutputRect.GetHeight() );
1073
1074 // check if output doesn't exceed given size
1075 if( bReduceTransparency && bTransparencyAutoMode && ( fBmpArea > ( fReduceTransparencyMinArea * fOutArea ) ) )
1076 {
1077 // output normally. Therefore, we simply clear the
1078 // special attribute, as everything non-special is
1079 // copied to rOutMtf further below.
1080 currentItem.bIsSpecial = false;
1081 }
1082 else
1083 {
1084 // create new bitmap action first
1085 if( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
1086 {
1087 Point aDstPtPix( aBoundRect.TopLeft() );
1088 Size aDstSzPix;
1089
1090 ScopedVclPtrInstance<VirtualDevice> aMapVDev; // here, we record only mapmode information
1091 aMapVDev->EnableOutput(false);
1092
1093 ScopedVclPtrInstance<VirtualDevice> aPaintVDev; // into this one, we render.
1094 aPaintVDev->SetBackground( aBackgroundComponent.aBgColor );
1095
1096 rOutMtf.AddAction( new MetaPushAction( PushFlags::MAPMODE ) );
1097 rOutMtf.AddAction( new MetaMapModeAction() );
1098
1099 aPaintVDev->SetDrawMode( GetDrawMode() );
1100
1101 while( aDstPtPix.Y() <= aBoundRect.Bottom() )
1102 {
1103 aDstPtPix.setX( aBoundRect.Left() );
1104 aDstSzPix = bTiling ? Size( MAX_TILE_WIDTH1024, MAX_TILE_HEIGHT1024 ) : aBoundRect.GetSize();
1105
1106 if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1 ) > aBoundRect.Bottom() )
1107 aDstSzPix.setHeight( aBoundRect.Bottom() - aDstPtPix.Y() + 1 );
1108
1109 while( aDstPtPix.X() <= aBoundRect.Right() )
1110 {
1111 if( ( aDstPtPix.X() + aDstSzPix.Width() - 1 ) > aBoundRect.Right() )
1112 aDstSzPix.setWidth( aBoundRect.Right() - aDstPtPix.X() + 1 );
1113
1114 if( !tools::Rectangle( aDstPtPix, aDstSzPix ).Intersection( aBoundRect ).IsEmpty() &&
1115 aPaintVDev->SetOutputSizePixel( aDstSzPix ) )
1116 {
1117 aPaintVDev->Push();
1118 aMapVDev->Push();
1119
1120 aMapVDev->mnDPIX = aPaintVDev->mnDPIX = mnDPIX;
1121 aMapVDev->mnDPIY = aPaintVDev->mnDPIY = mnDPIY;
1122
1123 aPaintVDev->EnableOutput(false);
1124
1125 // iterate over all actions
1126 for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
1127 pCurrAct;
1128 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1129 {
1130 // enable output only for
1131 // actions that are members of
1132 // the current aCCList element
1133 // (currentItem)
1134 if( aCCList_MemberMap[nActionNum] == &currentItem )
1135 aPaintVDev->EnableOutput();
1136
1137 // but process every action
1138 const MetaActionType nType( pCurrAct->GetType() );
1139
1140 if( MetaActionType::MAPMODE == nType )
1141 {
1142 pCurrAct->Execute( aMapVDev.get() );
1143
1144 MapMode aMtfMap( aMapVDev->GetMapMode() );
1145 const Point aNewOrg( aMapVDev->PixelToLogic( aDstPtPix ) );
1146
1147 aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
1148 aPaintVDev->SetMapMode( aMtfMap );
1149 }
1150 else if( ( MetaActionType::PUSH == nType ) || MetaActionType::POP == nType )
1151 {
1152 pCurrAct->Execute( aMapVDev.get() );
1153 pCurrAct->Execute( aPaintVDev.get() );
1154 }
1155 else if( MetaActionType::GRADIENT == nType )
1156 {
1157 MetaGradientAction* pGradientAction = static_cast<MetaGradientAction*>(pCurrAct);
1158 Printer* pPrinter = dynamic_cast< Printer* >(this);
1159 if( pPrinter )
1160 pPrinter->DrawGradientEx( aPaintVDev.get(), pGradientAction->GetRect(), pGradientAction->GetGradient() );
1161 else
1162 DrawGradient( pGradientAction->GetRect(), pGradientAction->GetGradient() );
1163 }
1164 else
1165 {
1166 pCurrAct->Execute( aPaintVDev.get() );
1167 }
1168
1169 Application::Reschedule( true );
1170 }
1171
1172 const bool bOldMap = mbMap;
1173 mbMap = aPaintVDev->mbMap = false;
1174
1175 Bitmap aBandBmp( aPaintVDev->GetBitmap( Point(), aDstSzPix ) );
1176
1177 // scale down bitmap, if requested
1178 if( bDownsampleBitmaps )
1179 {
1180 aBandBmp = GetDownsampledBitmap( aDstSzPix,
1181 Point(), aBandBmp.GetSizePixel(),
1182 aBandBmp, nMaxBmpDPIX, nMaxBmpDPIY );
1183 }
1184
1185 rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
1186 rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) );
1187 rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
1188
1189 aPaintVDev->mbMap = true;
1190 mbMap = bOldMap;
1191 aMapVDev->Pop();
1192 aPaintVDev->Pop();
1193 }
1194
1195 // overlapping bands to avoid missing lines (e.g. PostScript)
1196 aDstPtPix.AdjustX(aDstSzPix.Width() );
1197 }
1198
1199 // overlapping bands to avoid missing lines (e.g. PostScript)
1200 aDstPtPix.AdjustY(aDstSzPix.Height() );
1201 }
1202
1203 rOutMtf.AddAction( new MetaPopAction() );
1204 }
1205 }
1206 }
1207 }
1208
1209 aMapModeVDev->ClearStack(); // clean up aMapModeVDev
1210
1211 // STAGE 4: Copy actions to output metafile
1212
1213 // iterate over all actions and duplicate the ones not in a
1214 // special aCCList member into rOutMtf
1215 for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
23
Loop condition is false. Execution continues on line 1253
1216 pCurrAct;
1217 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1218 {
1219 const ConnectedComponents* pCurrAssociatedComponent = aCCList_MemberMap[nActionNum];
1220
1221 // NOTE: This relies on the fact that map-mode or draw
1222 // mode changing actions are solitary aCCList elements and
1223 // have empty bounding boxes, see comment on stage 2.1
1224 // above
1225 if( pCurrAssociatedComponent &&
1226 (pCurrAssociatedComponent->aBounds.IsEmpty() ||
1227 !pCurrAssociatedComponent->bIsSpecial) )
1228 {
1229 // #107169# Treat transparent bitmaps special, if they
1230 // are the first (or sole) action in their bounds
1231 // list. Note that we previously ensured that no
1232 // fully-transparent objects are before us here.
1233 if( DoesActionHandleTransparency( *pCurrAct ) &&
1234 pCurrAssociatedComponent->aComponentList.begin()->first == pCurrAct )
1235 {
1236 // convert actions, where masked-out parts are of
1237 // given background color
1238 ImplConvertTransparentAction(rOutMtf,
1239 *pCurrAct,
1240 *aMapModeVDev,
1241 aBackgroundComponent.aBgColor);
1242 }
1243 else
1244 {
1245 // simply add this action
1246 rOutMtf.AddAction( pCurrAct );
1247 }
1248
1249 pCurrAct->Execute(aMapModeVDev.get());
1250 }
1251 }
1252
1253 rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() );
1254 rOutMtf.SetPrefSize( rInMtf.GetPrefSize() );
1255
1256#if OSL_DEBUG_LEVEL1 > 1
1257 // iterate over all aCCList members and generate rectangles for the bounding boxes
1258 rOutMtf.AddAction( new MetaFillColorAction( COL_WHITE, false ) );
1259 for(auto const& aCurr:aCCList)
1260 {
1261 if( aCurr.bIsSpecial )
1262 rOutMtf.AddAction( new MetaLineColorAction( COL_RED, true) );
1263 else
1264 rOutMtf.AddAction( new MetaLineColorAction( COL_BLUE, true) );
1265
1266 rOutMtf.AddAction( new MetaRectAction( aMapModeVDev->PixelToLogic( aCurr.aBounds ) ) );
1267 }
1268#endif
1269 }
24
Calling implicit destructor for 'ScopedVclPtrInstance<VirtualDevice>'
25
Calling '~ScopedVclPtr'
1270 return bTransparent;
1271}
1272
1273void Printer::DrawGradientEx( OutputDevice* pOut, const tools::Rectangle& rRect, const Gradient& rGradient )
1274{
1275 const PrinterOptions& rPrinterOptions = GetPrinterOptions();
1276
1277 if( rPrinterOptions.IsReduceGradients() )
1278 {
1279 if( PrinterGradientMode::Stripes == rPrinterOptions.GetReducedGradientMode() )
1280 {
1281 if( !rGradient.GetSteps() || ( rGradient.GetSteps() > rPrinterOptions.GetReducedGradientStepCount() ) )
1282 {
1283 Gradient aNewGradient( rGradient );
1284
1285 aNewGradient.SetSteps( rPrinterOptions.GetReducedGradientStepCount() );
1286 pOut->DrawGradient( rRect, aNewGradient );
1287 }
1288 else
1289 pOut->DrawGradient( rRect, rGradient );
1290 }
1291 else
1292 {
1293 const Color& rStartColor = rGradient.GetStartColor();
1294 const Color& rEndColor = rGradient.GetEndColor();
1295 const long nR = ( ( static_cast<long>(rStartColor.GetRed()) * rGradient.GetStartIntensity() ) / 100 +
1296 ( static_cast<long>(rEndColor.GetRed()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1297 const long nG = ( ( static_cast<long>(rStartColor.GetGreen()) * rGradient.GetStartIntensity() ) / 100 +
1298 ( static_cast<long>(rEndColor.GetGreen()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1299 const long nB = ( ( static_cast<long>(rStartColor.GetBlue()) * rGradient.GetStartIntensity() ) / 100 +
1300 ( static_cast<long>(rEndColor.GetBlue()) * rGradient.GetEndIntensity() ) / 100 ) >> 1;
1301 const Color aColor( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
1302
1303 pOut->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
1304 pOut->SetLineColor( aColor );
1305 pOut->SetFillColor( aColor );
1306 pOut->DrawRect( rRect );
1307 pOut->Pop();
1308 }
1309 }
1310 else
1311 pOut->DrawGradient( rRect, rGradient );
1312}
1313
1314/* 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 ;-)
27
Calling 'Reference::clear'
34
Returning; memory was released
205 if (aTmp.get()) {
35
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();
26
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 )
13
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
27.1
Field 'm_pBody' is non-null
27.1
Field 'm_pBody' is non-null
27.1
Field 'm_pBody' is non-null
27.1
Field 'm_pBody' is non-null
)
28
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
29
Calling 'VclReferenceBase::release'
33
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;
36
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)
30
Assuming the condition is true
31
Taking true branch
40 delete this;
32
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