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 pdfwriter_impl2.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/pdfwriter_impl2.cxx

/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.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 "pdfwriter_impl.hxx"
21
22#include <vcl/pdfextoutdevdata.hxx>
23#include <vcl/virdev.hxx>
24#include <vcl/gdimtf.hxx>
25#include <vcl/metaact.hxx>
26#include <vcl/bitmapaccess.hxx>
27#include <vcl/graph.hxx>
28
29#include <unotools/streamwrap.hxx>
30
31#include <tools/helpers.hxx>
32#include <tools/fract.hxx>
33#include <tools/stream.hxx>
34
35#include <comphelper/fileformat.h>
36#include <comphelper/hash.hxx>
37#include <comphelper/processfactory.hxx>
38
39#include <com/sun/star/beans/PropertyValue.hpp>
40#include <com/sun/star/io/XSeekable.hpp>
41#include <com/sun/star/graphic/GraphicProvider.hpp>
42#include <com/sun/star/graphic/XGraphicProvider.hpp>
43#include <com/sun/star/beans/XMaterialHolder.hpp>
44
45#include <cppuhelper/implbase.hxx>
46
47#include <sal/log.hxx>
48#include <memory>
49
50using namespace vcl;
51using namespace com::sun::star;
52using namespace com::sun::star::uno;
53using namespace com::sun::star::beans;
54
55static bool lcl_canUsePDFAxialShading(const Gradient& rGradient);
56
57void PDFWriterImpl::implWriteGradient( const tools::PolyPolygon& i_rPolyPoly, const Gradient& i_rGradient,
58 VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext )
59{
60 GDIMetaFile aTmpMtf;
61
62 i_pDummyVDev->AddGradientActions( i_rPolyPoly.GetBoundRect(), i_rGradient, aTmpMtf );
63
64 m_rOuterFace.Push();
65 m_rOuterFace.IntersectClipRegion( i_rPolyPoly.getB2DPolyPolygon() );
66 playMetafile( aTmpMtf, nullptr, i_rContext, i_pDummyVDev );
67 m_rOuterFace.Pop();
68}
69
70void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSize, const BitmapEx& i_rBitmapEx, const Graphic& i_Graphic,
71 VirtualDevice const * i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext )
72{
73 if ( i_rBitmapEx.IsEmpty() || !i_rSize.Width() || !i_rSize.Height() )
74 return;
75
76 BitmapEx aBitmapEx( i_rBitmapEx );
77 Point aPoint( i_rPoint );
78 Size aSize( i_rSize );
79
80 // #i19065# Negative sizes have mirror semantics on
81 // OutputDevice. BitmapEx and co. have no idea about that, so
82 // perform that _before_ doing anything with aBitmapEx.
83 BmpMirrorFlags nMirrorFlags(BmpMirrorFlags::NONE);
84 if( aSize.Width() < 0 )
85 {
86 aSize.setWidth( aSize.Width() * -1 );
87 aPoint.AdjustX( -(aSize.Width()) );
88 nMirrorFlags |= BmpMirrorFlags::Horizontal;
89 }
90 if( aSize.Height() < 0 )
91 {
92 aSize.setHeight( aSize.Height() * -1 );
93 aPoint.AdjustY( -(aSize.Height()) );
94 nMirrorFlags |= BmpMirrorFlags::Vertical;
95 }
96
97 if( nMirrorFlags != BmpMirrorFlags::NONE )
98 {
99 aBitmapEx.Mirror( nMirrorFlags );
100 }
101
102 bool bIsJpeg = false, bIsPng = false;
103 if( i_Graphic.GetType() != GraphicType::NONE && i_Graphic.GetBitmapEx() == aBitmapEx )
104 {
105 GfxLinkType eType = i_Graphic.GetGfxLink().GetType();
106 bIsJpeg = (eType == GfxLinkType::NativeJpg);
107 bIsPng = (eType == GfxLinkType::NativePng);
108 }
109
110 // Do not downsample images smaller than 50x50px.
111 const Size aBmpSize(aBitmapEx.GetSizePixel());
112 if (i_rContext.m_nMaxImageResolution > 50 && aBmpSize.getWidth() > 50
113 && aBmpSize.getHeight() > 50)
114 {
115 // do downsampling if necessary
116 const Size aDstSizeTwip( i_pDummyVDev->PixelToLogic(i_pDummyVDev->LogicToPixel(aSize), MapMode(MapUnit::MapTwip)) );
117 const double fBmpPixelX = aBmpSize.Width();
118 const double fBmpPixelY = aBmpSize.Height();
119 const double fMaxPixelX = aDstSizeTwip.Width() * i_rContext.m_nMaxImageResolution / 1440.0;
120 const double fMaxPixelY = aDstSizeTwip.Height() * i_rContext.m_nMaxImageResolution / 1440.0;
121
122 // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance)
123 if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) ||
124 ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) &&
125 ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) )
126 {
127 // do scaling
128 Size aNewBmpSize;
129 const double fBmpWH = fBmpPixelX / fBmpPixelY;
130 const double fMaxWH = fMaxPixelX / fMaxPixelY;
131
132 if( fBmpWH < fMaxWH )
133 {
134 aNewBmpSize.setWidth( FRound( fMaxPixelY * fBmpWH ) );
135 aNewBmpSize.setHeight( FRound( fMaxPixelY ) );
136 }
137 else if( fBmpWH > 0.0 )
138 {
139 aNewBmpSize.setWidth( FRound( fMaxPixelX ) );
140 aNewBmpSize.setHeight( FRound( fMaxPixelX / fBmpWH) );
141 }
142
143 if( aNewBmpSize.Width() && aNewBmpSize.Height() )
144 {
145 // #i121233# Use best quality for PDF exports
146 aBitmapEx.Scale( aNewBmpSize, BmpScaleFlag::BestQuality );
147 }
148 else
149 {
150 aBitmapEx.SetEmpty();
151 }
152 }
153 }
154
155 const Size aSizePixel( aBitmapEx.GetSizePixel() );
156 if ( !(aSizePixel.Width() && aSizePixel.Height()) )
157 return;
158
159 if( m_aContext.ColorMode == PDFWriter::DrawGreyscale )
160 {
161 BmpConversion eConv = BmpConversion::N8BitGreys;
162 int nDepth = aBitmapEx.GetBitmap().GetBitCount();
163 if( nDepth <= 4 )
164 eConv = BmpConversion::N4BitGreys;
165 if( nDepth > 1 )
166 aBitmapEx.Convert( eConv );
167 }
168 bool bUseJPGCompression = !i_rContext.m_bOnlyLosslessCompression;
169 if ( bIsPng || ( aSizePixel.Width() < 32 ) || ( aSizePixel.Height() < 32 ) )
170 bUseJPGCompression = false;
171
172 auto pStrm=std::make_shared<SvMemoryStream>();
173 Bitmap aMask;
174
175 bool bTrueColorJPG = true;
176 if ( bUseJPGCompression )
177 {
178 // TODO this checks could be done much earlier, saving us
179 // from trying conversion & stores before...
180 if ( !aBitmapEx.IsTransparent() )
181 {
182 const auto& rCacheEntry=m_aPDFBmpCache.find(
183 aBitmapEx.GetChecksum());
184 if ( rCacheEntry != m_aPDFBmpCache.end() )
185 {
186 m_rOuterFace.DrawJPGBitmap( *rCacheEntry->second, true, aSizePixel,
187 tools::Rectangle( aPoint, aSize ), aMask, i_Graphic );
188 return;
189 }
190 }
191 sal_uInt32 nZippedFileSize = 0; // sj: we will calculate the filesize of a zipped bitmap
192 if ( !bIsJpeg ) // to determine if jpeg compression is useful
193 {
194 SvMemoryStream aTemp;
195 aTemp.SetCompressMode( aTemp.GetCompressMode() | SvStreamCompressFlags::ZBITMAP );
196 aTemp.SetVersion( SOFFICE_FILEFORMAT_403580 ); // sj: up from version 40 our bitmap stream operator
197 WriteDIBBitmapEx(aBitmapEx, aTemp); // is capable of zlib stream compression
198 nZippedFileSize = aTemp.TellEnd();
199 }
200 if ( aBitmapEx.IsTransparent() )
201 {
202 if ( aBitmapEx.IsAlpha() )
203 aMask = aBitmapEx.GetAlpha().GetBitmap();
204 else
205 aMask = aBitmapEx.GetMask();
206 }
207 Graphic aGraphic(BitmapEx(aBitmapEx.GetBitmap()));
208
209 Sequence< PropertyValue > aFilterData( 2 );
210 aFilterData[ 0 ].Name = "Quality";
211 aFilterData[ 0 ].Value <<= sal_Int32(i_rContext.m_nJPEGQuality);
212 aFilterData[ 1 ].Name = "ColorMode";
213 aFilterData[ 1 ].Value <<= sal_Int32(0);
214
215 try
216 {
217 uno::Reference < io::XStream > xStream = new utl::OStreamWrapper( *pStrm );
218 uno::Reference< io::XSeekable > xSeekable( xStream, UNO_QUERY_THROW );
219 uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
220 uno::Reference< graphic::XGraphicProvider > xGraphicProvider( graphic::GraphicProvider::create(xContext) );
221 uno::Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
222 uno::Reference < io::XOutputStream > xOut( xStream->getOutputStream() );
223 uno::Sequence< beans::PropertyValue > aOutMediaProperties( 3 );
224 aOutMediaProperties[0].Name = "OutputStream";
225 aOutMediaProperties[0].Value <<= xOut;
226 aOutMediaProperties[1].Name = "MimeType";
227 aOutMediaProperties[1].Value <<= OUString("image/jpeg");
228 aOutMediaProperties[2].Name = "FilterData";
229 aOutMediaProperties[2].Value <<= aFilterData;
230 xGraphicProvider->storeGraphic( xGraphic, aOutMediaProperties );
231 xOut->flush();
232 if ( !bIsJpeg && xSeekable->getLength() > nZippedFileSize )
233 {
234 bUseJPGCompression = false;
235 }
236 else
237 {
238 pStrm->Seek( STREAM_SEEK_TO_END((sal_uInt64) 0xFFFFFFFFFFFFFFFFul) );
239
240 xSeekable->seek( 0 );
241 Sequence< PropertyValue > aArgs( 1 );
242 aArgs[ 0 ].Name = "InputStream";
243 aArgs[ 0 ].Value <<= xStream;
244 uno::Reference< XPropertySet > xPropSet( xGraphicProvider->queryGraphicDescriptor( aArgs ) );
245 if ( xPropSet.is() )
246 {
247 sal_Int16 nBitsPerPixel = 24;
248 if ( xPropSet->getPropertyValue("BitsPerPixel") >>= nBitsPerPixel )
249 {
250 bTrueColorJPG = nBitsPerPixel != 8;
251 }
252 }
253 }
254 }
255 catch( uno::Exception& )
256 {
257 bUseJPGCompression = false;
258 }
259 }
260 if ( bUseJPGCompression )
261 {
262 m_rOuterFace.DrawJPGBitmap( *pStrm, bTrueColorJPG, aSizePixel, tools::Rectangle( aPoint, aSize ), aMask, i_Graphic );
263 if (!aBitmapEx.IsTransparent() && bTrueColorJPG)
264 {
265 // Cache last jpeg export
266 m_aPDFBmpCache.insert(
267 {aBitmapEx.GetChecksum(), pStrm});
268 }
269 }
270 else if ( aBitmapEx.IsTransparent() )
271 m_rOuterFace.DrawBitmapEx( aPoint, aSize, aBitmapEx );
272 else
273 m_rOuterFace.DrawBitmap( aPoint, aSize, aBitmapEx.GetBitmap(), i_Graphic );
274
275}
276
277void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevData* i_pOutDevData, const vcl::PDFWriter::PlayMetafileContext& i_rContext, VirtualDevice* pDummyVDev )
278{
279 bool bAssertionFired( false );
280
281 ScopedVclPtr<VirtualDevice> xPrivateDevice;
282 if( ! pDummyVDev )
1
Assuming 'pDummyVDev' is null
2
Taking true branch
283 {
284 xPrivateDevice.disposeAndReset(VclPtr<VirtualDevice>::Create());
3
Calling 'VclPtr::Create'
5
Returned allocated memory
6
Calling implicit destructor for 'VclPtr<VirtualDevice>'
7
Calling '~Reference'
14
Returning from '~Reference'
15
Returning from destructor for 'VclPtr<VirtualDevice>'
285 pDummyVDev = xPrivateDevice.get();
16
Calling 'VclPtr::get'
286 pDummyVDev->EnableOutput( false );
287 pDummyVDev->SetMapMode( i_rMtf.GetPrefMapMode() );
288 }
289 const GDIMetaFile& aMtf( i_rMtf );
290
291 for( sal_uInt32 i = 0, nCount = aMtf.GetActionSize(); i < nCount; )
292 {
293 if ( !i_pOutDevData || !i_pOutDevData->PlaySyncPageAct( m_rOuterFace, i, aMtf ) )
294 {
295 const MetaAction* pAction = aMtf.GetAction( i );
296 const MetaActionType nType = pAction->GetType();
297
298 switch( nType )
299 {
300 case MetaActionType::PIXEL:
301 {
302 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
303 m_rOuterFace.DrawPixel( pA->GetPoint(), pA->GetColor() );
304 }
305 break;
306
307 case MetaActionType::POINT:
308 {
309 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
310 m_rOuterFace.DrawPixel( pA->GetPoint() );
311 }
312 break;
313
314 case MetaActionType::LINE:
315 {
316 const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
317 if ( pA->GetLineInfo().IsDefault() )
318 m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint() );
319 else
320 m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint(), pA->GetLineInfo() );
321 }
322 break;
323
324 case MetaActionType::RECT:
325 {
326 const MetaRectAction* pA = static_cast<const MetaRectAction*>(pAction);
327 m_rOuterFace.DrawRect( pA->GetRect() );
328 }
329 break;
330
331 case MetaActionType::ROUNDRECT:
332 {
333 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
334 m_rOuterFace.DrawRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
335 }
336 break;
337
338 case MetaActionType::ELLIPSE:
339 {
340 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
341 m_rOuterFace.DrawEllipse( pA->GetRect() );
342 }
343 break;
344
345 case MetaActionType::ARC:
346 {
347 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
348 m_rOuterFace.DrawArc( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
349 }
350 break;
351
352 case MetaActionType::PIE:
353 {
354 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
355 m_rOuterFace.DrawPie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
356 }
357 break;
358
359 case MetaActionType::CHORD:
360 {
361 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
362 m_rOuterFace.DrawChord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() );
363 }
364 break;
365
366 case MetaActionType::POLYGON:
367 {
368 const MetaPolygonAction* pA = static_cast<const MetaPolygonAction*>(pAction);
369 m_rOuterFace.DrawPolygon( pA->GetPolygon() );
370 }
371 break;
372
373 case MetaActionType::POLYLINE:
374 {
375 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
376 if ( pA->GetLineInfo().IsDefault() )
377 m_rOuterFace.DrawPolyLine( pA->GetPolygon() );
378 else
379 m_rOuterFace.DrawPolyLine( pA->GetPolygon(), pA->GetLineInfo() );
380 }
381 break;
382
383 case MetaActionType::POLYPOLYGON:
384 {
385 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pAction);
386 m_rOuterFace.DrawPolyPolygon( pA->GetPolyPolygon() );
387 }
388 break;
389
390 case MetaActionType::GRADIENT:
391 {
392 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
393 const Gradient& rGradient = pA->GetGradient();
394 if (lcl_canUsePDFAxialShading(rGradient))
395 {
396 m_rOuterFace.DrawGradient( pA->GetRect(), rGradient );
397 }
398 else
399 {
400 const tools::PolyPolygon aPolyPoly( pA->GetRect() );
401 implWriteGradient( aPolyPoly, rGradient, pDummyVDev, i_rContext );
402 }
403 }
404 break;
405
406 case MetaActionType::GRADIENTEX:
407 {
408 const MetaGradientExAction* pA = static_cast<const MetaGradientExAction*>(pAction);
409 const Gradient& rGradient = pA->GetGradient();
410
411 if (lcl_canUsePDFAxialShading(rGradient))
412 m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), rGradient );
413 else
414 implWriteGradient( pA->GetPolyPolygon(), rGradient, pDummyVDev, i_rContext );
415 }
416 break;
417
418 case MetaActionType::HATCH:
419 {
420 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
421 m_rOuterFace.DrawHatch( pA->GetPolyPolygon(), pA->GetHatch() );
422 }
423 break;
424
425 case MetaActionType::Transparent:
426 {
427 const MetaTransparentAction* pA = static_cast<const MetaTransparentAction*>(pAction);
428 m_rOuterFace.DrawTransparent( pA->GetPolyPolygon(), pA->GetTransparence() );
429 }
430 break;
431
432 case MetaActionType::FLOATTRANSPARENT:
433 {
434 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
435
436 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
437 const Point& rPos = pA->GetPoint();
438 const Size& rSize= pA->GetSize();
439 const Gradient& rTransparenceGradient = pA->GetGradient();
440
441 // special case constant alpha value
442 if( rTransparenceGradient.GetStartColor() == rTransparenceGradient.GetEndColor() )
443 {
444 const Color aTransCol( rTransparenceGradient.GetStartColor() );
445 const sal_uInt16 nTransPercent = aTransCol.GetLuminance() * 100 / 255;
446 m_rOuterFace.BeginTransparencyGroup();
447 playMetafile( aTmpMtf, nullptr, i_rContext, pDummyVDev );
448 m_rOuterFace.EndTransparencyGroup( tools::Rectangle( rPos, rSize ), nTransPercent );
449 }
450 else
451 {
452 const Size aDstSizeTwip( pDummyVDev->PixelToLogic(pDummyVDev->LogicToPixel(rSize), MapMode(MapUnit::MapTwip)) );
453
454 // i#115962# Always use at least 300 DPI for bitmap conversion of transparence gradients,
455 // else the quality is not acceptable (see bugdoc as example)
456 sal_Int32 nMaxBmpDPI(300);
457
458 if( i_rContext.m_nMaxImageResolution > 50 )
459 {
460 if ( nMaxBmpDPI > i_rContext.m_nMaxImageResolution )
461 nMaxBmpDPI = i_rContext.m_nMaxImageResolution;
462 }
463 const sal_Int32 nPixelX = static_cast<sal_Int32>(static_cast<double>(aDstSizeTwip.Width()) * static_cast<double>(nMaxBmpDPI) / 1440.0);
464 const sal_Int32 nPixelY = static_cast<sal_Int32>(static_cast<double>(aDstSizeTwip.Height()) * static_cast<double>(nMaxBmpDPI) / 1440.0);
465 if ( nPixelX && nPixelY )
466 {
467 Size aDstSizePixel( nPixelX, nPixelY );
468 ScopedVclPtrInstance<VirtualDevice> xVDev;
469 if( xVDev->SetOutputSizePixel( aDstSizePixel ) )
470 {
471 Bitmap aPaint, aMask;
472 AlphaMask aAlpha;
473 Point aPoint;
474
475 MapMode aMapMode( pDummyVDev->GetMapMode() );
476 aMapMode.SetOrigin( aPoint );
477 xVDev->SetMapMode( aMapMode );
478 Size aDstSize( xVDev->PixelToLogic( aDstSizePixel ) );
479
480 Point aMtfOrigin( aTmpMtf.GetPrefMapMode().GetOrigin() );
481 if ( aMtfOrigin.X() || aMtfOrigin.Y() )
482 aTmpMtf.Move( -aMtfOrigin.X(), -aMtfOrigin.Y() );
483 double fScaleX = static_cast<double>(aDstSize.Width()) / static_cast<double>(aTmpMtf.GetPrefSize().Width());
484 double fScaleY = static_cast<double>(aDstSize.Height()) / static_cast<double>(aTmpMtf.GetPrefSize().Height());
485 if( fScaleX != 1.0 || fScaleY != 1.0 )
486 aTmpMtf.Scale( fScaleX, fScaleY );
487 aTmpMtf.SetPrefMapMode( aMapMode );
488
489 // create paint bitmap
490 aTmpMtf.WindStart();
491 aTmpMtf.Play( xVDev.get(), aPoint, aDstSize );
492 aTmpMtf.WindStart();
493
494 xVDev->EnableMapMode( false );
495 aPaint = xVDev->GetBitmap( aPoint, aDstSizePixel );
496 xVDev->EnableMapMode();
497
498 // create mask bitmap
499 xVDev->SetLineColor( COL_BLACK );
500 xVDev->SetFillColor( COL_BLACK );
501 xVDev->DrawRect( tools::Rectangle( aPoint, aDstSize ) );
502 xVDev->SetDrawMode( DrawModeFlags::WhiteLine | DrawModeFlags::WhiteFill | DrawModeFlags::WhiteText |
503 DrawModeFlags::WhiteBitmap | DrawModeFlags::WhiteGradient );
504 aTmpMtf.WindStart();
505 aTmpMtf.Play( xVDev.get(), aPoint, aDstSize );
506 aTmpMtf.WindStart();
507 xVDev->EnableMapMode( false );
508 aMask = xVDev->GetBitmap( aPoint, aDstSizePixel );
509 xVDev->EnableMapMode();
510
511 // create alpha mask from gradient
512 xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
513 xVDev->DrawGradient( tools::Rectangle( aPoint, aDstSize ), rTransparenceGradient );
514 xVDev->SetDrawMode( DrawModeFlags::Default );
515 xVDev->EnableMapMode( false );
516 xVDev->DrawMask( aPoint, aDstSizePixel, aMask, COL_WHITE );
517 aAlpha = xVDev->GetBitmap( aPoint, aDstSizePixel );
518
519 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
520 implWriteBitmapEx( rPos, rSize, BitmapEx( aPaint, aAlpha ), aGraphic, pDummyVDev, i_rContext );
521 }
522 }
523 }
524 }
525 break;
526
527 case MetaActionType::EPS:
528 {
529 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
530 const GDIMetaFile& aSubstitute( pA->GetSubstitute() );
531
532 m_rOuterFace.Push();
533 pDummyVDev->Push();
534
535 MapMode aMapMode( aSubstitute.GetPrefMapMode() );
536 Size aOutSize( OutputDevice::LogicToLogic( pA->GetSize(), pDummyVDev->GetMapMode(), aMapMode ) );
537 aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) );
538 aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) );
539 aMapMode.SetOrigin( OutputDevice::LogicToLogic( pA->GetPoint(), pDummyVDev->GetMapMode(), aMapMode ) );
540
541 m_rOuterFace.SetMapMode( aMapMode );
542 pDummyVDev->SetMapMode( aMapMode );
543 playMetafile( aSubstitute, nullptr, i_rContext, pDummyVDev );
544 pDummyVDev->Pop();
545 m_rOuterFace.Pop();
546 }
547 break;
548
549 case MetaActionType::COMMENT:
550 if( ! i_rContext.m_bTransparenciesWereRemoved )
551 {
552 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
553
554 if( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
555 {
556 const MetaGradientExAction* pGradAction = nullptr;
557 bool bDone = false;
558
559 while( !bDone && ( ++i < nCount ) )
560 {
561 pAction = aMtf.GetAction( i );
562
563 if( pAction->GetType() == MetaActionType::GRADIENTEX )
564 pGradAction = static_cast<const MetaGradientExAction*>(pAction);
565 else if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
566 ( static_cast<const MetaCommentAction*>(pAction)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END")) )
567 {
568 bDone = true;
569 }
570 }
571
572 if( pGradAction )
573 {
574 if (lcl_canUsePDFAxialShading(pGradAction->GetGradient()))
575 {
576 m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() );
577 }
578 else
579 {
580 implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext );
581 }
582 }
583 }
584 else
585 {
586 const sal_uInt8* pData = pA->GetData();
587 if ( pData )
588 {
589 SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pData), pA->GetDataSize(), StreamMode::READ );
590 bool bSkipSequence = false;
591 OString sSeqEnd;
592
593 if( pA->GetComment() == "XPATHSTROKE_SEQ_BEGIN" )
594 {
595 sSeqEnd = OString("XPATHSTROKE_SEQ_END");
596 SvtGraphicStroke aStroke;
597 ReadSvtGraphicStroke( aMemStm, aStroke );
598
599 tools::Polygon aPath;
600 aStroke.getPath( aPath );
601
602 tools::PolyPolygon aStartArrow;
603 tools::PolyPolygon aEndArrow;
604 double fTransparency( aStroke.getTransparency() );
605 double fStrokeWidth( aStroke.getStrokeWidth() );
606 SvtGraphicStroke::DashArray aDashArray;
607
608 aStroke.getStartArrow( aStartArrow );
609 aStroke.getEndArrow( aEndArrow );
610 aStroke.getDashArray( aDashArray );
611
612 bSkipSequence = true;
613 if ( aStartArrow.Count() || aEndArrow.Count() )
614 bSkipSequence = false;
615 if ( !aDashArray.empty() && ( fStrokeWidth != 0.0 ) && ( fTransparency == 0.0 ) )
616 bSkipSequence = false;
617 if ( bSkipSequence )
618 {
619 PDFWriter::ExtLineInfo aInfo;
620 aInfo.m_fLineWidth = fStrokeWidth;
621 aInfo.m_fTransparency = fTransparency;
622 aInfo.m_fMiterLimit = aStroke.getMiterLimit();
623 switch( aStroke.getCapType() )
624 {
625 default:
626 case SvtGraphicStroke::capButt: aInfo.m_eCap = PDFWriter::capButt;break;
627 case SvtGraphicStroke::capRound: aInfo.m_eCap = PDFWriter::capRound;break;
628 case SvtGraphicStroke::capSquare: aInfo.m_eCap = PDFWriter::capSquare;break;
629 }
630 switch( aStroke.getJoinType() )
631 {
632 default:
633 case SvtGraphicStroke::joinMiter: aInfo.m_eJoin = PDFWriter::joinMiter;break;
634 case SvtGraphicStroke::joinRound: aInfo.m_eJoin = PDFWriter::joinRound;break;
635 case SvtGraphicStroke::joinBevel: aInfo.m_eJoin = PDFWriter::joinBevel;break;
636 case SvtGraphicStroke::joinNone:
637 aInfo.m_eJoin = PDFWriter::joinMiter;
638 aInfo.m_fMiterLimit = 0.0;
639 break;
640 }
641 aInfo.m_aDashArray = aDashArray;
642
643 if(SvtGraphicStroke::joinNone == aStroke.getJoinType()
644 && fStrokeWidth > 0.0)
645 {
646 // emulate no edge rounding by handling single edges
647 const sal_uInt16 nPoints(aPath.GetSize());
648 const bool bCurve(aPath.HasFlags());
649
650 for(sal_uInt16 a(0); a + 1 < nPoints; a++)
651 {
652 if(bCurve
653 && PolyFlags::Normal != aPath.GetFlags(a + 1)
654 && a + 2 < nPoints
655 && PolyFlags::Normal != aPath.GetFlags(a + 2)
656 && a + 3 < nPoints)
657 {
658 const tools::Polygon aSnippet(4,
659 aPath.GetConstPointAry() + a,
660 aPath.GetConstFlagAry() + a);
661 m_rOuterFace.DrawPolyLine( aSnippet, aInfo );
662 a += 2;
663 }
664 else
665 {
666 const tools::Polygon aSnippet(2,
667 aPath.GetConstPointAry() + a);
668 m_rOuterFace.DrawPolyLine( aSnippet, aInfo );
669 }
670 }
671 }
672 else
673 {
674 m_rOuterFace.DrawPolyLine( aPath, aInfo );
675 }
676 }
677 }
678 else if ( pA->GetComment() == "XPATHFILL_SEQ_BEGIN" )
679 {
680 sSeqEnd = OString("XPATHFILL_SEQ_END");
681 SvtGraphicFill aFill;
682 ReadSvtGraphicFill( aMemStm, aFill );
683
684 if ( ( aFill.getFillType() == SvtGraphicFill::fillSolid ) && ( aFill.getFillRule() == SvtGraphicFill::fillEvenOdd ) )
685 {
686 double fTransparency = aFill.getTransparency();
687 if ( fTransparency == 0.0 )
688 {
689 tools::PolyPolygon aPath;
690 aFill.getPath( aPath );
691
692 bSkipSequence = true;
693 m_rOuterFace.DrawPolyPolygon( aPath );
694 }
695 else if ( fTransparency == 1.0 )
696 bSkipSequence = true;
697 }
698 }
699 if ( bSkipSequence )
700 {
701 while( ++i < nCount )
702 {
703 pAction = aMtf.GetAction( i );
704 if ( pAction->GetType() == MetaActionType::COMMENT )
705 {
706 OString sComment( static_cast<const MetaCommentAction*>(pAction)->GetComment() );
707 if (sComment == sSeqEnd)
708 break;
709 }
710 // #i44496#
711 // the replacement action for stroke is a filled rectangle
712 // the set fillcolor of the replacement is part of the graphics
713 // state and must not be skipped
714 else if( pAction->GetType() == MetaActionType::FILLCOLOR )
715 {
716 const MetaFillColorAction* pMA = static_cast<const MetaFillColorAction*>(pAction);
717 if( pMA->IsSetting() )
718 m_rOuterFace.SetFillColor( pMA->GetColor() );
719 else
720 m_rOuterFace.SetFillColor();
721 }
722 }
723 }
724 }
725 }
726 }
727 break;
728
729 case MetaActionType::BMP:
730 {
731 const MetaBmpAction* pA = static_cast<const MetaBmpAction*>(pAction);
732 BitmapEx aBitmapEx( pA->GetBitmap() );
733 Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
734 aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
735 if( ! ( aSize.Width() && aSize.Height() ) )
736 aSize = pDummyVDev->PixelToLogic( aBitmapEx.GetSizePixel() );
737
738 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
739 implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, aGraphic, pDummyVDev, i_rContext );
740 }
741 break;
742
743 case MetaActionType::BMPSCALE:
744 {
745 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
746 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
747 implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), BitmapEx( pA->GetBitmap() ), aGraphic, pDummyVDev, i_rContext );
748 }
749 break;
750
751 case MetaActionType::BMPSCALEPART:
752 {
753 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
754 BitmapEx aBitmapEx( pA->GetBitmap() );
755 aBitmapEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
756 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
757 implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, aGraphic, pDummyVDev, i_rContext );
758 }
759 break;
760
761 case MetaActionType::BMPEX:
762 {
763 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction*>(pAction);
764 const BitmapEx& aBitmapEx( pA->GetBitmapEx() );
765 Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(),
766 aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) );
767 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
768 implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, aGraphic, pDummyVDev, i_rContext );
769 }
770 break;
771
772 case MetaActionType::BMPEXSCALE:
773 {
774 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
775 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
776 implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), pA->GetBitmapEx(), aGraphic, pDummyVDev, i_rContext );
777 }
778 break;
779
780 case MetaActionType::BMPEXSCALEPART:
781 {
782 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
783 BitmapEx aBitmapEx( pA->GetBitmapEx() );
784 aBitmapEx.Crop( tools::Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) );
785 Graphic aGraphic = i_pOutDevData ? i_pOutDevData->GetCurrentGraphic() : Graphic();
786 implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, aGraphic, pDummyVDev, i_rContext );
787 }
788 break;
789
790 case MetaActionType::MASK:
791 case MetaActionType::MASKSCALE:
792 case MetaActionType::MASKSCALEPART:
793 {
794 SAL_WARN( "vcl", "MetaMask...Action not supported yet" )do { if (true) { 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
() << "MetaMask...Action not supported yet") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "794" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "MetaMask...Action not supported yet")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MetaMask...Action not supported yet"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "794" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "MetaMask...Action not supported yet") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "794" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "MetaMask...Action not supported yet")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "MetaMask...Action not supported yet"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "794" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
795 }
796 break;
797
798 case MetaActionType::TEXT:
799 {
800 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
801 m_rOuterFace.DrawText( pA->GetPoint(), pA->GetText().copy( pA->GetIndex(), std::min<sal_Int32>(pA->GetText().getLength() - pA->GetIndex(), pA->GetLen()) ) );
802 }
803 break;
804
805 case MetaActionType::TEXTRECT:
806 {
807 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
808 m_rOuterFace.DrawText( pA->GetRect(), pA->GetText(), pA->GetStyle() );
809 }
810 break;
811
812 case MetaActionType::TEXTARRAY:
813 {
814 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
815 m_rOuterFace.DrawTextArray( pA->GetPoint(), pA->GetText(), pA->GetDXArray(), pA->GetIndex(), pA->GetLen() );
816 }
817 break;
818
819 case MetaActionType::STRETCHTEXT:
820 {
821 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
822 m_rOuterFace.DrawStretchText( pA->GetPoint(), pA->GetWidth(), pA->GetText(), pA->GetIndex(), pA->GetLen() );
823 }
824 break;
825
826 case MetaActionType::TEXTLINE:
827 {
828 const MetaTextLineAction* pA = static_cast<const MetaTextLineAction*>(pAction);
829 m_rOuterFace.DrawTextLine( pA->GetStartPoint(), pA->GetWidth(), pA->GetStrikeout(), pA->GetUnderline(), pA->GetOverline() );
830
831 }
832 break;
833
834 case MetaActionType::CLIPREGION:
835 {
836 const MetaClipRegionAction* pA = static_cast<const MetaClipRegionAction*>(pAction);
837
838 if( pA->IsClipping() )
839 {
840 if( pA->GetRegion().IsEmpty() )
841 m_rOuterFace.SetClipRegion( basegfx::B2DPolyPolygon() );
842 else
843 {
844 const vcl::Region& aReg( pA->GetRegion() );
845 m_rOuterFace.SetClipRegion( aReg.GetAsB2DPolyPolygon() );
846 }
847 }
848 else
849 m_rOuterFace.SetClipRegion();
850 }
851 break;
852
853 case MetaActionType::ISECTRECTCLIPREGION:
854 {
855 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pAction);
856 m_rOuterFace.IntersectClipRegion( pA->GetRect() );
857 }
858 break;
859
860 case MetaActionType::ISECTREGIONCLIPREGION:
861 {
862 const MetaISectRegionClipRegionAction* pA = static_cast<const MetaISectRegionClipRegionAction*>(pAction);
863 const vcl::Region& aReg( pA->GetRegion() );
864 m_rOuterFace.IntersectClipRegion( aReg.GetAsB2DPolyPolygon() );
865 }
866 break;
867
868 case MetaActionType::MOVECLIPREGION:
869 {
870 const MetaMoveClipRegionAction* pA = static_cast<const MetaMoveClipRegionAction*>(pAction);
871 m_rOuterFace.MoveClipRegion( pA->GetHorzMove(), pA->GetVertMove() );
872 }
873 break;
874
875 case MetaActionType::MAPMODE:
876 {
877 const_cast< MetaAction* >( pAction )->Execute( pDummyVDev );
878 m_rOuterFace.SetMapMode( pDummyVDev->GetMapMode() );
879 }
880 break;
881
882 case MetaActionType::LINECOLOR:
883 {
884 const MetaLineColorAction* pA = static_cast<const MetaLineColorAction*>(pAction);
885
886 if( pA->IsSetting() )
887 m_rOuterFace.SetLineColor( pA->GetColor() );
888 else
889 m_rOuterFace.SetLineColor();
890 }
891 break;
892
893 case MetaActionType::FILLCOLOR:
894 {
895 const MetaFillColorAction* pA = static_cast<const MetaFillColorAction*>(pAction);
896
897 if( pA->IsSetting() )
898 m_rOuterFace.SetFillColor( pA->GetColor() );
899 else
900 m_rOuterFace.SetFillColor();
901 }
902 break;
903
904 case MetaActionType::TEXTLINECOLOR:
905 {
906 const MetaTextLineColorAction* pA = static_cast<const MetaTextLineColorAction*>(pAction);
907
908 if( pA->IsSetting() )
909 m_rOuterFace.SetTextLineColor( pA->GetColor() );
910 else
911 m_rOuterFace.SetTextLineColor();
912 }
913 break;
914
915 case MetaActionType::OVERLINECOLOR:
916 {
917 const MetaOverlineColorAction* pA = static_cast<const MetaOverlineColorAction*>(pAction);
918
919 if( pA->IsSetting() )
920 m_rOuterFace.SetOverlineColor( pA->GetColor() );
921 else
922 m_rOuterFace.SetOverlineColor();
923 }
924 break;
925
926 case MetaActionType::TEXTFILLCOLOR:
927 {
928 const MetaTextFillColorAction* pA = static_cast<const MetaTextFillColorAction*>(pAction);
929
930 if( pA->IsSetting() )
931 m_rOuterFace.SetTextFillColor( pA->GetColor() );
932 else
933 m_rOuterFace.SetTextFillColor();
934 }
935 break;
936
937 case MetaActionType::TEXTCOLOR:
938 {
939 const MetaTextColorAction* pA = static_cast<const MetaTextColorAction*>(pAction);
940 m_rOuterFace.SetTextColor( pA->GetColor() );
941 }
942 break;
943
944 case MetaActionType::TEXTALIGN:
945 {
946 const MetaTextAlignAction* pA = static_cast<const MetaTextAlignAction*>(pAction);
947 m_rOuterFace.SetTextAlign( pA->GetTextAlign() );
948 }
949 break;
950
951 case MetaActionType::FONT:
952 {
953 const MetaFontAction* pA = static_cast<const MetaFontAction*>(pAction);
954 m_rOuterFace.SetFont( pA->GetFont() );
955 }
956 break;
957
958 case MetaActionType::PUSH:
959 {
960 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pAction);
961
962 pDummyVDev->Push( pA->GetFlags() );
963 m_rOuterFace.Push( pA->GetFlags() );
964 }
965 break;
966
967 case MetaActionType::POP:
968 {
969 pDummyVDev->Pop();
970 m_rOuterFace.Pop();
971 }
972 break;
973
974 case MetaActionType::LAYOUTMODE:
975 {
976 const MetaLayoutModeAction* pA = static_cast<const MetaLayoutModeAction*>(pAction);
977 m_rOuterFace.SetLayoutMode( pA->GetLayoutMode() );
978 }
979 break;
980
981 case MetaActionType::TEXTLANGUAGE:
982 {
983 const MetaTextLanguageAction* pA = static_cast<const MetaTextLanguageAction*>(pAction);
984 m_rOuterFace.SetDigitLanguage( pA->GetTextLanguage() );
985 }
986 break;
987
988 case MetaActionType::WALLPAPER:
989 {
990 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pAction);
991 m_rOuterFace.DrawWallpaper( pA->GetRect(), pA->GetWallpaper() );
992 }
993 break;
994
995 case MetaActionType::RASTEROP:
996 {
997 // !!! >>> we don't want to support this actions
998 }
999 break;
1000
1001 case MetaActionType::REFPOINT:
1002 {
1003 // !!! >>> we don't want to support this actions
1004 }
1005 break;
1006
1007 default:
1008 // #i24604# Made assertion fire only once per
1009 // metafile. The asserted actions here are all
1010 // deprecated
1011 if( !bAssertionFired )
1012 {
1013 bAssertionFired = true;
1014 SAL_WARN( "vcl", "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered " << static_cast<int>(nType) )do { if (true) { 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
() << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1014" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType)), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType); ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1014" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType)) == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1014" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType)), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered "
<< static_cast<int>(nType); ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1014" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1015 }
1016 break;
1017 }
1018 i++;
1019 }
1020 }
1021}
1022
1023// Encryption methods
1024
1025/* a crutch to transport a ::comphelper::Hash safely though UNO API
1026 this is needed for the PDF export dialog, which otherwise would have to pass
1027 clear text passwords down till they can be used in PDFWriter. Unfortunately
1028 the MD5 sum of the password (which is needed to create the PDF encryption key)
1029 is not sufficient, since an MD5 digest cannot be created in an arbitrary state
1030 which would be needed in PDFWriterImpl::computeEncryptionKey.
1031*/
1032class EncHashTransporter : public cppu::WeakImplHelper < css::beans::XMaterialHolder >
1033{
1034 ::std::unique_ptr<::comphelper::Hash> m_pDigest;
1035 sal_IntPtr maID;
1036 std::vector< sal_uInt8 > maOValue;
1037
1038 static std::map< sal_IntPtr, EncHashTransporter* > sTransporters;
1039public:
1040 EncHashTransporter()
1041 : m_pDigest(new ::comphelper::Hash(::comphelper::HashType::MD5))
1042 {
1043 maID = reinterpret_cast< sal_IntPtr >(this);
1044 while( sTransporters.find( maID ) != sTransporters.end() ) // paranoia mode
1045 maID++;
1046 sTransporters[ maID ] = this;
1047 }
1048
1049 virtual ~EncHashTransporter() override
1050 {
1051 sTransporters.erase( maID );
1052 SAL_INFO( "vcl", "EncHashTransporter freed" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "EncHashTransporter freed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1052" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "EncHashTransporter freed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"EncHashTransporter freed"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1052" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "EncHashTransporter freed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1052" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "EncHashTransporter freed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"EncHashTransporter freed"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1052" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1053 }
1054
1055 ::comphelper::Hash* getUDigest() { return m_pDigest.get(); };
1056 std::vector< sal_uInt8 >& getOValue() { return maOValue; }
1057 void invalidate()
1058 {
1059 m_pDigest.reset();
1060 }
1061
1062 // XMaterialHolder
1063 virtual uno::Any SAL_CALL getMaterial() override
1064 {
1065 return uno::makeAny( sal_Int64(maID) );
1066 }
1067
1068 static EncHashTransporter* getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& );
1069
1070};
1071
1072std::map< sal_IntPtr, EncHashTransporter* > EncHashTransporter::sTransporters;
1073
1074EncHashTransporter* EncHashTransporter::getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& xRef )
1075{
1076 EncHashTransporter* pResult = nullptr;
1077 if( xRef.is() )
1078 {
1079 uno::Any aMat( xRef->getMaterial() );
1080 sal_Int64 nMat = 0;
1081 if( aMat >>= nMat )
1082 {
1083 std::map< sal_IntPtr, EncHashTransporter* >::iterator it = sTransporters.find( static_cast<sal_IntPtr>(nMat) );
1084 if( it != sTransporters.end() )
1085 pResult = it->second;
1086 }
1087 }
1088 return pResult;
1089}
1090
1091void PDFWriterImpl::checkAndEnableStreamEncryption( sal_Int32 nObject )
1092{
1093 if( !m_aContext.Encryption.Encrypt() )
1094 return;
1095
1096 m_bEncryptThisStream = true;
1097 sal_Int32 i = m_nKeyLength;
1098 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>(nObject);
1099 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 8 );
1100 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 16 );
1101 // the other location of m_nEncryptionKey is already set to 0, our fixed generation number
1102 // do the MD5 hash
1103 ::std::vector<unsigned char> const nMD5Sum(::comphelper::Hash::calculateHash(
1104 m_aContext.Encryption.EncryptionKey.data(), i+2, ::comphelper::HashType::MD5));
1105 // the i+2 to take into account the generation number, always zero
1106 // initialize the RC4 with the key
1107 // key length: see algorithm 3.1, step 4: (N+5) max 16
1108 rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), m_nRC4KeyLength, nullptr, 0 );
1109}
1110
1111void PDFWriterImpl::enableStringEncryption( sal_Int32 nObject )
1112{
1113 if( !m_aContext.Encryption.Encrypt() )
1114 return;
1115
1116 sal_Int32 i = m_nKeyLength;
1117 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>(nObject);
1118 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 8 );
1119 m_aContext.Encryption.EncryptionKey[i++] = static_cast<sal_uInt8>( nObject >> 16 );
1120 // the other location of m_nEncryptionKey is already set to 0, our fixed generation number
1121 // do the MD5 hash
1122 // the i+2 to take into account the generation number, always zero
1123 ::std::vector<unsigned char> const nMD5Sum(::comphelper::Hash::calculateHash(
1124 m_aContext.Encryption.EncryptionKey.data(), i+2, ::comphelper::HashType::MD5));
1125 // initialize the RC4 with the key
1126 // key length: see algorithm 3.1, step 4: (N+5) max 16
1127 rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum.data(), m_nRC4KeyLength, nullptr, 0 );
1128}
1129
1130/* init the encryption engine
11311. init the document id, used both for building the document id and for building the encryption key(s)
11322. build the encryption key following algorithms described in the PDF specification
1133 */
1134uno::Reference< beans::XMaterialHolder > PDFWriterImpl::initEncryption( const OUString& i_rOwnerPassword,
1135 const OUString& i_rUserPassword
1136 )
1137{
1138 uno::Reference< beans::XMaterialHolder > xResult;
1139 if( !i_rOwnerPassword.isEmpty() || !i_rUserPassword.isEmpty() )
1140 {
1141 EncHashTransporter* pTransporter = new EncHashTransporter;
1142 xResult = pTransporter;
1143
1144 // get padded passwords
1145 sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE];
1146 padPassword( i_rOwnerPassword.isEmpty() ? i_rUserPassword : i_rOwnerPassword, aPadOPW );
1147 padPassword( i_rUserPassword, aPadUPW );
1148
1149 if( computeODictionaryValue( aPadOPW, aPadUPW, pTransporter->getOValue(), SECUR_128BIT_KEY ) )
1150 {
1151 pTransporter->getUDigest()->update(aPadUPW, ENCRYPTED_PWD_SIZE);
1152 }
1153 else
1154 xResult.clear();
1155
1156 // trash temporary padded cleartext PWDs
1157 rtl_secureZeroMemory (aPadOPW, sizeof(aPadOPW));
1158 rtl_secureZeroMemory (aPadUPW, sizeof(aPadUPW));
1159 }
1160 return xResult;
1161}
1162
1163bool PDFWriterImpl::prepareEncryption( const uno::Reference< beans::XMaterialHolder >& xEnc )
1164{
1165 bool bSuccess = false;
1166 EncHashTransporter* pTransporter = EncHashTransporter::getEncHashTransporter( xEnc );
1167 if( pTransporter )
1168 {
1169 sal_Int32 nKeyLength = 0, nRC4KeyLength = 0;
1170 sal_Int32 nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, nKeyLength, nRC4KeyLength );
1171 m_aContext.Encryption.OValue = pTransporter->getOValue();
1172 bSuccess = computeUDictionaryValue( pTransporter, m_aContext.Encryption, nKeyLength, nAccessPermissions );
1173 }
1174 if( ! bSuccess )
1175 {
1176 m_aContext.Encryption.OValue.clear();
1177 m_aContext.Encryption.UValue.clear();
1178 m_aContext.Encryption.EncryptionKey.clear();
1179 }
1180 return bSuccess;
1181}
1182
1183sal_Int32 PDFWriterImpl::computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties,
1184 sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength )
1185{
1186 /*
1187 2) compute the access permissions, in numerical form
1188
1189 the default value depends on the revision 2 (40 bit) or 3 (128 bit security):
1190 - for 40 bit security the unused bit must be set to 1, since they are not used
1191 - for 128 bit security the same bit must be preset to 0 and set later if needed
1192 according to the table 3.15, pdf v 1.4 */
1193 sal_Int32 nAccessPermissions = 0xfffff0c0;
1194
1195 o_rKeyLength = SECUR_128BIT_KEY;
1196 o_rRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16,
1197 // thus maximum permitted value is 16
1198
1199 nAccessPermissions |= ( i_rProperties.CanPrintTheDocument ) ? 1 << 2 : 0;
1200 nAccessPermissions |= ( i_rProperties.CanModifyTheContent ) ? 1 << 3 : 0;
1201 nAccessPermissions |= ( i_rProperties.CanCopyOrExtract ) ? 1 << 4 : 0;
1202 nAccessPermissions |= ( i_rProperties.CanAddOrModify ) ? 1 << 5 : 0;
1203 nAccessPermissions |= ( i_rProperties.CanFillInteractive ) ? 1 << 8 : 0;
1204 nAccessPermissions |= ( i_rProperties.CanExtractForAccessibility ) ? 1 << 9 : 0;
1205 nAccessPermissions |= ( i_rProperties.CanAssemble ) ? 1 << 10 : 0;
1206 nAccessPermissions |= ( i_rProperties.CanPrintFull ) ? 1 << 11 : 0;
1207 return nAccessPermissions;
1208}
1209
1210/*************************************************************
1211begin i12626 methods
1212
1213Implements Algorithm 3.2, step 1 only
1214*/
1215void PDFWriterImpl::padPassword( const OUString& i_rPassword, sal_uInt8* o_pPaddedPW )
1216{
1217 // get ansi-1252 version of the password string CHECKIT ! i12626
1218 OString aString( OUStringToOString( i_rPassword, RTL_TEXTENCODING_MS_1252(((rtl_TextEncoding) 1)) ) );
1219
1220 //copy the string to the target
1221 sal_Int32 nToCopy = ( aString.getLength() < ENCRYPTED_PWD_SIZE ) ? aString.getLength() : ENCRYPTED_PWD_SIZE;
1222 sal_Int32 nCurrentChar;
1223
1224 for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ )
1225 o_pPaddedPW[nCurrentChar] = static_cast<sal_uInt8>( aString[nCurrentChar] );
1226
1227 //pad it with standard byte string
1228 sal_Int32 i,y;
1229 for( i = nCurrentChar, y = 0 ; i < ENCRYPTED_PWD_SIZE; i++, y++ )
1230 o_pPaddedPW[i] = s_nPadString[y];
1231}
1232
1233/**********************************
1234Algorithm 3.2 Compute the encryption key used
1235
1236step 1 should already be done before calling, the paThePaddedPassword parameter should contain
1237the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter,
1238it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used
1239
1240TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec.
1241
1242*/
1243bool PDFWriterImpl::computeEncryptionKey( EncHashTransporter* i_pTransporter, vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, sal_Int32 i_nAccessPermissions )
1244{
1245 bool bSuccess = true;
1246 ::std::vector<unsigned char> nMD5Sum;
1247
1248 // transporter contains an MD5 digest with the padded user password already
1249 ::comphelper::Hash *const pDigest = i_pTransporter->getUDigest();
1250 if (pDigest)
1251 {
1252 //step 3
1253 if( ! io_rProperties.OValue.empty() )
1254 pDigest->update(io_rProperties.OValue.data(), io_rProperties.OValue.size());
1255 else
1256 bSuccess = false;
1257 //Step 4
1258 sal_uInt8 nPerm[4];
1259
1260 nPerm[0] = static_cast<sal_uInt8>(i_nAccessPermissions);
1261 nPerm[1] = static_cast<sal_uInt8>( i_nAccessPermissions >> 8 );
1262 nPerm[2] = static_cast<sal_uInt8>( i_nAccessPermissions >> 16 );
1263 nPerm[3] = static_cast<sal_uInt8>( i_nAccessPermissions >> 24 );
1264
1265 pDigest->update(nPerm, sizeof(nPerm));
1266
1267 //step 5, get the document ID, binary form
1268 pDigest->update(io_rProperties.DocumentIdentifier.data(), io_rProperties.DocumentIdentifier.size());
1269 //get the digest
1270 nMD5Sum = pDigest->finalize();
1271
1272 //step 6, only if 128 bit
1273 for (sal_Int32 i = 0; i < 50; i++)
1274 {
1275 nMD5Sum = ::comphelper::Hash::calculateHash(nMD5Sum.data(), nMD5Sum.size(), ::comphelper::HashType::MD5);
1276 }
1277 }
1278 else
1279 bSuccess = false;
1280
1281 i_pTransporter->invalidate();
1282
1283 //Step 7
1284 if( bSuccess )
1285 {
1286 io_rProperties.EncryptionKey.resize( MAXIMUM_RC4_KEY_LENGTH );
1287 for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ )
1288 io_rProperties.EncryptionKey[i] = nMD5Sum[i];
1289 }
1290 else
1291 io_rProperties.EncryptionKey.clear();
1292
1293 return bSuccess;
1294}
1295
1296/**********************************
1297Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member
1298the step numbers down here correspond to the ones in PDF v.1.4 specification
1299*/
1300bool PDFWriterImpl::computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword,
1301 const sal_uInt8* i_pPaddedUserPassword,
1302 std::vector< sal_uInt8 >& io_rOValue,
1303 sal_Int32 i_nKeyLength
1304 )
1305{
1306 bool bSuccess = true;
1307
1308 io_rOValue.resize( ENCRYPTED_PWD_SIZE );
1309
1310 rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1311 if (aCipher)
1312 {
1313 //step 1 already done, data is in i_pPaddedOwnerPassword
1314 //step 2
1315
1316 ::std::vector<unsigned char> nMD5Sum(::comphelper::Hash::calculateHash(
1317 i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE, ::comphelper::HashType::MD5));
1318 //step 3, only if 128 bit
1319 if (i_nKeyLength == SECUR_128BIT_KEY)
1320 {
1321 sal_Int32 i;
1322 for (i = 0; i < 50; i++)
1323 {
1324 nMD5Sum = ::comphelper::Hash::calculateHash(nMD5Sum.data(), nMD5Sum.size(), ::comphelper::HashType::MD5);
1325 }
1326 }
1327 //Step 4, the key is in nMD5Sum
1328 //step 5 already done, data is in i_pPaddedUserPassword
1329 //step 6
1330 if (rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1331 nMD5Sum.data(), i_nKeyLength , nullptr, 0 )
1332 == rtl_Cipher_E_None)
1333 {
1334 // encrypt the user password using the key set above
1335 rtl_cipher_encodeARCFOUR( aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted
1336 io_rOValue.data(), sal_Int32(io_rOValue.size()) ); //encrypted data
1337 //Step 7, only if 128 bit
1338 if( i_nKeyLength == SECUR_128BIT_KEY )
1339 {
1340 sal_uInt32 i;
1341 size_t y;
1342 sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key
1343
1344 for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
1345 {
1346 for( y = 0; y < sizeof( nLocalKey ); y++ )
1347 nLocalKey[y] = static_cast<sal_uInt8>( nMD5Sum[y] ^ i );
1348
1349 if (rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1350 nLocalKey, SECUR_128BIT_KEY, nullptr, 0 ) //destination data area, on init can be NULL
1351 != rtl_Cipher_E_None)
1352 {
1353 bSuccess = false;
1354 break;
1355 }
1356 rtl_cipher_encodeARCFOUR( aCipher, io_rOValue.data(), sal_Int32(io_rOValue.size()), // the data to be encrypted
1357 io_rOValue.data(), sal_Int32(io_rOValue.size()) ); // encrypted data, can be the same as the input, encrypt "in place"
1358 //step 8, store in class data member
1359 }
1360 }
1361 }
1362 else
1363 bSuccess = false;
1364 }
1365 else
1366 bSuccess = false;
1367
1368 if( aCipher )
1369 rtl_cipher_destroyARCFOUR( aCipher );
1370
1371 if( ! bSuccess )
1372 io_rOValue.clear();
1373 return bSuccess;
1374}
1375
1376/**********************************
1377Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit)
1378*/
1379bool PDFWriterImpl::computeUDictionaryValue( EncHashTransporter* i_pTransporter,
1380 vcl::PDFWriter::PDFEncryptionProperties& io_rProperties,
1381 sal_Int32 i_nKeyLength,
1382 sal_Int32 i_nAccessPermissions
1383 )
1384{
1385 bool bSuccess = true;
1386
1387 io_rProperties.UValue.resize( ENCRYPTED_PWD_SIZE );
1388
1389 ::comphelper::Hash aDigest(::comphelper::HashType::MD5);
1390 rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream );
1391 if (aCipher)
1392 {
1393 //step 1, common to both 3.4 and 3.5
1394 if( computeEncryptionKey( i_pTransporter, io_rProperties, i_nAccessPermissions ) )
1395 {
1396 // prepare encryption key for object
1397 for( sal_Int32 i = i_nKeyLength, y = 0; y < 5 ; y++ )
1398 io_rProperties.EncryptionKey[i++] = 0;
1399
1400 //or 3.5, for 128 bit security
1401 //step6, initialize the last 16 bytes of the encrypted user password to 0
1402 for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++)
1403 io_rProperties.UValue[i] = 0;
1404 //steps 2 and 3
1405 aDigest.update(s_nPadString, sizeof(s_nPadString));
1406 aDigest.update(io_rProperties.DocumentIdentifier.data(), io_rProperties.DocumentIdentifier.size());
1407
1408 ::std::vector<unsigned char> const nMD5Sum(aDigest.finalize());
1409 //Step 4
1410 rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1411 io_rProperties.EncryptionKey.data(), SECUR_128BIT_KEY, nullptr, 0 ); //destination data area
1412 rtl_cipher_encodeARCFOUR( aCipher, nMD5Sum.data(), nMD5Sum.size(), // the data to be encrypted
1413 io_rProperties.UValue.data(), SECUR_128BIT_KEY ); //encrypted data, stored in class data member
1414 //step 5
1415 sal_uInt32 i;
1416 size_t y;
1417 sal_uInt8 nLocalKey[SECUR_128BIT_KEY];
1418
1419 for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1
1420 {
1421 for( y = 0; y < sizeof( nLocalKey ) ; y++ )
1422 nLocalKey[y] = static_cast<sal_uInt8>( io_rProperties.EncryptionKey[y] ^ i );
1423
1424 rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode,
1425 nLocalKey, SECUR_128BIT_KEY, // key and key length
1426 nullptr, 0 ); //destination data area, on init can be NULL
1427 rtl_cipher_encodeARCFOUR( aCipher, io_rProperties.UValue.data(), SECUR_128BIT_KEY, // the data to be encrypted
1428 io_rProperties.UValue.data(), SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place"
1429 }
1430 }
1431 else
1432 bSuccess = false;
1433 }
1434 else
1435 bSuccess = false;
1436
1437 if( aCipher )
1438 rtl_cipher_destroyARCFOUR( aCipher );
1439
1440 if( ! bSuccess )
1441 io_rProperties.UValue.clear();
1442 return bSuccess;
1443}
1444
1445/* end i12626 methods */
1446
1447const long unsetRun[256] =
1448{
1449 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */
1450 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */
1451 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */
1452 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */
1453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
1454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */
1455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
1456 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */
1457 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
1458 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
1459 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
1460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
1461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
1462 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
1463 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
1464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */
1465};
1466
1467const long setRun[256] =
1468{
1469 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */
1470 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
1471 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
1472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
1473 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
1474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
1475 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */
1476 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
1477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */
1478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */
1479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */
1480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */
1481 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */
1482 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */
1483 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */
1484 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */
1485};
1486
1487static bool isSet( const Scanline i_pLine, long i_nIndex )
1488{
1489 return (i_pLine[ i_nIndex/8 ] & (0x80 >> (i_nIndex&7))) != 0;
1490}
1491
1492static long findBitRunImpl( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet )
1493{
1494 long nIndex = i_nStartIndex;
1495 if( nIndex < i_nW )
1496 {
1497 const sal_uInt8 * pByte = i_pLine + (nIndex/8);
1498 sal_uInt8 nByte = *pByte;
1499
1500 // run up to byte boundary
1501 long nBitInByte = (nIndex & 7);
1502 if( nBitInByte )
1503 {
1504 sal_uInt8 nMask = 0x80 >> nBitInByte;
1505 while( nBitInByte != 8 )
1506 {
1507 if( (nByte & nMask) != (i_bSet ? nMask : 0) )
1508 return std::min(nIndex, i_nW);
1509 nMask = nMask >> 1;
1510 nBitInByte++;
1511 nIndex++;
1512 }
1513 if( nIndex < i_nW )
1514 {
1515 pByte++;
1516 nByte = *pByte;
1517 }
1518 }
1519
1520 sal_uInt8 nRunByte;
1521 const long* pRunTable;
1522 if( i_bSet )
1523 {
1524 nRunByte = 0xff;
1525 pRunTable = setRun;
1526 }
1527 else
1528 {
1529 nRunByte = 0;
1530 pRunTable = unsetRun;
1531 }
1532
1533 if( nIndex < i_nW )
1534 {
1535 while( nByte == nRunByte )
1536 {
1537 nIndex += 8;
1538
1539 if (nIndex >= i_nW)
1540 break;
1541
1542 pByte++;
1543 nByte = *pByte;
1544 }
1545 }
1546
1547 if( nIndex < i_nW )
1548 {
1549 nIndex += pRunTable[nByte];
1550 }
1551 }
1552 return std::min(nIndex, i_nW);
1553}
1554
1555static long findBitRun(const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet)
1556{
1557 if (i_nStartIndex < 0)
1558 return i_nW;
1559
1560 return findBitRunImpl(i_pLine, i_nStartIndex, i_nW, i_bSet);
1561}
1562
1563static long findBitRun(const Scanline i_pLine, long i_nStartIndex, long i_nW)
1564{
1565 if (i_nStartIndex < 0)
1566 return i_nW;
1567
1568 const bool bSet = i_nStartIndex < i_nW && isSet(i_pLine, i_nStartIndex);
1569
1570 return findBitRunImpl(i_pLine, i_nStartIndex, i_nW, bSet);
1571}
1572
1573struct BitStreamState
1574{
1575 sal_uInt8 mnBuffer;
1576 sal_uInt32 mnNextBitPos;
1577
1578 BitStreamState()
1579 : mnBuffer( 0 )
1580 , mnNextBitPos( 8 )
1581 {
1582 }
1583
1584 const sal_uInt8& getByte() const { return mnBuffer; }
1585 void flush() { mnNextBitPos = 8; mnBuffer = 0; }
1586};
1587
1588void PDFWriterImpl::putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState )
1589{
1590 while( i_nLength > io_rState.mnNextBitPos )
1591 {
1592 io_rState.mnBuffer |= static_cast<sal_uInt8>( i_nCode >> (i_nLength - io_rState.mnNextBitPos) );
1593 i_nLength -= io_rState.mnNextBitPos;
1594 writeBuffer( &io_rState.getByte(), 1 );
1595 io_rState.flush();
1596 }
1597 assert(i_nLength < 9)(static_cast <bool> (i_nLength < 9) ? void (0) : __assert_fail
("i_nLength < 9", "/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
, 1597, __extension__ __PRETTY_FUNCTION__))
;
1598 static const unsigned int msbmask[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
1599 io_rState.mnBuffer |= static_cast<sal_uInt8>( (i_nCode & msbmask[i_nLength]) << (io_rState.mnNextBitPos - i_nLength) );
1600 io_rState.mnNextBitPos -= i_nLength;
1601 if( io_rState.mnNextBitPos == 0 )
1602 {
1603 writeBuffer( &io_rState.getByte(), 1 );
1604 io_rState.flush();
1605 }
1606}
1607
1608namespace {
1609
1610struct PixelCode
1611{
1612 sal_uInt32 mnEncodedPixels;
1613 sal_uInt32 mnCodeBits;
1614 sal_uInt32 mnCode;
1615};
1616
1617}
1618
1619const PixelCode WhitePixelCodes[] =
1620{
1621 { 0, 8, 0x35 }, // 0011 0101
1622 { 1, 6, 0x7 }, // 0001 11
1623 { 2, 4, 0x7 }, // 0111
1624 { 3, 4, 0x8 }, // 1000
1625 { 4, 4, 0xB }, // 1011
1626 { 5, 4, 0xC }, // 1100
1627 { 6, 4, 0xE }, // 1110
1628 { 7, 4, 0xF }, // 1111
1629 { 8, 5, 0x13 }, // 1001 1
1630 { 9, 5, 0x14 }, // 1010 0
1631 { 10, 5, 0x7 }, // 0011 1
1632 { 11, 5, 0x8 }, // 0100 0
1633 { 12, 6, 0x8 }, // 0010 00
1634 { 13, 6, 0x3 }, // 0000 11
1635 { 14, 6, 0x34 }, // 1101 00
1636 { 15, 6, 0x35 }, // 1101 01
1637 { 16, 6, 0x2A }, // 1010 10
1638 { 17, 6, 0x2B }, // 1010 11
1639 { 18, 7, 0x27 }, // 0100 111
1640 { 19, 7, 0xC }, // 0001 100
1641 { 20, 7, 0x8 }, // 0001 000
1642 { 21, 7, 0x17 }, // 0010 111
1643 { 22, 7, 0x3 }, // 0000 011
1644 { 23, 7, 0x4 }, // 0000 100
1645 { 24, 7, 0x28 }, // 0101 000
1646 { 25, 7, 0x2B }, // 0101 011
1647 { 26, 7, 0x13 }, // 0010 011
1648 { 27, 7, 0x24 }, // 0100 100
1649 { 28, 7, 0x18 }, // 0011 000
1650 { 29, 8, 0x2 }, // 0000 0010
1651 { 30, 8, 0x3 }, // 0000 0011
1652 { 31, 8, 0x1A }, // 0001 1010
1653 { 32, 8, 0x1B }, // 0001 1011
1654 { 33, 8, 0x12 }, // 0001 0010
1655 { 34, 8, 0x13 }, // 0001 0011
1656 { 35, 8, 0x14 }, // 0001 0100
1657 { 36, 8, 0x15 }, // 0001 0101
1658 { 37, 8, 0x16 }, // 0001 0110
1659 { 38, 8, 0x17 }, // 0001 0111
1660 { 39, 8, 0x28 }, // 0010 1000
1661 { 40, 8, 0x29 }, // 0010 1001
1662 { 41, 8, 0x2A }, // 0010 1010
1663 { 42, 8, 0x2B }, // 0010 1011
1664 { 43, 8, 0x2C }, // 0010 1100
1665 { 44, 8, 0x2D }, // 0010 1101
1666 { 45, 8, 0x4 }, // 0000 0100
1667 { 46, 8, 0x5 }, // 0000 0101
1668 { 47, 8, 0xA }, // 0000 1010
1669 { 48, 8, 0xB }, // 0000 1011
1670 { 49, 8, 0x52 }, // 0101 0010
1671 { 50, 8, 0x53 }, // 0101 0011
1672 { 51, 8, 0x54 }, // 0101 0100
1673 { 52, 8, 0x55 }, // 0101 0101
1674 { 53, 8, 0x24 }, // 0010 0100
1675 { 54, 8, 0x25 }, // 0010 0101
1676 { 55, 8, 0x58 }, // 0101 1000
1677 { 56, 8, 0x59 }, // 0101 1001
1678 { 57, 8, 0x5A }, // 0101 1010
1679 { 58, 8, 0x5B }, // 0101 1011
1680 { 59, 8, 0x4A }, // 0100 1010
1681 { 60, 8, 0x4B }, // 0100 1011
1682 { 61, 8, 0x32 }, // 0011 0010
1683 { 62, 8, 0x33 }, // 0011 0011
1684 { 63, 8, 0x34 }, // 0011 0100
1685 { 64, 5, 0x1B }, // 1101 1
1686 { 128, 5, 0x12 }, // 1001 0
1687 { 192, 6, 0x17 }, // 0101 11
1688 { 256, 7, 0x37 }, // 0110 111
1689 { 320, 8, 0x36 }, // 0011 0110
1690 { 384, 8, 0x37 }, // 0011 0111
1691 { 448, 8, 0x64 }, // 0110 0100
1692 { 512, 8, 0x65 }, // 0110 0101
1693 { 576, 8, 0x68 }, // 0110 1000
1694 { 640, 8, 0x67 }, // 0110 0111
1695 { 704, 9, 0xCC }, // 0110 0110 0
1696 { 768, 9, 0xCD }, // 0110 0110 1
1697 { 832, 9, 0xD2 }, // 0110 1001 0
1698 { 896, 9, 0xD3 }, // 0110 1001 1
1699 { 960, 9, 0xD4 }, // 0110 1010 0
1700 { 1024, 9, 0xD5 }, // 0110 1010 1
1701 { 1088, 9, 0xD6 }, // 0110 1011 0
1702 { 1152, 9, 0xD7 }, // 0110 1011 1
1703 { 1216, 9, 0xD8 }, // 0110 1100 0
1704 { 1280, 9, 0xD9 }, // 0110 1100 1
1705 { 1344, 9, 0xDA }, // 0110 1101 0
1706 { 1408, 9, 0xDB }, // 0110 1101 1
1707 { 1472, 9, 0x98 }, // 0100 1100 0
1708 { 1536, 9, 0x99 }, // 0100 1100 1
1709 { 1600, 9, 0x9A }, // 0100 1101 0
1710 { 1664, 6, 0x18 }, // 0110 00
1711 { 1728, 9, 0x9B }, // 0100 1101 1
1712 { 1792, 11, 0x8 }, // 0000 0001 000
1713 { 1856, 11, 0xC }, // 0000 0001 100
1714 { 1920, 11, 0xD }, // 0000 0001 101
1715 { 1984, 12, 0x12 }, // 0000 0001 0010
1716 { 2048, 12, 0x13 }, // 0000 0001 0011
1717 { 2112, 12, 0x14 }, // 0000 0001 0100
1718 { 2176, 12, 0x15 }, // 0000 0001 0101
1719 { 2240, 12, 0x16 }, // 0000 0001 0110
1720 { 2304, 12, 0x17 }, // 0000 0001 0111
1721 { 2368, 12, 0x1C }, // 0000 0001 1100
1722 { 2432, 12, 0x1D }, // 0000 0001 1101
1723 { 2496, 12, 0x1E }, // 0000 0001 1110
1724 { 2560, 12, 0x1F } // 0000 0001 1111
1725};
1726
1727const PixelCode BlackPixelCodes[] =
1728{
1729 { 0, 10, 0x37 }, // 0000 1101 11
1730 { 1, 3, 0x2 }, // 010
1731 { 2, 2, 0x3 }, // 11
1732 { 3, 2, 0x2 }, // 10
1733 { 4, 3, 0x3 }, // 011
1734 { 5, 4, 0x3 }, // 0011
1735 { 6, 4, 0x2 }, // 0010
1736 { 7, 5, 0x3 }, // 0001 1
1737 { 8, 6, 0x5 }, // 0001 01
1738 { 9, 6, 0x4 }, // 0001 00
1739 { 10, 7, 0x4 }, // 0000 100
1740 { 11, 7, 0x5 }, // 0000 101
1741 { 12, 7, 0x7 }, // 0000 111
1742 { 13, 8, 0x4 }, // 0000 0100
1743 { 14, 8, 0x7 }, // 0000 0111
1744 { 15, 9, 0x18 }, // 0000 1100 0
1745 { 16, 10, 0x17 }, // 0000 0101 11
1746 { 17, 10, 0x18 }, // 0000 0110 00
1747 { 18, 10, 0x8 }, // 0000 0010 00
1748 { 19, 11, 0x67 }, // 0000 1100 111
1749 { 20, 11, 0x68 }, // 0000 1101 000
1750 { 21, 11, 0x6C }, // 0000 1101 100
1751 { 22, 11, 0x37 }, // 0000 0110 111
1752 { 23, 11, 0x28 }, // 0000 0101 000
1753 { 24, 11, 0x17 }, // 0000 0010 111
1754 { 25, 11, 0x18 }, // 0000 0011 000
1755 { 26, 12, 0xCA }, // 0000 1100 1010
1756 { 27, 12, 0xCB }, // 0000 1100 1011
1757 { 28, 12, 0xCC }, // 0000 1100 1100
1758 { 29, 12, 0xCD }, // 0000 1100 1101
1759 { 30, 12, 0x68 }, // 0000 0110 1000
1760 { 31, 12, 0x69 }, // 0000 0110 1001
1761 { 32, 12, 0x6A }, // 0000 0110 1010
1762 { 33, 12, 0x6B }, // 0000 0110 1011
1763 { 34, 12, 0xD2 }, // 0000 1101 0010
1764 { 35, 12, 0xD3 }, // 0000 1101 0011
1765 { 36, 12, 0xD4 }, // 0000 1101 0100
1766 { 37, 12, 0xD5 }, // 0000 1101 0101
1767 { 38, 12, 0xD6 }, // 0000 1101 0110
1768 { 39, 12, 0xD7 }, // 0000 1101 0111
1769 { 40, 12, 0x6C }, // 0000 0110 1100
1770 { 41, 12, 0x6D }, // 0000 0110 1101
1771 { 42, 12, 0xDA }, // 0000 1101 1010
1772 { 43, 12, 0xDB }, // 0000 1101 1011
1773 { 44, 12, 0x54 }, // 0000 0101 0100
1774 { 45, 12, 0x55 }, // 0000 0101 0101
1775 { 46, 12, 0x56 }, // 0000 0101 0110
1776 { 47, 12, 0x57 }, // 0000 0101 0111
1777 { 48, 12, 0x64 }, // 0000 0110 0100
1778 { 49, 12, 0x65 }, // 0000 0110 0101
1779 { 50, 12, 0x52 }, // 0000 0101 0010
1780 { 51, 12, 0x53 }, // 0000 0101 0011
1781 { 52, 12, 0x24 }, // 0000 0010 0100
1782 { 53, 12, 0x37 }, // 0000 0011 0111
1783 { 54, 12, 0x38 }, // 0000 0011 1000
1784 { 55, 12, 0x27 }, // 0000 0010 0111
1785 { 56, 12, 0x28 }, // 0000 0010 1000
1786 { 57, 12, 0x58 }, // 0000 0101 1000
1787 { 58, 12, 0x59 }, // 0000 0101 1001
1788 { 59, 12, 0x2B }, // 0000 0010 1011
1789 { 60, 12, 0x2C }, // 0000 0010 1100
1790 { 61, 12, 0x5A }, // 0000 0101 1010
1791 { 62, 12, 0x66 }, // 0000 0110 0110
1792 { 63, 12, 0x67 }, // 0000 0110 0111
1793 { 64, 10, 0xF }, // 0000 0011 11
1794 { 128, 12, 0xC8 }, // 0000 1100 1000
1795 { 192, 12, 0xC9 }, // 0000 1100 1001
1796 { 256, 12, 0x5B }, // 0000 0101 1011
1797 { 320, 12, 0x33 }, // 0000 0011 0011
1798 { 384, 12, 0x34 }, // 0000 0011 0100
1799 { 448, 12, 0x35 }, // 0000 0011 0101
1800 { 512, 13, 0x6C }, // 0000 0011 0110 0
1801 { 576, 13, 0x6D }, // 0000 0011 0110 1
1802 { 640, 13, 0x4A }, // 0000 0010 0101 0
1803 { 704, 13, 0x4B }, // 0000 0010 0101 1
1804 { 768, 13, 0x4C }, // 0000 0010 0110 0
1805 { 832, 13, 0x4D }, // 0000 0010 0110 1
1806 { 896, 13, 0x72 }, // 0000 0011 1001 0
1807 { 960, 13, 0x73 }, // 0000 0011 1001 1
1808 { 1024, 13, 0x74 }, // 0000 0011 1010 0
1809 { 1088, 13, 0x75 }, // 0000 0011 1010 1
1810 { 1152, 13, 0x76 }, // 0000 0011 1011 0
1811 { 1216, 13, 0x77 }, // 0000 0011 1011 1
1812 { 1280, 13, 0x52 }, // 0000 0010 1001 0
1813 { 1344, 13, 0x53 }, // 0000 0010 1001 1
1814 { 1408, 13, 0x54 }, // 0000 0010 1010 0
1815 { 1472, 13, 0x55 }, // 0000 0010 1010 1
1816 { 1536, 13, 0x5A }, // 0000 0010 1101 0
1817 { 1600, 13, 0x5B }, // 0000 0010 1101 1
1818 { 1664, 13, 0x64 }, // 0000 0011 0010 0
1819 { 1728, 13, 0x65 }, // 0000 0011 0010 1
1820 { 1792, 11, 0x8 }, // 0000 0001 000
1821 { 1856, 11, 0xC }, // 0000 0001 100
1822 { 1920, 11, 0xD }, // 0000 0001 101
1823 { 1984, 12, 0x12 }, // 0000 0001 0010
1824 { 2048, 12, 0x13 }, // 0000 0001 0011
1825 { 2112, 12, 0x14 }, // 0000 0001 0100
1826 { 2176, 12, 0x15 }, // 0000 0001 0101
1827 { 2240, 12, 0x16 }, // 0000 0001 0110
1828 { 2304, 12, 0x17 }, // 0000 0001 0111
1829 { 2368, 12, 0x1C }, // 0000 0001 1100
1830 { 2432, 12, 0x1D }, // 0000 0001 1101
1831 { 2496, 12, 0x1E }, // 0000 0001 1110
1832 { 2560, 12, 0x1F } // 0000 0001 1111
1833};
1834
1835void PDFWriterImpl::putG4Span( long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState )
1836{
1837 const PixelCode* pTable = i_bWhitePixel ? WhitePixelCodes : BlackPixelCodes;
1838 // maximum encoded span is 2560 consecutive pixels
1839 while( i_nSpan > 2623 )
1840 {
1841 // write 2560 bits, that is entry (63 + (2560 >> 6)) == 103 in the appropriate table
1842 putG4Bits( pTable[103].mnCodeBits, pTable[103].mnCode, io_rState );
1843 i_nSpan -= pTable[103].mnEncodedPixels;
1844 }
1845 // write multiples of 64 pixels up to 2560
1846 if( i_nSpan > 63 )
1847 {
1848 sal_uInt32 nTabIndex = 63 + (i_nSpan >> 6);
1849 OSL_ASSERT( pTable[nTabIndex].mnEncodedPixels == static_cast<sal_uInt32>(64*(i_nSpan >> 6)) )do { if (true && (!(pTable[nTabIndex].mnEncodedPixels
== static_cast<sal_uInt32>(64*(i_nSpan >> 6)))))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/gdi/pdfwriter_impl2.cxx"
":" "1849" ": "), "OSL_ASSERT: %s", "pTable[nTabIndex].mnEncodedPixels == static_cast<sal_uInt32>(64*(i_nSpan >> 6))"
); } } while (false)
;
1850 putG4Bits( pTable[nTabIndex].mnCodeBits, pTable[nTabIndex].mnCode, io_rState );
1851 i_nSpan -= pTable[nTabIndex].mnEncodedPixels;
1852 }
1853 putG4Bits( pTable[i_nSpan].mnCodeBits, pTable[i_nSpan].mnCode, io_rState );
1854}
1855
1856void PDFWriterImpl::writeG4Stream( BitmapReadAccess const * i_pBitmap )
1857{
1858 long nW = i_pBitmap->Width();
1859 long nH = i_pBitmap->Height();
1860 if( nW <= 0 || nH <= 0 )
1861 return;
1862 if( i_pBitmap->GetBitCount() != 1 )
1863 return;
1864
1865 BitStreamState aBitState;
1866
1867 // the first reference line is virtual and completely empty
1868 std::unique_ptr<sal_uInt8[]> pFirstRefLine(new sal_uInt8[nW/8 + 1]);
1869 memset(pFirstRefLine.get(), 0, nW/8 + 1);
1870 Scanline pRefLine = pFirstRefLine.get();
1871 for( long nY = 0; nY < nH; nY++ )
1872 {
1873 const Scanline pCurLine = i_pBitmap->GetScanline( nY );
1874 long nLineIndex = 0;
1875 bool bRunSet = (*pCurLine & 0x80) != 0;
1876 bool bRefSet = (*pRefLine & 0x80) != 0;
1877 long nRunIndex1 = bRunSet ? 0 : findBitRun( pCurLine, 0, nW, bRunSet );
1878 long nRefIndex1 = bRefSet ? 0 : findBitRun( pRefLine, 0, nW, bRefSet );
1879 for( ; nLineIndex < nW; )
1880 {
1881 long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW );
1882 if( nRefIndex2 >= nRunIndex1 )
1883 {
1884 long nDiff = nRefIndex1 - nRunIndex1;
1885 if( -3 <= nDiff && nDiff <= 3 )
1886 { // vertical coding
1887 static const struct
1888 {
1889 sal_uInt32 mnCodeBits;
1890 sal_uInt32 mnCode;
1891 } VerticalCodes[7] = {
1892 { 7, 0x03 }, // 0000 011
1893 { 6, 0x03 }, // 0000 11
1894 { 3, 0x03 }, // 011
1895 { 1, 0x1 }, // 1
1896 { 3, 0x2 }, // 010
1897 { 6, 0x02 }, // 0000 10
1898 { 7, 0x02 } // 0000 010
1899 };
1900 // convert to index
1901 nDiff += 3;
1902
1903 // emit diff code
1904 putG4Bits( VerticalCodes[nDiff].mnCodeBits, VerticalCodes[nDiff].mnCode, aBitState );
1905 nLineIndex = nRunIndex1;
1906 }
1907 else
1908 { // difference too large, horizontal coding
1909 // emit horz code 001
1910 putG4Bits( 3, 0x1, aBitState );
1911 long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW );
1912 bool bWhiteFirst = ( nLineIndex + nRunIndex1 == 0 || ! isSet( pCurLine, nLineIndex ) );
1913 putG4Span( nRunIndex1 - nLineIndex, bWhiteFirst, aBitState );
1914 putG4Span( nRunIndex2 - nRunIndex1, ! bWhiteFirst, aBitState );
1915 nLineIndex = nRunIndex2;
1916 }
1917 }
1918 else
1919 { // emit pass code 0001
1920 putG4Bits( 4, 0x1, aBitState );
1921 nLineIndex = nRefIndex2;
1922 }
1923 if( nLineIndex < nW )
1924 {
1925 bool bSet = isSet( pCurLine, nLineIndex );
1926 nRunIndex1 = findBitRun( pCurLine, nLineIndex, nW, bSet );
1927 nRefIndex1 = findBitRun( pRefLine, nLineIndex, nW, ! bSet );
1928 nRefIndex1 = findBitRun( pRefLine, nRefIndex1, nW, bSet );
1929 }
1930 }
1931
1932 // the current line is the reference for the next line
1933 pRefLine = pCurLine;
1934 }
1935 // terminate strip with EOFB
1936 putG4Bits( 12, 1, aBitState );
1937 putG4Bits( 12, 1, aBitState );
1938 if( aBitState.mnNextBitPos != 8 )
1939 {
1940 writeBuffer( &aBitState.getByte(), 1 );
1941 aBitState.flush();
1942 }
1943}
1944
1945void PDFWriterImpl::DrawHatchLine_DrawLine(const Point& rStartPoint, const Point& rEndPoint)
1946{
1947 drawLine(rStartPoint, rEndPoint);
1948}
1949
1950static bool lcl_canUsePDFAxialShading(const Gradient& rGradient) {
1951 switch (rGradient.GetStyle())
1952 {
1953 case GradientStyle::Linear:
1954 case GradientStyle::Axial:
1955 break;
1956 default:
1957 return false;
1958 }
1959
1960 // TODO: handle step count
1961 return rGradient.GetSteps() <= 0;
1962}
1963
1964void PDFWriterImpl::ImplClearFontData(bool bNewFontLists)
1965{
1966 VirtualDevice::ImplClearFontData(bNewFontLists);
1967 if (bNewFontLists && AcquireGraphics())
1968 {
1969 ReleaseFontCollection();
1970 ReleaseFontCache();
1971 }
1972}
1973
1974void PDFWriterImpl::ImplRefreshFontData(bool bNewFontLists)
1975{
1976 if (bNewFontLists && AcquireGraphics())
1977 {
1978 SetFontCollectionFromSVData();
1979 ResetNewFontCache();
1980 }
1981}
1982
1983vcl::Region PDFWriterImpl::ClipToDeviceBounds(vcl::Region aRegion) const
1984{
1985 return aRegion;
1986}
1987
1988
1989/* 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 );
4
Memory is allocated
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();
17
Calling 'Reference::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 ;-)
205 if (aTmp.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();
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 )
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
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
)
8
Taking true branch
113 m_pBody->release();
9
Calling 'VclReferenceBase::release'
13
Returning; memory was released
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)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
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;
18
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)
10
Assuming the condition is true
11
Taking true branch
40 delete this;
12
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