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 eps.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/filter/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 -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/filter/source/graphicfilter/eps/eps.cxx

/home/maarten/src/libreoffice/core/filter/source/graphicfilter/eps/eps.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 <tools/solar.h>
21#include <tools/stream.hxx>
22#include <tools/poly.hxx>
23#include <tools/fract.hxx>
24#include <tools/helpers.hxx>
25#include <unotools/resmgr.hxx>
26#include <vcl/svapp.hxx>
27#include <vcl/metaact.hxx>
28#include <vcl/graph.hxx>
29#include <vcl/bitmapaccess.hxx>
30#include <vcl/region.hxx>
31#include <vcl/font.hxx>
32#include <vcl/virdev.hxx>
33#include <vcl/cvtgrf.hxx>
34#include <vcl/gradient.hxx>
35#include <unotools/configmgr.hxx>
36#include <vcl/FilterConfigItem.hxx>
37#include <vcl/graphictools.hxx>
38#include <vcl/weld.hxx>
39#include <strings.hrc>
40#include <osl/diagnose.h>
41#include <com/sun/star/task/XStatusIndicator.hpp>
42
43#include <memory>
44
45using namespace ::com::sun::star::uno;
46
47#define POSTSCRIPT_BOUNDINGSEARCH0x1000 0x1000 // we only try to get the BoundingBox
48 // in the first 4096 bytes
49
50#define EPS_PREVIEW_TIFF1 1
51#define EPS_PREVIEW_EPSI2 2
52
53#define PS_LINESIZE70 70 // maximum number of characters a line in the output
54
55// -----------------------------field-types------------------------------
56
57namespace {
58
59struct StackMember
60{
61 struct StackMember * pSucc;
62 Color aGlobalCol;
63 bool bLineCol;
64 Color aLineCol;
65 bool bFillCol;
66 Color aFillCol;
67 Color aTextCol;
68 bool bTextFillCol;
69 Color aTextFillCol;
70 Color aBackgroundCol;
71 vcl::Font aFont;
72 TextAlign eTextAlign;
73
74 double fLineWidth;
75 double fMiterLimit;
76 SvtGraphicStroke::CapType eLineCap;
77 SvtGraphicStroke::JoinType eJoinType;
78 SvtGraphicStroke::DashArray aDashArray;
79};
80
81struct PSLZWCTreeNode
82{
83
84 PSLZWCTreeNode* pBrother; // next node who has the same father
85 PSLZWCTreeNode* pFirstChild; // first son
86 sal_uInt16 nCode; // The code for the string of pixel values, which arises if... <missing comment>
87 sal_uInt16 nValue; // the pixel value
88};
89
90enum NMode {PS_NONE = 0x00, PS_SPACE = 0x01, PS_RET = 0x02, PS_WRAP = 0x04}; // formatting mode: action which is inserted behind the output
91inline NMode operator|(NMode a, NMode b)
92{
93 return static_cast<NMode>(static_cast<sal_uInt8>(a) | static_cast<sal_uInt8>(b));
94}
95
96class PSWriter
97{
98private:
99 bool mbStatus;
100 bool mbLevelWarning; // if there any embedded eps file which was not exported
101 sal_uInt32 mnLatestPush; // offset to streamposition, where last push was done
102
103 long mnLevel; // dialog options
104 bool mbGrayScale;
105 bool mbCompression;
106 sal_Int32 mnPreview;
107 sal_Int32 mnTextMode;
108
109 SvStream* mpPS;
110 const GDIMetaFile* pMTF;
111 std::unique_ptr<GDIMetaFile>
112 pAMTF; // only created if Graphics is not a Metafile
113 ScopedVclPtrInstance<VirtualDevice>
114 pVDev;
115
116 double nBoundingX2; // this represents the bounding box
117 double nBoundingY2;
118
119 StackMember* pGDIStack;
120 sal_uInt32 mnCursorPos; // current cursor position in output
121 Color aColor; // current color which is used for output
122 bool bLineColor;
123 Color aLineColor; // current GDIMetafile color settings
124 bool bFillColor;
125 Color aFillColor;
126 Color aTextColor;
127 bool bTextFillColor;
128 Color aTextFillColor;
129 Color aBackgroundColor;
130 TextAlign eTextAlign;
131
132 double fLineWidth;
133 double fMiterLimit;
134 SvtGraphicStroke::CapType eLineCap;
135 SvtGraphicStroke::JoinType eJoinType;
136 SvtGraphicStroke::DashArray aDashArray;
137
138 vcl::Font maFont;
139 vcl::Font maLastFont;
140 sal_uInt8 nNextChrSetId; // first unused ChrSet-Id
141
142 std::unique_ptr<PSLZWCTreeNode[]> pTable; // LZW compression data
143 PSLZWCTreeNode* pPrefix; // the compression is as same as the TIFF compression
144 sal_uInt16 nDataSize;
145 sal_uInt16 nClearCode;
146 sal_uInt16 nEOICode;
147 sal_uInt16 nTableSize;
148 sal_uInt16 nCodeSize;
149 sal_uInt32 nOffset;
150 sal_uInt32 dwShift;
151
152 css::uno::Reference< css::task::XStatusIndicator > xStatusIndicator;
153
154 void ImplWriteProlog( const Graphic* pPreviewEPSI );
155 void ImplWriteEpilog();
156 void ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev );
157
158 // this method makes LF's, space inserting and word wrapping as used in all nMode
159 // parameters
160 inline void ImplExecMode( NMode nMode );
161
162 // writes char[] + LF to stream
163 inline void ImplWriteLine( const char*, NMode nMode = PS_RET );
164
165 // writes ( nNumb / 10^nCount ) in ASCII format to stream
166 void ImplWriteF( sal_Int32 nNumb, sal_uInt8 nCount = 3, NMode nMode = PS_SPACE );
167
168 // writes a double in ASCII format to stream
169 void ImplWriteDouble( double );
170
171 // writes a long in ASCII format to stream
172 void ImplWriteLong( sal_Int32 nNumb, NMode nMode = PS_SPACE );
173
174 // writes a byte in ASCII format to stream
175 void ImplWriteByte( sal_uInt8 nNumb, NMode nMode = PS_SPACE );
176
177 // writes a byte in ASCII (hex) format to stream
178 void ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode = PS_WRAP );
179
180 // writes nNumb as number from 0.000 till 1.000 in ASCII format to stream
181 void ImplWriteB1( sal_uInt8 nNumb );
182
183 inline void ImplWritePoint( const Point& );
184 void ImplMoveTo( const Point& );
185 void ImplLineTo( const Point&, NMode nMode = PS_SPACE );
186 void ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode );
187 void ImplTranslate( const double& fX, const double& fY );
188 void ImplScale( const double& fX, const double& fY );
189
190 void ImplAddPath( const tools::Polygon & rPolygon );
191 void ImplWriteLineInfo( double fLineWidth, double fMiterLimit, SvtGraphicStroke::CapType eLineCap,
192 SvtGraphicStroke::JoinType eJoinType, SvtGraphicStroke::DashArray const & rDashArray );
193 void ImplWriteLineInfo( const LineInfo& rLineInfo );
194 void ImplRect( const tools::Rectangle & rRectangle );
195 void ImplRectFill ( const tools::Rectangle & rRectangle );
196 void ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev );
197 void ImplIntersect( const tools::PolyPolygon& rPolyPoly );
198 void ImplPolyPoly( const tools::PolyPolygon & rPolyPolygon, bool bTextOutline = false );
199 void ImplPolyLine( const tools::Polygon & rPolygon );
200
201 void ImplSetClipRegion( vcl::Region const & rRegion );
202 void ImplBmp( Bitmap const *, Bitmap const *, const Point &, double nWidth, double nHeight );
203 void ImplText( const OUString& rUniString, const Point& rPos, const long* pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev );
204 void ImplSetAttrForText( const Point & rPoint );
205 void ImplWriteCharacter( char );
206 void ImplWriteString( const OString&, VirtualDevice const & rVDev, const long* pDXArry, bool bStretch );
207 void ImplDefineFont( const char*, const char* );
208
209 void ImplClosePathDraw();
210 void ImplPathDraw();
211
212 inline void ImplWriteLineColor( NMode nMode );
213 inline void ImplWriteFillColor( NMode nMode );
214 inline void ImplWriteTextColor( NMode nMode );
215 void ImplWriteColor( NMode nMode );
216
217 static double ImplGetScaling( const MapMode& );
218 void ImplGetMapMode( const MapMode& );
219 static bool ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uInt32 nSize );
220 static sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize );
221 // LZW methods
222 void StartCompression();
223 void Compress( sal_uInt8 nSrc );
224 void EndCompression();
225 inline void WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
226
227public:
228 bool WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* );
229 PSWriter();
230};
231
232}
233
234//========================== methods from PSWriter ==========================
235
236
237PSWriter::PSWriter()
238 : mbStatus(false)
239 , mbLevelWarning(false)
240 , mnLatestPush(0)
241 , mnLevel(0)
242 , mbGrayScale(false)
243 , mbCompression(false)
244 , mnPreview(0)
245 , mnTextMode(0)
246 , mpPS(nullptr)
247 , pMTF(nullptr)
248 , pVDev()
249 , nBoundingX2(0)
250 , nBoundingY2(0)
251 , pGDIStack(nullptr)
252 , mnCursorPos(0)
253 , aColor()
254 , bLineColor(false)
255 , aLineColor()
256 , bFillColor(false)
257 , aFillColor()
258 , aTextColor()
259 , bTextFillColor(false)
260 , aTextFillColor()
261 , aBackgroundColor()
262 , eTextAlign()
263 , fLineWidth(0)
264 , fMiterLimit(0)
265 , eLineCap()
266 , eJoinType()
267 , aDashArray()
268 , maFont()
269 , maLastFont()
270 , nNextChrSetId(0)
271 , pPrefix(nullptr)
272 , nDataSize(0)
273 , nClearCode(0)
274 , nEOICode(0)
275 , nTableSize(0)
276 , nCodeSize(0)
277 , nOffset(0)
278 , dwShift(0)
279 , xStatusIndicator()
280{
281}
282
283bool PSWriter::WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* pFilterConfigItem )
284{
285 sal_uInt32 nStreamPosition = 0, nPSPosition = 0; // -Wall warning, unset, check
286
287 mbStatus = true;
288 mnPreview = 0;
289 mbLevelWarning = false;
290 mnLatestPush = 0xEFFFFFFE;
291
292 if ( pFilterConfigItem )
293 {
294 xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
295 if ( xStatusIndicator.is() )
296 {
297 xStatusIndicator->start( OUString(), 100 );
298 }
299 }
300
301 mpPS = &rTargetStream;
302 mpPS->SetEndian( SvStreamEndian::LITTLE );
303
304 // default values for the dialog options
305 mnLevel = 2;
306 mbGrayScale = false;
307#ifdef UNX1 // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
308 mbCompression = false;
309#else
310 mbCompression = true;
311#endif
312 mnTextMode = 0; // default0 : export glyph outlines
313
314 // try to get the dialog selection
315 if ( pFilterConfigItem )
316 {
317#ifdef UNX1 // don't put binary tiff preview ahead of postscript code by default on unix as ghostscript is unable to read it
318 mnPreview = pFilterConfigItem->ReadInt32( "Preview", 0 );
319#else
320 mnPreview = pFilterConfigItem->ReadInt32( "Preview", 1 );
321#endif
322 mnLevel = pFilterConfigItem->ReadInt32( "Version", 2 );
323 if ( mnLevel != 1 )
324 mnLevel = 2;
325 mbGrayScale = pFilterConfigItem->ReadInt32( "ColorFormat", 1 ) == 2;
326#ifdef UNX1 // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
327 mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 0 ) != 0;
328#else
329 mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 1 ) == 1;
330#endif
331 mnTextMode = pFilterConfigItem->ReadInt32( "TextMode", 0 );
332 if ( mnTextMode > 2 )
333 mnTextMode = 0;
334 }
335
336 // compression is not available for Level 1
337 if ( mnLevel == 1 )
338 {
339 mbGrayScale = true;
340 mbCompression = false;
341 }
342
343 if ( mnPreview & EPS_PREVIEW_TIFF1 )
344 {
345 rTargetStream.WriteUInt32( 0xC6D3D0C5 );
346 nStreamPosition = rTargetStream.Tell();
347 rTargetStream.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
348 .WriteUInt32( nStreamPosition + 26 ).WriteUInt32( 0 ).WriteUInt16( 0xffff );
349
350 ErrCode nErrCode;
351 if ( mbGrayScale )
352 {
353 BitmapEx aTempBitmapEx( rGraphic.GetBitmapEx() );
354 aTempBitmapEx.Convert( BmpConversion::N8BitGreys );
355 nErrCode = GraphicConverter::Export( rTargetStream, aTempBitmapEx, ConvertDataFormat::TIF ) ;
356 }
357 else
358 nErrCode = GraphicConverter::Export( rTargetStream, rGraphic, ConvertDataFormat::TIF ) ;
359
360 if ( nErrCode == ERRCODE_NONEErrCode(0) )
361 {
362 nPSPosition = rTargetStream.TellEnd();
363 rTargetStream.Seek( nStreamPosition + 20 );
364 rTargetStream.WriteUInt32( nPSPosition - 30 ); // size of tiff gfx
365 rTargetStream.Seek( nPSPosition );
366 }
367 else
368 {
369 mnPreview &=~ EPS_PREVIEW_TIFF1;
370 rTargetStream.Seek( nStreamPosition - 4 );
371 }
372 }
373
374 // global default value setting
375 StackMember* pGS;
376
377 if (rGraphic.GetType() == GraphicType::GdiMetafile)
378 pMTF = &rGraphic.GetGDIMetaFile();
379 else if (rGraphic.GetGDIMetaFile().GetActionSize())
380 {
381 pAMTF.reset( new GDIMetaFile( rGraphic.GetGDIMetaFile() ) );
382 pMTF = pAMTF.get();
383 }
384 else
385 {
386 BitmapEx aBmp( rGraphic.GetBitmapEx() );
387 pAMTF.reset( new GDIMetaFile );
388 ScopedVclPtrInstance< VirtualDevice > pTmpVDev;
389 pAMTF->Record( pTmpVDev );
390 pTmpVDev->DrawBitmapEx( Point(), aBmp );
391 pAMTF->Stop();
392 pAMTF->SetPrefSize( aBmp.GetSizePixel() );
393 pMTF = pAMTF.get();
394 }
395 pVDev->SetMapMode( pMTF->GetPrefMapMode() );
396 nBoundingX2 = pMTF->GetPrefSize().Width();
397 nBoundingY2 = pMTF->GetPrefSize().Height();
398
399 pGDIStack = nullptr;
400 aColor = COL_TRANSPARENT;
401 bLineColor = true;
402 aLineColor = COL_BLACK;
403 bFillColor = true;
404 aFillColor = COL_WHITE;
405 bTextFillColor = true;
406 aTextFillColor = COL_BLACK;
407 fLineWidth = 1;
408 fMiterLimit = 15; // use same limit as most graphic systems and basegfx
409 eLineCap = SvtGraphicStroke::capButt;
410 eJoinType = SvtGraphicStroke::joinMiter;
411 aBackgroundColor = COL_WHITE;
412 eTextAlign = ALIGN_BASELINE;
413
414 nNextChrSetId = 1;
415
416 if( pMTF->GetActionSize() )
417 {
418 ImplWriteProlog( ( mnPreview & EPS_PREVIEW_EPSI2 ) ? &rGraphic : nullptr );
419 mnCursorPos = 0;
420 ImplWriteActions( *pMTF, *pVDev );
421 ImplWriteEpilog();
422 if ( mnPreview & EPS_PREVIEW_TIFF1 )
423 {
424 sal_uInt32 nPosition = rTargetStream.Tell();
425 rTargetStream.Seek( nStreamPosition );
426 rTargetStream.WriteUInt32( nPSPosition );
427 rTargetStream.WriteUInt32( nPosition - nPSPosition );
428 rTargetStream.Seek( nPosition );
429 }
430 while( pGDIStack )
431 {
432 pGS=pGDIStack;
433 pGDIStack=pGS->pSucc;
434 delete pGS;
435 }
436 }
437 else
438 mbStatus = false;
439
440 if ( mbStatus && mbLevelWarning && pFilterConfigItem )
441 {
442 std::locale loc = Translate::Create("flt");
443 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
444 VclMessageType::Info, VclButtonsType::Ok,
445 Translate::get(KEY_VERSION_CHECKreinterpret_cast<char const *>("KEY_VERSION_CHECK" "\004"
u8"Warning: Not all of the imported EPS graphics could be saved at level1\nas some are at a higher level!"
)
, loc)));
446 xInfoBox->run();
447 }
448
449 if ( xStatusIndicator.is() )
450 xStatusIndicator->end();
451
452 return mbStatus;
453}
454
455void PSWriter::ImplWriteProlog( const Graphic* pPreview )
456{
457 ImplWriteLine( "%!PS-Adobe-3.0 EPSF-3.0 " );
458 mpPS->WriteCharPtr( "%%BoundingBox: " ); // BoundingBox
459 ImplWriteLong( 0 );
460 ImplWriteLong( 0 );
461 Size aSizePoint = OutputDevice::LogicToLogic( pMTF->GetPrefSize(),
462 pMTF->GetPrefMapMode(), MapMode(MapUnit::MapPoint));
463 ImplWriteLong( aSizePoint.Width() );
464 ImplWriteLong( aSizePoint.Height() ,PS_RET );
465 ImplWriteLine( "%%Pages: 0" );
466 OUString aCreator( "%%Creator: " + utl::ConfigManager::getProductName() + " " +
467 utl::ConfigManager::getProductVersion() );
468 ImplWriteLine( OUStringToOString( aCreator, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)) ).getStr() );
469 ImplWriteLine( "%%Title: none" );
470 ImplWriteLine( "%%CreationDate: none" );
471
472// defaults
473
474 mpPS->WriteCharPtr( "%%LanguageLevel: " ); // Language level
475 ImplWriteLong( mnLevel, PS_RET );
476 if ( !mbGrayScale && mnLevel == 1 )
477 ImplWriteLine( "%%Extensions: CMYK" ); // CMYK extension is to set in color mode in level 1
478 ImplWriteLine( "%%EndComments" );
479 if ( pPreview && aSizePoint.Width() && aSizePoint.Height() )
480 {
481 Size aSizeBitmap( ( aSizePoint.Width() + 7 ) & ~7, aSizePoint.Height() );
482 Bitmap aTmpBitmap( pPreview->GetBitmapEx().GetBitmap() );
483 aTmpBitmap.Scale( aSizeBitmap, BmpScaleFlag::BestQuality );
484 aTmpBitmap.Convert( BmpConversion::N1BitThreshold );
485 BitmapReadAccess* pAcc = aTmpBitmap.AcquireReadAccess();
486 if ( pAcc )
487 {
488 mpPS->WriteCharPtr( "%%BeginPreview: " ); // BoundingBox
489 ImplWriteLong( aSizeBitmap.Width() );
490 ImplWriteLong( aSizeBitmap.Height() );
491 mpPS->WriteCharPtr( "1 " );
492 sal_Int32 nLines = aSizeBitmap.Width() / 312;
493 if ( ( nLines * 312 ) != aSizeBitmap.Width() )
494 nLines++;
495 nLines *= aSizeBitmap.Height();
496 ImplWriteLong( nLines );
497 sal_Int32 nCount2, nCount = 4;
498 const BitmapColor aBlack( pAcc->GetBestMatchingColor( COL_BLACK ) );
499 for ( long nY = 0; nY < aSizeBitmap.Height(); nY++ )
500 {
501 nCount2 = 0;
502 char nVal = 0;
503 Scanline pScanline = pAcc->GetScanline( nY );
504 for ( long nX = 0; nX < aSizeBitmap.Width(); nX++ )
505 {
506 if ( !nCount2 )
507 {
508 ImplExecMode( PS_RET );
509 mpPS->WriteCharPtr( "%" );
510 nCount2 = 312;
511 }
512 nVal <<= 1;
513 if ( pAcc->GetPixelFromData( pScanline, nX ) == aBlack )
514 nVal |= 1;
515 if ( ! ( --nCount ) )
516 {
517 if ( nVal > 9 )
518 nVal += 'A' - 10;
519 else
520 nVal += '0';
521 mpPS->WriteChar( nVal );
522 nVal = 0;
523 nCount += 4;
524 }
525 nCount2--;
526 }
527 }
528 Bitmap::ReleaseAccess( pAcc );
529 ImplExecMode( PS_RET );
530 ImplWriteLine( "%%EndPreview" );
531 }
532 }
533 ImplWriteLine( "%%BeginProlog" );
534 ImplWriteLine( "%%BeginResource: procset SDRes-Prolog 1.0 0" );
535
536// BEGIN EPSF
537 ImplWriteLine( "/b4_inc_state save def\n/dict_count countdictstack def\n/op_count count 1 sub def\nuserdict begin" );
538 ImplWriteLine( "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath" );
539 ImplWriteLine( "/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if" );
540
541 ImplWriteLine( "/bdef {bind def} bind def" ); // the new operator bdef is created
542 if ( mbGrayScale )
543 ImplWriteLine( "/c {setgray} bdef" );
544 else
545 ImplWriteLine( "/c {setrgbcolor} bdef" );
546 ImplWriteLine( "/l {neg lineto} bdef" );
547 ImplWriteLine( "/rl {neg rlineto} bdef" );
548 ImplWriteLine( "/lc {setlinecap} bdef" );
549 ImplWriteLine( "/lj {setlinejoin} bdef" );
550 ImplWriteLine( "/lw {setlinewidth} bdef" );
551 ImplWriteLine( "/ml {setmiterlimit} bdef" );
552 ImplWriteLine( "/ld {setdash} bdef" );
553 ImplWriteLine( "/m {neg moveto} bdef" );
554 ImplWriteLine( "/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef" );
555 ImplWriteLine( "/r {rotate} bdef" );
556 ImplWriteLine( "/t {neg translate} bdef" );
557 ImplWriteLine( "/s {scale} bdef" );
558 ImplWriteLine( "/sw {show} bdef" );
559 ImplWriteLine( "/gs {gsave} bdef" );
560 ImplWriteLine( "/gr {grestore} bdef" );
561
562 ImplWriteLine( "/f {findfont dup length dict begin" ); // Setfont
563 ImplWriteLine( "{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def" );
564 ImplWriteLine( "currentdict end /NFont exch definefont pop /NFont findfont} bdef" );
565
566 ImplWriteLine( "/p {closepath} bdef" );
567 ImplWriteLine( "/sf {scalefont setfont} bdef" );
568
569 ImplWriteLine( "/ef {eofill}bdef" ); // close path and fill
570 ImplWriteLine( "/pc {closepath stroke}bdef" ); // close path and draw
571 ImplWriteLine( "/ps {stroke}bdef" ); // draw current path
572 ImplWriteLine( "/pum {matrix currentmatrix}bdef" ); // pushes the current matrix
573 ImplWriteLine( "/pom {setmatrix}bdef" ); // pops the matrix
574 ImplWriteLine( "/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef" );
575 ImplWriteLine( "%%EndResource" );
576 ImplWriteLine( "%%EndProlog" );
577 ImplWriteLine( "%%BeginSetup" );
578 ImplWriteLine( "%%EndSetup" );
579 ImplWriteLine( "%%Page: 1 1" );
580 ImplWriteLine( "%%BeginPageSetup" );
581 ImplWriteLine( "%%EndPageSetup" );
582 ImplWriteLine( "pum" );
583 ImplScale( static_cast<double>(aSizePoint.Width()) / static_cast<double>(pMTF->GetPrefSize().Width()), static_cast<double>(aSizePoint.Height()) / static_cast<double>(pMTF->GetPrefSize().Height()) );
584 ImplWriteDouble( 0 );
585 ImplWriteDouble( -pMTF->GetPrefSize().Height() );
586 ImplWriteLine( "t" );
587 ImplWriteLine( "/tm matrix currentmatrix def" );
588}
589
590void PSWriter::ImplWriteEpilog()
591{
592 ImplTranslate( 0, nBoundingY2 );
593 ImplWriteLine( "pom" );
594 ImplWriteLine( "count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore" );
595
596 ImplWriteLine( "%%PageTrailer" );
597 ImplWriteLine( "%%Trailer" );
598
599 ImplWriteLine( "%%EOF" );
600}
601
602void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev )
603{
604 tools::PolyPolygon aFillPath;
605
606 for( size_t nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
1
Assuming 'nCurAction' is < 'nCount'
2
Loop condition is true. Entering loop body
607 {
608 MetaAction* pMA = rMtf.GetAction( nCurAction );
609
610 switch( pMA->GetType() )
3
Control jumps to 'case HATCH:' at line 888
611 {
612 case MetaActionType::NONE :
613 break;
614
615 case MetaActionType::PIXEL :
616 {
617 Color aOldLineColor( aLineColor );
618 aLineColor = static_cast<const MetaPixelAction*>(pMA)->GetColor();
619 ImplWriteLineColor( PS_SPACE );
620 ImplMoveTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
621 ImplLineTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
622 ImplPathDraw();
623 aLineColor = aOldLineColor;
624 }
625 break;
626
627 case MetaActionType::POINT :
628 {
629 ImplWriteLineColor( PS_SPACE );
630 ImplMoveTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
631 ImplLineTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
632 ImplPathDraw();
633 }
634 break;
635
636 case MetaActionType::LINE :
637 {
638 const LineInfo& rLineInfo = static_cast<const MetaLineAction*>(pMA)->GetLineInfo();
639 ImplWriteLineInfo( rLineInfo );
640 if ( bLineColor )
641 {
642 ImplWriteLineColor( PS_SPACE );
643 ImplMoveTo( static_cast<const MetaLineAction*>(pMA)->GetStartPoint() );
644 ImplLineTo( static_cast<const MetaLineAction*>(pMA )->GetEndPoint() );
645 ImplPathDraw();
646 }
647 }
648 break;
649
650 case MetaActionType::RECT :
651 {
652 ImplRect( static_cast<const MetaRectAction*>(pMA)->GetRect() );
653 }
654 break;
655
656 case MetaActionType::ROUNDRECT :
657 ImplRect( static_cast<const MetaRoundRectAction*>(pMA)->GetRect() );
658 break;
659
660 case MetaActionType::ELLIPSE :
661 {
662 tools::Rectangle aRect = static_cast<const MetaEllipseAction*>(pMA)->GetRect();
663 Point aCenter = aRect.Center();
664 tools::Polygon aPoly( aCenter, aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
665 tools::PolyPolygon aPolyPoly( aPoly );
666 ImplPolyPoly( aPolyPoly );
667 }
668 break;
669
670 case MetaActionType::ARC :
671 {
672 tools::Polygon aPoly( static_cast<const MetaArcAction*>(pMA)->GetRect(), static_cast<const MetaArcAction*>(pMA)->GetStartPoint(),
673 static_cast<const MetaArcAction*>(pMA)->GetEndPoint(), PolyStyle::Arc );
674 tools::PolyPolygon aPolyPoly( aPoly );
675 ImplPolyPoly( aPolyPoly );
676 }
677 break;
678
679 case MetaActionType::PIE :
680 {
681 tools::Polygon aPoly( static_cast<const MetaPieAction*>(pMA)->GetRect(), static_cast<const MetaPieAction*>(pMA)->GetStartPoint(),
682 static_cast<const MetaPieAction*>(pMA)->GetEndPoint(), PolyStyle::Pie );
683 tools::PolyPolygon aPolyPoly( aPoly );
684 ImplPolyPoly( aPolyPoly );
685 }
686 break;
687
688 case MetaActionType::CHORD :
689 {
690 tools::Polygon aPoly( static_cast<const MetaChordAction*>(pMA)->GetRect(), static_cast<const MetaChordAction*>(pMA)->GetStartPoint(),
691 static_cast<const MetaChordAction*>(pMA)->GetEndPoint(), PolyStyle::Chord );
692 tools::PolyPolygon aPolyPoly( aPoly );
693 ImplPolyPoly( aPolyPoly );
694 }
695 break;
696
697 case MetaActionType::POLYLINE :
698 {
699 tools::Polygon aPoly( static_cast<const MetaPolyLineAction*>(pMA)->GetPolygon() );
700 const LineInfo& rLineInfo = static_cast<const MetaPolyLineAction*>(pMA)->GetLineInfo();
701 ImplWriteLineInfo( rLineInfo );
702
703 if(basegfx::B2DLineJoin::NONE == rLineInfo.GetLineJoin()
704 && rLineInfo.GetWidth() > 1)
705 {
706 // emulate B2DLineJoin::NONE by creating single edges
707 const sal_uInt16 nPoints(aPoly.GetSize());
708 const bool bCurve(aPoly.HasFlags());
709
710 for(sal_uInt16 a(0); a + 1 < nPoints; a++)
711 {
712 if(bCurve
713 && PolyFlags::Normal != aPoly.GetFlags(a + 1)
714 && a + 2 < nPoints
715 && PolyFlags::Normal != aPoly.GetFlags(a + 2)
716 && a + 3 < nPoints)
717 {
718 const tools::Polygon aSnippet(4,
719 aPoly.GetConstPointAry() + a,
720 aPoly.GetConstFlagAry() + a);
721 ImplPolyLine(aSnippet);
722 a += 2;
723 }
724 else
725 {
726 const tools::Polygon aSnippet(2,
727 aPoly.GetConstPointAry() + a);
728 ImplPolyLine(aSnippet);
729 }
730 }
731 }
732 else
733 {
734 ImplPolyLine( aPoly );
735 }
736 }
737 break;
738
739 case MetaActionType::POLYGON :
740 {
741 tools::PolyPolygon aPolyPoly( static_cast<const MetaPolygonAction*>(pMA)->GetPolygon() );
742 ImplPolyPoly( aPolyPoly );
743 }
744 break;
745
746 case MetaActionType::POLYPOLYGON :
747 {
748 ImplPolyPoly( static_cast<const MetaPolyPolygonAction*>(pMA)->GetPolyPolygon() );
749 }
750 break;
751
752 case MetaActionType::TEXT:
753 {
754 const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
755
756 OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
757 Point aPoint( pA->GetPoint() );
758
759 ImplText( aUniStr, aPoint, nullptr, 0, rVDev );
760 }
761 break;
762
763 case MetaActionType::TEXTRECT:
764 {
765 OSL_FAIL( "Unsupported action: TextRect...Action!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/graphicfilter/eps/eps.cxx"
":" "765" ": "), "%s", "Unsupported action: TextRect...Action!"
); } } while (false)
;
766 }
767 break;
768
769 case MetaActionType::STRETCHTEXT :
770 {
771 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pMA);
772 OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
773 Point aPoint( pA->GetPoint() );
774
775 ImplText( aUniStr, aPoint, nullptr, pA->GetWidth(), rVDev );
776 }
777 break;
778
779 case MetaActionType::TEXTARRAY:
780 {
781 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
782 OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
783 Point aPoint( pA->GetPoint() );
784
785 ImplText( aUniStr, aPoint, pA->GetDXArray(), 0, rVDev );
786 }
787 break;
788
789 case MetaActionType::BMP :
790 {
791 Bitmap aBitmap = static_cast<const MetaBmpAction*>(pMA)->GetBitmap();
792 if ( mbGrayScale )
793 aBitmap.Convert( BmpConversion::N8BitGreys );
794 Point aPoint = static_cast<const MetaBmpAction*>(pMA)->GetPoint();
795 Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
796 ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
797 }
798 break;
799
800 case MetaActionType::BMPSCALE :
801 {
802 Bitmap aBitmap = static_cast<const MetaBmpScaleAction*>(pMA)->GetBitmap();
803 if ( mbGrayScale )
804 aBitmap.Convert( BmpConversion::N8BitGreys );
805 Point aPoint = static_cast<const MetaBmpScaleAction*>(pMA)->GetPoint();
806 Size aSize = static_cast<const MetaBmpScaleAction*>(pMA)->GetSize();
807 ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
808 }
809 break;
810
811 case MetaActionType::BMPSCALEPART :
812 {
813 Bitmap aBitmap( static_cast<const MetaBmpScalePartAction*>(pMA)->GetBitmap() );
814 aBitmap.Crop( tools::Rectangle( static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcPoint(),
815 static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcSize() ) );
816 if ( mbGrayScale )
817 aBitmap.Convert( BmpConversion::N8BitGreys );
818 Point aPoint = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestPoint();
819 Size aSize = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestSize();
820 ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
821 }
822 break;
823
824 case MetaActionType::BMPEX :
825 {
826 BitmapEx aBitmapEx( static_cast<MetaBmpExAction*>(pMA)->GetBitmapEx() );
827 Bitmap aBitmap( aBitmapEx.GetBitmap() );
828 if ( mbGrayScale )
829 aBitmap.Convert( BmpConversion::N8BitGreys );
830 Bitmap aMask( aBitmapEx.GetMask() );
831 Point aPoint( static_cast<const MetaBmpExAction*>(pMA)->GetPoint() );
832 Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
833 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
834 }
835 break;
836
837 case MetaActionType::BMPEXSCALE :
838 {
839 BitmapEx aBitmapEx( static_cast<MetaBmpExScaleAction*>(pMA)->GetBitmapEx() );
840 Bitmap aBitmap( aBitmapEx.GetBitmap() );
841 if ( mbGrayScale )
842 aBitmap.Convert( BmpConversion::N8BitGreys );
843 Bitmap aMask( aBitmapEx.GetMask() );
844 Point aPoint = static_cast<const MetaBmpExScaleAction*>(pMA)->GetPoint();
845 Size aSize( static_cast<const MetaBmpExScaleAction*>(pMA)->GetSize() );
846 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
847 }
848 break;
849
850 case MetaActionType::BMPEXSCALEPART :
851 {
852 BitmapEx aBitmapEx( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetBitmapEx() );
853 aBitmapEx.Crop( tools::Rectangle( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcPoint(),
854 static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcSize() ) );
855 Bitmap aBitmap( aBitmapEx.GetBitmap() );
856 if ( mbGrayScale )
857 aBitmap.Convert( BmpConversion::N8BitGreys );
858 Bitmap aMask( aBitmapEx.GetMask() );
859 Point aPoint = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestPoint();
860 Size aSize = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestSize();
861 ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
862 }
863 break;
864
865 // Unsupported Actions
866 case MetaActionType::MASK:
867 case MetaActionType::MASKSCALE:
868 case MetaActionType::MASKSCALEPART:
869 {
870 OSL_FAIL( "Unsupported action: MetaMask...Action!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/graphicfilter/eps/eps.cxx"
":" "870" ": "), "%s", "Unsupported action: MetaMask...Action!"
); } } while (false)
;
871 }
872 break;
873
874 case MetaActionType::GRADIENT :
875 {
876 tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientAction*>(pMA)->GetRect() );
877 ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientAction*>(pMA)->GetGradient(), rVDev );
878 }
879 break;
880
881 case MetaActionType::GRADIENTEX :
882 {
883 tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientExAction*>(pMA)->GetPolyPolygon() );
884 ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientExAction*>(pMA)->GetGradient(), rVDev );
885 }
886 break;
887
888 case MetaActionType::HATCH :
889 {
890 ScopedVclPtrInstance< VirtualDevice > l_pVirDev;
4
Calling default constructor for 'ScopedVclPtrInstance<VirtualDevice>'
6
Returning from default constructor for 'ScopedVclPtrInstance<VirtualDevice>'
891 GDIMetaFile aTmpMtf;
892
893 l_pVirDev->SetMapMode( rVDev.GetMapMode() );
894 l_pVirDev->AddHatchActions( static_cast<const MetaHatchAction*>(pMA)->GetPolyPolygon(),
895 static_cast<const MetaHatchAction*>(pMA)->GetHatch(), aTmpMtf );
896 ImplWriteActions( aTmpMtf, rVDev );
897 }
7
Calling implicit destructor for 'ScopedVclPtrInstance<VirtualDevice>'
8
Calling '~ScopedVclPtr'
898 break;
899
900 case MetaActionType::WALLPAPER :
901 {
902 const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
903 tools::Rectangle aRect = pA->GetRect();
904 const Wallpaper& aWallpaper = pA->GetWallpaper();
905
906 if ( aWallpaper.IsBitmap() )
907 {
908 BitmapEx aBitmapEx = aWallpaper.GetBitmap();
909 Bitmap aBitmap( aBitmapEx.GetBitmap() );
910 if ( aBitmapEx.IsTransparent() )
911 {
912 if ( aWallpaper.IsGradient() )
913 {
914
915 // gradient action
916
917 }
918 Bitmap aMask( aBitmapEx.GetMask() );
919 ImplBmp( &aBitmap, &aMask, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
920 }
921 else
922 ImplBmp( &aBitmap, nullptr, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
923
924 // wallpaper Style
925
926 }
927 else if ( aWallpaper.IsGradient() )
928 {
929
930 // gradient action
931
932 }
933 else
934 {
935 aColor = aWallpaper.GetColor();
936 ImplRectFill( aRect );
937 }
938 }
939 break;
940
941 case MetaActionType::ISECTRECTCLIPREGION:
942 {
943 const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
944 vcl::Region aRegion( pA->GetRect() );
945 ImplSetClipRegion( aRegion );
946 }
947 break;
948
949 case MetaActionType::CLIPREGION:
950 {
951 const MetaClipRegionAction* pA = static_cast<const MetaClipRegionAction*>(pMA);
952 const vcl::Region& aRegion( pA->GetRegion() );
953 ImplSetClipRegion( aRegion );
954 }
955 break;
956
957 case MetaActionType::ISECTREGIONCLIPREGION:
958 {
959 const MetaISectRegionClipRegionAction* pA = static_cast<const MetaISectRegionClipRegionAction*>(pMA);
960 const vcl::Region& aRegion( pA->GetRegion() );
961 ImplSetClipRegion( aRegion );
962 }
963 break;
964
965 case MetaActionType::MOVECLIPREGION:
966 {
967 // TODO: Implement!
968 }
969 break;
970
971 case MetaActionType::LINECOLOR :
972 {
973 if ( static_cast<const MetaLineColorAction*>(pMA)->IsSetting() )
974 {
975 bLineColor = true;
976 aLineColor = static_cast<const MetaLineColorAction*>(pMA)->GetColor();
977 }
978 else
979 bLineColor = false;
980 }
981 break;
982
983 case MetaActionType::FILLCOLOR :
984 {
985 if ( static_cast<const MetaFillColorAction*>(pMA)->IsSetting() )
986 {
987 bFillColor = true;
988 aFillColor = static_cast<const MetaFillColorAction*>(pMA)->GetColor();
989 }
990 else
991 bFillColor = false;
992 }
993 break;
994
995 case MetaActionType::TEXTCOLOR :
996 {
997 aTextColor = static_cast<const MetaTextColorAction*>(pMA)->GetColor();
998 }
999 break;
1000
1001 case MetaActionType::TEXTFILLCOLOR :
1002 {
1003 if ( static_cast<const MetaTextFillColorAction*>(pMA)->IsSetting() )
1004 {
1005 bTextFillColor = true;
1006 aTextFillColor = static_cast<const MetaTextFillColorAction*>(pMA)->GetColor();
1007 }
1008 else
1009 bTextFillColor = false;
1010 }
1011 break;
1012
1013 case MetaActionType::TEXTALIGN :
1014 {
1015 eTextAlign = static_cast<const MetaTextAlignAction*>(pMA)->GetTextAlign();
1016 }
1017 break;
1018
1019 case MetaActionType::MAPMODE :
1020 {
1021 pMA->Execute( &rVDev );
1022 ImplGetMapMode( rVDev.GetMapMode() );
1023 }
1024 break;
1025
1026 case MetaActionType::FONT :
1027 {
1028 maFont = static_cast<const MetaFontAction*>(pMA)->GetFont();
1029 rVDev.SetFont( maFont );
1030 }
1031 break;
1032
1033 case MetaActionType::PUSH :
1034 {
1035 rVDev.Push(static_cast<const MetaPushAction*>(pMA)->GetFlags() );
1036 StackMember* pGS = new StackMember;
1037 pGS->pSucc = pGDIStack;
1038 pGDIStack = pGS;
1039 pGS->aDashArray = aDashArray;
1040 pGS->eJoinType = eJoinType;
1041 pGS->eLineCap = eLineCap;
1042 pGS->fLineWidth = fLineWidth;
1043 pGS->fMiterLimit = fMiterLimit;
1044 pGS->eTextAlign = eTextAlign;
1045 pGS->aGlobalCol = aColor;
1046 pGS->bLineCol = bLineColor;
1047 pGS->aLineCol = aLineColor;
1048 pGS->bFillCol = bFillColor;
1049 pGS->aFillCol = aFillColor;
1050 pGS->aTextCol = aTextColor;
1051 pGS->bTextFillCol = bTextFillColor;
1052 pGS->aTextFillCol = aTextFillColor;
1053 pGS->aBackgroundCol = aBackgroundColor;
1054 pGS->aFont = maFont;
1055 mnLatestPush = mpPS->Tell();
1056 ImplWriteLine( "gs" );
1057 }
1058 break;
1059
1060 case MetaActionType::POP :
1061 {
1062 rVDev.Pop();
1063 if( pGDIStack )
1064 {
1065 StackMember* pGS = pGDIStack;
1066 pGDIStack = pGS->pSucc;
1067 aDashArray = pGS->aDashArray;
1068 eJoinType = pGS->eJoinType;
1069 eLineCap = pGS->eLineCap;
1070 fLineWidth = pGS->fLineWidth;
1071 fMiterLimit = pGS->fMiterLimit;
1072 eTextAlign = pGS->eTextAlign;
1073 aColor = pGS->aGlobalCol;
1074 bLineColor = pGS->bLineCol;
1075 aLineColor = pGS->aLineCol;
1076 bFillColor = pGS->bFillCol;
1077 aFillColor = pGS->aFillCol;
1078 aTextColor = pGS->aTextCol;
1079 bTextFillColor = pGS->bTextFillCol;
1080 aTextFillColor = pGS->aTextFillCol;
1081 aBackgroundColor = pGS->aBackgroundCol;
1082 maFont = pGS->aFont;
1083 maLastFont = vcl::Font(); // set maLastFont != maFont -> so that
1084 delete pGS;
1085 sal_uInt32 nCurrentPos = mpPS->Tell();
1086 if ( nCurrentPos - 3 == mnLatestPush )
1087 {
1088 mpPS->Seek( mnLatestPush );
1089 ImplWriteLine( " " );
1090 mpPS->Seek( mnLatestPush );
1091 }
1092 else
1093 ImplWriteLine( "gr" );
1094 }
1095 }
1096 break;
1097
1098 case MetaActionType::EPS :
1099 {
1100 GfxLink aGfxLink = static_cast<const MetaEPSAction*>(pMA)->GetLink();
1101 const GDIMetaFile aSubstitute( static_cast<const MetaEPSAction*>(pMA)->GetSubstitute() );
1102
1103 bool bLevelConflict = false;
1104 sal_uInt8* pSource = const_cast<sal_uInt8*>(aGfxLink.GetData());
1105 sal_uInt32 nSize = aGfxLink.GetDataSize();
1106 sal_uInt32 nParseThis = POSTSCRIPT_BOUNDINGSEARCH0x1000;
1107 if ( nSize < 64 ) // assuming eps is larger than 64 bytes
1108 pSource = nullptr;
1109 if ( nParseThis > nSize )
1110 nParseThis = nSize;
1111
1112 if ( pSource && ( mnLevel == 1 ) )
1113 {
1114 sal_uInt8* pFound = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%LanguageLevel:"), nParseThis - 10, 16 );
1115 if ( pFound )
1116 {
1117 sal_uInt8 k, i = 10;
1118 pFound += 16;
1119 while ( --i )
1120 {
1121 k = *pFound++;
1122 if ( ( k > '0' ) && ( k <= '9' ) )
1123 {
1124 if ( k != '1' )
1125 {
1126 bLevelConflict = true;
1127 mbLevelWarning = true;
1128 }
1129 break;
1130 }
1131 }
1132 }
1133 }
1134 if ( !bLevelConflict )
1135 {
1136 double nBoundingBox[4];
1137 if ( pSource && ImplGetBoundingBox( nBoundingBox, pSource, nParseThis ) )
1138 {
1139 Point aPoint = static_cast<const MetaEPSAction*>(pMA)->GetPoint();
1140 Size aSize = static_cast<const MetaEPSAction*>(pMA)->GetSize();
1141
1142 MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1143 Size aOutSize( OutputDevice::LogicToLogic( aSize, rVDev.GetMapMode(), aMapMode ) );
1144 Point aOrigin( OutputDevice::LogicToLogic( aPoint, rVDev.GetMapMode(), aMapMode ) );
1145 aOrigin.AdjustY(aOutSize.Height() );
1146 aMapMode.SetOrigin( aOrigin );
1147 aMapMode.SetScaleX( Fraction(aOutSize.Width() / ( nBoundingBox[ 2 ] - nBoundingBox[ 0 ] )) );
1148 aMapMode.SetScaleY( Fraction(aOutSize.Height() / ( nBoundingBox[ 3 ] - nBoundingBox[ 1 ] )) );
1149 ImplWriteLine( "gs" );
1150 ImplGetMapMode( aMapMode );
1151 ImplWriteLine( "%%BeginDocument:" );
1152 mpPS->WriteBytes(pSource, aGfxLink.GetDataSize());
1153 ImplWriteLine( "%%EndDocument\ngr" );
1154 }
1155 }
1156 }
1157 break;
1158
1159 case MetaActionType::Transparent:
1160 {
1161 // TODO: implement!
1162 }
1163 break;
1164
1165 case MetaActionType::RASTEROP:
1166 {
1167 pMA->Execute( &rVDev );
1168 }
1169 break;
1170
1171 case MetaActionType::FLOATTRANSPARENT:
1172 {
1173 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
1174
1175 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1176 Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1177 const Size aSrcSize( aTmpMtf.GetPrefSize() );
1178 const Point aDestPt( pA->GetPoint() );
1179 const Size aDestSize( pA->GetSize() );
1180 const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1181 const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1182 long nMoveX, nMoveY;
1183
1184 if( fScaleX != 1.0 || fScaleY != 1.0 )
1185 {
1186 aTmpMtf.Scale( fScaleX, fScaleY );
1187 aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1188 aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1189 }
1190
1191 nMoveX = aDestPt.X() - aSrcPt.X();
1192 nMoveY = aDestPt.Y() - aSrcPt.Y();
1193
1194 if( nMoveX || nMoveY )
1195 aTmpMtf.Move( nMoveX, nMoveY );
1196
1197 ImplWriteActions( aTmpMtf, rVDev );
1198 }
1199 break;
1200
1201 case MetaActionType::COMMENT:
1202 {
1203 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pMA);
1204 if ( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") )
1205 {
1206 const MetaGradientExAction* pGradAction = nullptr;
1207 while( ++nCurAction < nCount )
1208 {
1209 MetaAction* pAction = rMtf.GetAction( nCurAction );
1210 if( pAction->GetType() == MetaActionType::GRADIENTEX )
1211 pGradAction = static_cast<const MetaGradientExAction*>(pAction);
1212 else if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
1213 ( static_cast<const MetaCommentAction*>(pAction)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
1214 {
1215 break;
1216 }
1217 }
1218
1219 if( pGradAction )
1220 ImplWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), rVDev );
1221 }
1222 else if ( pA->GetComment() == "XPATHFILL_SEQ_END" )
1223 {
1224 if ( aFillPath.Count() )
1225 {
1226 aFillPath = tools::PolyPolygon();
1227 ImplWriteLine( "gr" );
1228 }
1229 }
1230 else
1231 {
1232 const sal_uInt8* pData = pA->GetData();
1233 if ( pData )
1234 {
1235 SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pData), pA->GetDataSize(), StreamMode::READ );
1236 bool bSkipSequence = false;
1237 OString sSeqEnd;
1238
1239 if( pA->GetComment() == "XPATHSTROKE_SEQ_BEGIN" )
1240 {
1241 sSeqEnd = "XPATHSTROKE_SEQ_END";
1242 SvtGraphicStroke aStroke;
1243 ReadSvtGraphicStroke( aMemStm, aStroke );
1244
1245 tools::Polygon aPath;
1246 aStroke.getPath( aPath );
1247
1248 tools::PolyPolygon aStartArrow;
1249 tools::PolyPolygon aEndArrow;
1250 double fStrokeWidth( aStroke.getStrokeWidth() );
1251 SvtGraphicStroke::JoinType eJT( aStroke.getJoinType() );
1252 SvtGraphicStroke::DashArray l_aDashArray;
1253
1254 aStroke.getStartArrow( aStartArrow );
1255 aStroke.getEndArrow( aEndArrow );
1256 aStroke.getDashArray( l_aDashArray );
1257
1258 bSkipSequence = true;
1259 if ( l_aDashArray.size() > 11 ) // ps dasharray limit is 11
1260 bSkipSequence = false;
1261 if ( aStartArrow.Count() || aEndArrow.Count() )
1262 bSkipSequence = false;
1263 if ( static_cast<sal_uInt32>(eJT) > 2 )
1264 bSkipSequence = false;
1265 if ( !l_aDashArray.empty() && ( fStrokeWidth != 0.0 ) )
1266 bSkipSequence = false;
1267 if ( bSkipSequence )
1268 {
1269 ImplWriteLineInfo( fStrokeWidth, aStroke.getMiterLimit(),
1270 aStroke.getCapType(), eJT, l_aDashArray );
1271 ImplPolyLine( aPath );
1272 }
1273 }
1274 else if (pA->GetComment() == "XPATHFILL_SEQ_BEGIN")
1275 {
1276 sSeqEnd = "XPATHFILL_SEQ_END";
1277 SvtGraphicFill aFill;
1278 ReadSvtGraphicFill( aMemStm, aFill );
1279 switch( aFill.getFillType() )
1280 {
1281 case SvtGraphicFill::fillSolid :
1282 {
1283 bSkipSequence = true;
1284 tools::PolyPolygon aPolyPoly;
1285 aFill.getPath( aPolyPoly );
1286 sal_uInt16 i, nPolyCount = aPolyPoly.Count();
1287 if ( nPolyCount )
1288 {
1289 aFillColor = aFill.getFillColor();
1290 ImplWriteFillColor( PS_SPACE );
1291 for ( i = 0; i < nPolyCount; )
1292 {
1293 ImplAddPath( aPolyPoly.GetObject( i ) );
1294 if ( ++i < nPolyCount )
1295 {
1296 mpPS->WriteCharPtr( "p" );
1297 mnCursorPos += 2;
1298 ImplExecMode( PS_RET );
1299 }
1300 }
1301 mpPS->WriteCharPtr( "p ef" );
1302 mnCursorPos += 4;
1303 ImplExecMode( PS_RET );
1304 }
1305 }
1306 break;
1307
1308 case SvtGraphicFill::fillTexture :
1309 {
1310 aFill.getPath( aFillPath );
1311
1312 /* normally an object filling is consisting of three MetaActions:
1313 MetaBitmapAction using RasterOp xor,
1314 MetaPolyPolygonAction using RasterOp rop_0
1315 MetaBitmapAction using RasterOp xor
1316
1317 Because RasterOps cannot been used in Postscript, we have to
1318 replace these actions. The MetaComment "XPATHFILL_SEQ_BEGIN" is
1319 providing the clippath of the object. The following loop is
1320 trying to find the bitmap that is matching the clippath, so that
1321 only one bitmap is exported, otherwise if the bitmap is not
1322 locatable, all metaactions are played normally.
1323 */
1324 sal_uInt32 nCommentStartAction = nCurAction;
1325 sal_uInt32 nBitmapCount = 0;
1326 sal_uInt32 nBitmapAction = 0;
1327
1328 bool bOk = true;
1329 while( bOk && ( ++nCurAction < nCount ) )
1330 {
1331 MetaAction* pAction = rMtf.GetAction( nCurAction );
1332 switch( pAction->GetType() )
1333 {
1334 case MetaActionType::BMPSCALE :
1335 case MetaActionType::BMPSCALEPART :
1336 case MetaActionType::BMPEXSCALE :
1337 case MetaActionType::BMPEXSCALEPART :
1338 {
1339 nBitmapCount++;
1340 nBitmapAction = nCurAction;
1341 }
1342 break;
1343 case MetaActionType::COMMENT :
1344 {
1345 if (static_cast<const MetaCommentAction*>(pAction)->GetComment() == "XPATHFILL_SEQ_END")
1346 bOk = false;
1347 }
1348 break;
1349 default: break;
1350 }
1351 }
1352 if( nBitmapCount == 2 )
1353 {
1354 ImplWriteLine( "gs" );
1355 ImplIntersect( aFillPath );
1356 GDIMetaFile aTempMtf;
1357 aTempMtf.AddAction( rMtf.GetAction( nBitmapAction )->Clone() );
1358 ImplWriteActions( aTempMtf, rVDev );
1359 ImplWriteLine( "gr" );
1360 aFillPath = tools::PolyPolygon();
1361 }
1362 else
1363 nCurAction = nCommentStartAction + 1;
1364 }
1365 break;
1366
1367 case SvtGraphicFill::fillGradient :
1368 aFill.getPath( aFillPath );
1369 break;
1370
1371 case SvtGraphicFill::fillHatch :
1372 break;
1373 }
1374 if ( aFillPath.Count() )
1375 {
1376 ImplWriteLine( "gs" );
1377 ImplIntersect( aFillPath );
1378 }
1379 }
1380 if ( bSkipSequence )
1381 {
1382 while( ++nCurAction < nCount )
1383 {
1384 pMA = rMtf.GetAction( nCurAction );
1385 if ( pMA->GetType() == MetaActionType::COMMENT )
1386 {
1387 OString sComment( static_cast<MetaCommentAction*>(pMA)->GetComment() );
1388 if ( sComment == sSeqEnd )
1389 break;
1390 }
1391 }
1392 }
1393 }
1394 }
1395 }
1396 break;
1397 default: break;
1398 }
1399 }
1400}
1401
1402inline void PSWriter::ImplWritePoint( const Point& rPoint )
1403{
1404 ImplWriteDouble( rPoint.X() );
1405 ImplWriteDouble( rPoint.Y() );
1406}
1407
1408void PSWriter::ImplMoveTo( const Point& rPoint )
1409{
1410 ImplWritePoint( rPoint );
1411 ImplWriteByte( 'm' );
1412 ImplExecMode( PS_SPACE );
1413}
1414
1415void PSWriter::ImplLineTo( const Point& rPoint, NMode nMode )
1416{
1417 ImplWritePoint( rPoint );
1418 ImplWriteByte( 'l' );
1419 ImplExecMode( nMode );
1420}
1421
1422void PSWriter::ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode )
1423{
1424 ImplWritePoint( rP1 );
1425 ImplWritePoint( rP2 );
1426 ImplWritePoint( rP3 );
1427 mpPS->WriteCharPtr( "ct " );
1428 ImplExecMode( nMode );
1429}
1430
1431void PSWriter::ImplTranslate( const double& fX, const double& fY )
1432{
1433 ImplWriteDouble( fX );
1434 ImplWriteDouble( fY );
1435 ImplWriteByte( 't' );
1436 ImplExecMode( PS_RET );
1437}
1438
1439void PSWriter::ImplScale( const double& fX, const double& fY )
1440{
1441 ImplWriteDouble( fX );
1442 ImplWriteDouble( fY );
1443 ImplWriteByte( 's' );
1444 ImplExecMode( PS_RET );
1445}
1446
1447void PSWriter::ImplRect( const tools::Rectangle & rRect )
1448{
1449 if ( bFillColor )
1450 ImplRectFill( rRect );
1451 if ( bLineColor )
1452 {
1453 double nWidth = rRect.GetWidth();
1454 double nHeight = rRect.GetHeight();
1455
1456 ImplWriteLineColor( PS_SPACE );
1457 ImplMoveTo( rRect.TopLeft() );
1458 ImplWriteDouble( nWidth );
1459 mpPS->WriteCharPtr( "0 rl 0 " );
1460 ImplWriteDouble( nHeight );
1461 mpPS->WriteCharPtr( "rl " );
1462 ImplWriteDouble( nWidth );
1463 mpPS->WriteCharPtr( "neg 0 rl " );
1464 ImplClosePathDraw();
1465 }
1466 mpPS->WriteUChar( 10 );
1467 mnCursorPos = 0;
1468}
1469
1470void PSWriter::ImplRectFill( const tools::Rectangle & rRect )
1471{
1472 double nWidth = rRect.GetWidth();
1473 double nHeight = rRect.GetHeight();
1474
1475 ImplWriteFillColor( PS_SPACE );
1476 ImplMoveTo( rRect.TopLeft() );
1477 ImplWriteDouble( nWidth );
1478 mpPS->WriteCharPtr( "0 rl 0 " );
1479 ImplWriteDouble( nHeight );
1480 mpPS->WriteCharPtr( "rl " );
1481 ImplWriteDouble( nWidth );
1482 mpPS->WriteCharPtr( "neg 0 rl ef " );
1483 mpPS->WriteCharPtr( "p ef" );
1484 mnCursorPos += 2;
1485 ImplExecMode( PS_RET );
1486}
1487
1488void PSWriter::ImplAddPath( const tools::Polygon & rPolygon )
1489{
1490 sal_uInt16 nPointCount = rPolygon.GetSize();
1491 if ( nPointCount <= 1 )
1492 return;
1493
1494 sal_uInt16 i = 1;
1495 ImplMoveTo( rPolygon.GetPoint( 0 ) );
1496 while ( i < nPointCount )
1497 {
1498 if ( ( rPolygon.GetFlags( i ) == PolyFlags::Control )
1499 && ( ( i + 2 ) < nPointCount )
1500 && ( rPolygon.GetFlags( i + 1 ) == PolyFlags::Control )
1501 && ( rPolygon.GetFlags( i + 2 ) != PolyFlags::Control ) )
1502 {
1503 ImplCurveTo( rPolygon[ i ], rPolygon[ i + 1 ], rPolygon[ i + 2 ], PS_WRAP );
1504 i += 3;
1505 }
1506 else
1507 ImplLineTo( rPolygon.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1508 }
1509}
1510
1511void PSWriter::ImplIntersect( const tools::PolyPolygon& rPolyPoly )
1512{
1513 sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1514 for ( i = 0; i < nPolyCount; )
1515 {
1516 ImplAddPath( rPolyPoly.GetObject( i ) );
1517 if ( ++i < nPolyCount )
1518 {
1519 mpPS->WriteCharPtr( "p" );
1520 mnCursorPos += 2;
1521 ImplExecMode( PS_RET );
1522 }
1523 }
1524 ImplWriteLine( "eoclip newpath" );
1525}
1526
1527void PSWriter::ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev )
1528{
1529 ScopedVclPtrInstance< VirtualDevice > l_pVDev;
1530 GDIMetaFile aTmpMtf;
1531 l_pVDev->SetMapMode( rVDev.GetMapMode() );
1532 l_pVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
1533 ImplWriteActions( aTmpMtf, rVDev );
1534}
1535
1536void PSWriter::ImplPolyPoly( const tools::PolyPolygon & rPolyPoly, bool bTextOutline )
1537{
1538 sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1539 if ( !nPolyCount )
1540 return;
1541
1542 if ( bFillColor || bTextOutline )
1543 {
1544 if ( bTextOutline )
1545 ImplWriteTextColor( PS_SPACE );
1546 else
1547 ImplWriteFillColor( PS_SPACE );
1548 for ( i = 0; i < nPolyCount; )
1549 {
1550 ImplAddPath( rPolyPoly.GetObject( i ) );
1551 if ( ++i < nPolyCount )
1552 {
1553 mpPS->WriteCharPtr( "p" );
1554 mnCursorPos += 2;
1555 ImplExecMode( PS_RET );
1556 }
1557 }
1558 mpPS->WriteCharPtr( "p ef" );
1559 mnCursorPos += 4;
1560 ImplExecMode( PS_RET );
1561 }
1562 if ( bLineColor )
1563 {
1564 ImplWriteLineColor( PS_SPACE );
1565 for ( i = 0; i < nPolyCount; i++ )
1566 ImplAddPath( rPolyPoly.GetObject( i ) );
1567 ImplClosePathDraw();
1568 }
1569}
1570
1571void PSWriter::ImplPolyLine( const tools::Polygon & rPoly )
1572{
1573 if ( !bLineColor )
1574 return;
1575
1576 ImplWriteLineColor( PS_SPACE );
1577 sal_uInt16 i, nPointCount = rPoly.GetSize();
1578 if ( !nPointCount )
1579 return;
1580
1581 if ( nPointCount > 1 )
1582 {
1583 ImplMoveTo( rPoly.GetPoint( 0 ) );
1584 i = 1;
1585 while ( i < nPointCount )
1586 {
1587 if ( ( rPoly.GetFlags( i ) == PolyFlags::Control )
1588 && ( ( i + 2 ) < nPointCount )
1589 && ( rPoly.GetFlags( i + 1 ) == PolyFlags::Control )
1590 && ( rPoly.GetFlags( i + 2 ) != PolyFlags::Control ) )
1591 {
1592 ImplCurveTo( rPoly[ i ], rPoly[ i + 1 ], rPoly[ i + 2 ], PS_WRAP );
1593 i += 3;
1594 }
1595 else
1596 ImplLineTo( rPoly.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1597 }
1598 }
1599
1600 // #104645# explicitly close path if polygon is closed
1601 if( rPoly[ 0 ] == rPoly[ nPointCount-1 ] )
1602 ImplClosePathDraw();
1603 else
1604 ImplPathDraw();
1605}
1606
1607void PSWriter::ImplSetClipRegion( vcl::Region const & rClipRegion )
1608{
1609 if ( rClipRegion.IsEmpty() )
1610 return;
1611
1612 RectangleVector aRectangles;
1613 rClipRegion.GetRegionRectangles(aRectangles);
1614
1615 for (auto const& rectangle : aRectangles)
1616 {
1617 double nX1(rectangle.Left());
1618 double nY1(rectangle.Top());
1619 double nX2(rectangle.Right());
1620 double nY2(rectangle.Bottom());
1621
1622 ImplWriteDouble( nX1 );
1623 ImplWriteDouble( nY1 );
1624 ImplWriteByte( 'm' );
1625 ImplWriteDouble( nX2 );
1626 ImplWriteDouble( nY1 );
1627 ImplWriteByte( 'l' );
1628 ImplWriteDouble( nX2 );
1629 ImplWriteDouble( nY2 );
1630 ImplWriteByte( 'l' );
1631 ImplWriteDouble( nX1 );
1632 ImplWriteDouble( nY2 );
1633 ImplWriteByte( 'l' );
1634 ImplWriteDouble( nX1 );
1635 ImplWriteDouble( nY1 );
1636 ImplWriteByte( 'l', PS_SPACE | PS_WRAP );
1637 }
1638
1639 ImplWriteLine( "eoclip newpath" );
1640}
1641
1642// possible gfx formats:
1643//
1644// level 1: grayscale 8 bit
1645// color 24 bit
1646//
1647// level 2: grayscale 8 bit
1648// color 1(pal), 4(pal), 8(pal), 24 Bit
1649//
1650
1651void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
1652{
1653 if ( !pBitmap )
1654 return;
1655
1656 sal_Int32 nHeightOrg = pBitmap->GetSizePixel().Height();
1657 sal_Int32 nHeightLeft = nHeightOrg;
1658 long nWidth = pBitmap->GetSizePixel().Width();
1659 Point aSourcePos( rPoint );
1660
1661 while ( nHeightLeft )
1662 {
1663 Bitmap aTileBitmap( *pBitmap );
1664 long nHeight = nHeightLeft;
1665 double nYHeight = nYHeightOrg;
1666
1667 bool bDoTrans = false;
1668
1669 tools::Rectangle aRect;
1670 vcl::Region aRegion;
1671
1672 if ( pMaskBitmap )
1673 {
1674 bDoTrans = true;
1675 while (true)
1676 {
1677 if ( mnLevel == 1 && nHeight > 10 )
1678 nHeight = 8;
1679 aRect = tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) );
1680 aRegion = pMaskBitmap->CreateRegion( COL_BLACK, aRect );
1681
1682 if( mnLevel == 1 )
1683 {
1684 RectangleVector aRectangleVector;
1685 aRegion.GetRegionRectangles(aRectangleVector);
1686
1687 if ( aRectangleVector.size() * 5 > 1000 )
1688 {
1689 nHeight >>= 1;
1690 if ( nHeight < 2 )
1691 return;
1692 continue;
1693 }
1694 }
1695 break;
1696 }
1697 }
1698 if ( nHeight != nHeightOrg )
1699 {
1700 nYHeight = nYHeightOrg * nHeight / nHeightOrg;
1701 aTileBitmap.Crop( tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) ) );
1702 }
1703 if ( bDoTrans )
1704 {
1705 ImplWriteLine( "gs\npum" );
1706 ImplTranslate( aSourcePos.X(), aSourcePos.Y() );
1707 ImplScale( nXWidth / nWidth, nYHeight / nHeight );
1708
1709 RectangleVector aRectangles;
1710 aRegion.GetRegionRectangles(aRectangles);
1711 const long nMoveVertical(nHeightLeft - nHeightOrg);
1712
1713 for (auto & rectangle : aRectangles)
1714 {
1715 rectangle.Move(0, nMoveVertical);
1716
1717 ImplWriteLong( rectangle.Left() );
1718 ImplWriteLong( rectangle.Top() );
1719 ImplWriteByte( 'm' );
1720 ImplWriteLong( rectangle.Right() + 1 );
1721 ImplWriteLong( rectangle.Top() );
1722 ImplWriteByte( 'l' );
1723 ImplWriteLong( rectangle.Right() + 1 );
1724 ImplWriteLong( rectangle.Bottom() + 1 );
1725 ImplWriteByte( 'l' );
1726 ImplWriteLong( rectangle.Left() );
1727 ImplWriteLong( rectangle.Bottom() + 1 );
1728 ImplWriteByte( 'l' );
1729 ImplWriteByte( 'p', PS_SPACE | PS_WRAP );
1730 }
1731
1732 ImplWriteLine( "eoclip newpath" );
1733 ImplWriteLine( "pom" );
1734 }
1735 BitmapReadAccess* pAcc = aTileBitmap.AcquireReadAccess();
1736
1737 if (!bDoTrans )
1738 ImplWriteLine( "pum" );
1739
1740 ImplTranslate( aSourcePos.X(), aSourcePos.Y() + nYHeight );
1741 ImplScale( nXWidth, nYHeight );
1742 if ( mnLevel == 1 ) // level 1 is always grayscale !!!
1743 {
1744 ImplWriteLong( nWidth );
1745 ImplWriteLong( nHeight );
1746 mpPS->WriteCharPtr( "8 [" );
1747 ImplWriteLong( nWidth );
1748 mpPS->WriteCharPtr( "0 0 " );
1749 ImplWriteLong( -nHeight );
1750 ImplWriteLong( 0 );
1751 ImplWriteLong( nHeight );
1752 ImplWriteLine( "]" );
1753 mpPS->WriteCharPtr( "{currentfile " );
1754 ImplWriteLong( nWidth );
1755 ImplWriteLine( "string readhexstring pop}" );
1756 ImplWriteLine( "image" );
1757 for ( long y = 0; y < nHeight; y++ )
1758 {
1759 Scanline pScanlineRead = pAcc->GetScanline( y );
1760 for ( long x = 0; x < nWidth; x++ )
1761 {
1762 ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1763 }
1764 }
1765 mpPS->WriteUChar( 10 );
1766 }
1767 else // Level 2
1768 {
1769 if ( mbGrayScale )
1770 {
1771 ImplWriteLine( "/DeviceGray setcolorspace" );
1772 ImplWriteLine( "<<" );
1773 ImplWriteLine( "/ImageType 1" );
1774 mpPS->WriteCharPtr( "/Width " );
1775 ImplWriteLong( nWidth, PS_RET );
1776 mpPS->WriteCharPtr( "/Height " );
1777 ImplWriteLong( nHeight, PS_RET );
1778 ImplWriteLine( "/BitsPerComponent 8" );
1779 ImplWriteLine( "/Decode[0 1]" );
1780 mpPS->WriteCharPtr( "/ImageMatrix[" );
1781 ImplWriteLong( nWidth );
1782 mpPS->WriteCharPtr( "0 0 " );
1783 ImplWriteLong( -nHeight );
1784 ImplWriteLong( 0 );
1785 ImplWriteLong( nHeight, PS_NONE );
1786 ImplWriteByte( ']', PS_RET );
1787 ImplWriteLine( "/DataSource currentfile" );
1788 ImplWriteLine( "/ASCIIHexDecode filter" );
1789 if ( mbCompression )
1790 ImplWriteLine( "/LZWDecode filter" );
1791 ImplWriteLine( ">>" );
1792 ImplWriteLine( "image" );
1793 if ( mbCompression )
1794 {
1795 StartCompression();
1796 for ( long y = 0; y < nHeight; y++ )
1797 {
1798 Scanline pScanlineRead = pAcc->GetScanline( y );
1799 for ( long x = 0; x < nWidth; x++ )
1800 {
1801 Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
1802 }
1803 }
1804 EndCompression();
1805 }
1806 else
1807 {
1808 for ( long y = 0; y < nHeight; y++ )
1809 {
1810 Scanline pScanlineRead = pAcc->GetScanline( y );
1811 for ( long x = 0; x < nWidth; x++ )
1812 {
1813 ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1814 }
1815 }
1816 }
1817 }
1818 else
1819 {
1820 // have we to write a palette ?
1821
1822 if ( pAcc->HasPalette() )
1823 {
1824 ImplWriteLine( "[/Indexed /DeviceRGB " );
1825 ImplWriteLong( pAcc->GetPaletteEntryCount() - 1, PS_RET );
1826 ImplWriteByte( '<', PS_NONE );
1827 for ( sal_uInt16 i = 0; i < pAcc->GetPaletteEntryCount(); i++ )
1828 {
1829 BitmapColor aBitmapColor = pAcc->GetPaletteColor( i );
1830 ImplWriteHexByte( aBitmapColor.GetRed(), PS_NONE );
1831 ImplWriteHexByte( aBitmapColor.GetGreen(), PS_NONE );
1832 ImplWriteHexByte( aBitmapColor.GetBlue(), PS_SPACE | PS_WRAP );
1833 }
1834 ImplWriteByte( '>', PS_RET );
1835
1836 ImplWriteLine( "] setcolorspace" );
1837 ImplWriteLine( "<<" );
1838 ImplWriteLine( "/ImageType 1" );
1839 mpPS->WriteCharPtr( "/Width " );
1840 ImplWriteLong( nWidth, PS_RET );
1841 mpPS->WriteCharPtr( "/Height " );
1842 ImplWriteLong( nHeight, PS_RET );
1843 ImplWriteLine( "/BitsPerComponent 8" );
1844 ImplWriteLine( "/Decode[0 255]" );
1845 mpPS->WriteCharPtr( "/ImageMatrix[" );
1846 ImplWriteLong( nWidth );
1847 mpPS->WriteCharPtr( "0 0 " );
1848 ImplWriteLong( -nHeight );
1849 ImplWriteLong( 0);
1850 ImplWriteLong( nHeight, PS_NONE );
1851 ImplWriteByte( ']', PS_RET );
1852 ImplWriteLine( "/DataSource currentfile" );
1853 ImplWriteLine( "/ASCIIHexDecode filter" );
1854 if ( mbCompression )
1855 ImplWriteLine( "/LZWDecode filter" );
1856 ImplWriteLine( ">>" );
1857 ImplWriteLine( "image" );
1858 if ( mbCompression )
1859 {
1860 StartCompression();
1861 for ( long y = 0; y < nHeight; y++ )
1862 {
1863 Scanline pScanlineRead = pAcc->GetScanline( y );
1864 for ( long x = 0; x < nWidth; x++ )
1865 {
1866 Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
1867 }
1868 }
1869 EndCompression();
1870 }
1871 else
1872 {
1873 for ( long y = 0; y < nHeight; y++ )
1874 {
1875 Scanline pScanlineRead = pAcc->GetScanline( y );
1876 for ( long x = 0; x < nWidth; x++ )
1877 {
1878 ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1879 }
1880 }
1881 }
1882 }
1883 else // 24 bit color
1884 {
1885 ImplWriteLine( "/DeviceRGB setcolorspace" );
1886 ImplWriteLine( "<<" );
1887 ImplWriteLine( "/ImageType 1" );
1888 mpPS->WriteCharPtr( "/Width " );
1889 ImplWriteLong( nWidth, PS_RET );
1890 mpPS->WriteCharPtr( "/Height " );
1891 ImplWriteLong( nHeight, PS_RET );
1892 ImplWriteLine( "/BitsPerComponent 8" );
1893 ImplWriteLine( "/Decode[0 1 0 1 0 1]" );
1894 mpPS->WriteCharPtr( "/ImageMatrix[" );
1895 ImplWriteLong( nWidth );
1896 mpPS->WriteCharPtr( "0 0 " );
1897 ImplWriteLong( -nHeight );
1898 ImplWriteLong( 0 );
1899 ImplWriteLong( nHeight, PS_NONE );
1900 ImplWriteByte( ']', PS_RET );
1901 ImplWriteLine( "/DataSource currentfile" );
1902 ImplWriteLine( "/ASCIIHexDecode filter" );
1903 if ( mbCompression )
1904 ImplWriteLine( "/LZWDecode filter" );
1905 ImplWriteLine( ">>" );
1906 ImplWriteLine( "image" );
1907 if ( mbCompression )
1908 {
1909 StartCompression();
1910 for ( long y = 0; y < nHeight; y++ )
1911 {
1912 Scanline pScanlineRead = pAcc->GetScanline( y );
1913 for ( long x = 0; x < nWidth; x++ )
1914 {
1915 const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanlineRead, x ) );
1916 Compress( aBitmapColor.GetRed() );
1917 Compress( aBitmapColor.GetGreen() );
1918 Compress( aBitmapColor.GetBlue() );
1919 }
1920 }
1921 EndCompression();
1922 }
1923 else
1924 {
1925 for ( long y = 0; y < nHeight; y++ )
1926 {
1927 Scanline pScanline = pAcc->GetScanline( y );
1928 for ( long x = 0; x < nWidth; x++ )
1929 {
1930 const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanline, x ) );
1931 ImplWriteHexByte( aBitmapColor.GetRed() );
1932 ImplWriteHexByte( aBitmapColor.GetGreen() );
1933 ImplWriteHexByte( aBitmapColor.GetBlue() );
1934 }
1935 }
1936 }
1937 }
1938 }
1939 ImplWriteLine( ">" ); // in Level 2 the dictionary needs to be closed (eod)
1940 }
1941 if ( bDoTrans )
1942 ImplWriteLine( "gr" );
1943 else
1944 ImplWriteLine( "pom" );
1945
1946 Bitmap::ReleaseAccess( pAcc );
1947 nHeightLeft -= nHeight;
1948 if ( nHeightLeft )
1949 {
1950 nHeightLeft++;
1951 aSourcePos.setY( static_cast<long>( rPoint.Y() + ( nYHeightOrg * ( nHeightOrg - nHeightLeft ) ) / nHeightOrg ) );
1952 }
1953 }
1954}
1955
1956void PSWriter::ImplWriteCharacter( char nChar )
1957{
1958 switch( nChar )
1959 {
1960 case '(' :
1961 case ')' :
1962 case '\\' :
1963 ImplWriteByte( sal_uInt8('\\'), PS_NONE );
1964 }
1965 ImplWriteByte( static_cast<sal_uInt8>(nChar), PS_NONE );
1966}
1967
1968void PSWriter::ImplWriteString( const OString& rString, VirtualDevice const & rVDev, const long* pDXArry, bool bStretch )
1969{
1970 sal_Int32 nLen = rString.getLength();
1971 if ( !nLen )
1972 return;
1973
1974 if ( pDXArry )
1975 {
1976 double nx = 0;
1977
1978 for (sal_Int32 i = 0; i < nLen; ++i)
1979 {
1980 if ( i > 0 )
1981 nx = pDXArry[ i - 1 ];
1982 ImplWriteDouble( bStretch ? nx : rVDev.GetTextWidth( OUString(rString[i]) ) );
1983 ImplWriteDouble( nx );
1984 ImplWriteLine( "(", PS_NONE );
1985 ImplWriteCharacter( rString[i] );
1986 ImplWriteLine( ") bs" );
1987 }
1988 }
1989 else
1990 {
1991 ImplWriteByte( '(', PS_NONE );
1992 for (sal_Int32 i = 0; i < nLen; ++i)
1993 ImplWriteCharacter( rString[i] );
1994 ImplWriteLine( ") sw" );
1995 }
1996}
1997
1998void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, const long* pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev )
1999{
2000 if ( rUniString.isEmpty() )
2001 return;
2002 if ( mnTextMode == 0 ) // using glyph outlines
2003 {
2004 vcl::Font aNotRotatedFont( maFont );
2005 aNotRotatedFont.SetOrientation( 0 );
2006
2007 ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::BITMASK);
2008 pVirDev->SetMapMode( rVDev.GetMapMode() );
2009 pVirDev->SetFont( aNotRotatedFont );
2010 pVirDev->SetTextAlign( eTextAlign );
2011
2012 sal_Int16 nRotation = maFont.GetOrientation();
2013 tools::Polygon aPolyDummy( 1 );
2014
2015 Point aPos( rPos );
2016 if ( nRotation )
2017 {
2018 aPolyDummy.SetPoint( aPos, 0 );
2019 aPolyDummy.Rotate( rPos, nRotation );
2020 aPos = aPolyDummy.GetPoint( 0 );
2021 }
2022 bool bOldLineColor = bLineColor;
2023 bLineColor = false;
2024 std::vector<tools::PolyPolygon> aPolyPolyVec;
2025 if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, -1, nWidth, pDXArry ) )
2026 {
2027 // always adjust text position to match baseline alignment
2028 ImplWriteLine( "pum" );
2029 ImplWriteDouble( aPos.X() );
2030 ImplWriteDouble( aPos.Y() );
2031 ImplWriteLine( "t" );
2032 if ( nRotation )
2033 {
2034 ImplWriteF( nRotation, 1 );
2035 mpPS->WriteCharPtr( "r " );
2036 }
2037 for (auto const& elem : aPolyPolyVec)
2038 ImplPolyPoly( elem, true );
2039 ImplWriteLine( "pom" );
2040 }
2041 bLineColor = bOldLineColor;
2042 }
2043 else if ( ( mnTextMode == 1 ) || ( mnTextMode == 2 ) ) // normal text output
2044 {
2045 if ( mnTextMode == 2 ) // forcing output one complete text packet, by
2046 pDXArry = nullptr; // ignoring the kerning array
2047 ImplSetAttrForText( rPos );
2048 OString aStr(OUStringToOString(rUniString,
2049 maFont.GetCharSet()));
2050 ImplWriteString( aStr, rVDev, pDXArry, nWidth != 0 );
2051 if ( maFont.GetOrientation() )
2052 ImplWriteLine( "gr" );
2053 }
2054}
2055
2056void PSWriter::ImplSetAttrForText( const Point& rPoint )
2057{
2058 Point aPoint( rPoint );
2059
2060 long nRotation = maFont.GetOrientation();
2061 ImplWriteTextColor(PS_RET);
2062
2063 Size aSize = maFont.GetFontSize();
2064
2065 if ( maLastFont != maFont )
2066 {
2067 if ( maFont.GetPitch() == PITCH_FIXED ) // a little bit font selection
2068 ImplDefineFont( "Courier", "Oblique" );
2069 else if ( maFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL(((rtl_TextEncoding) 10)) )
2070 ImplWriteLine( "/Symbol findfont" );
2071 else if ( maFont.GetFamilyType() == FAMILY_SWISS )
2072 ImplDefineFont( "Helvetica", "Oblique" );
2073 else
2074 ImplDefineFont( "Times", "Italic" );
2075
2076 maLastFont = maFont;
2077 aSize = maFont.GetFontSize();
2078 ImplWriteDouble( aSize.Height() );
2079 mpPS->WriteCharPtr( "sf " );
2080 }
2081 if ( eTextAlign != ALIGN_BASELINE )
2082 { // PostScript does not know about FontAlignment
2083 if ( eTextAlign == ALIGN_TOP ) // -> so I assume that
2084 aPoint.AdjustY( aSize.Height() * 4 / 5 ); // the area under the baseline
2085 else if ( eTextAlign == ALIGN_BOTTOM ) // is about 20% of the font size
2086 aPoint.AdjustY( -( aSize.Height() / 5 ) );
2087 }
2088 ImplMoveTo( aPoint );
2089 if ( nRotation )
2090 {
2091 mpPS->WriteCharPtr( "gs " );
2092 ImplWriteF( nRotation, 1 );
2093 mpPS->WriteCharPtr( "r " );
2094 }
2095}
2096
2097void PSWriter::ImplDefineFont( const char* pOriginalName, const char* pItalic )
2098{
2099 mpPS->WriteUChar( '/' ); //convert the font pOriginalName using ISOLatin1Encoding
2100 mpPS->WriteCharPtr( pOriginalName );
2101 switch ( maFont.GetWeight() )
2102 {
2103 case WEIGHT_SEMIBOLD :
2104 case WEIGHT_BOLD :
2105 case WEIGHT_ULTRABOLD :
2106 case WEIGHT_BLACK :
2107 mpPS->WriteCharPtr( "-Bold" );
2108 if ( maFont.GetItalic() != ITALIC_NONE )
2109 mpPS->WriteCharPtr( pItalic );
2110 break;
2111 default:
2112 if ( maFont.GetItalic() != ITALIC_NONE )
2113 mpPS->WriteCharPtr( pItalic );
2114 break;
2115 }
2116 ImplWriteLine( " f" );
2117}
2118
2119void PSWriter::ImplClosePathDraw()
2120{
2121 mpPS->WriteCharPtr( "pc" );
2122 mnCursorPos += 2;
2123 ImplExecMode( PS_RET );
2124}
2125
2126void PSWriter::ImplPathDraw()
2127{
2128 mpPS->WriteCharPtr( "ps" );
2129 mnCursorPos += 2;
2130 ImplExecMode( PS_RET );
2131}
2132
2133
2134inline void PSWriter::ImplWriteLineColor( NMode nMode )
2135{
2136 if ( aColor != aLineColor )
2137 {
2138 aColor = aLineColor;
2139 ImplWriteColor( nMode );
2140 }
2141}
2142
2143inline void PSWriter::ImplWriteFillColor( NMode nMode )
2144{
2145 if ( aColor != aFillColor )
2146 {
2147 aColor = aFillColor;
2148 ImplWriteColor( nMode );
2149 }
2150}
2151
2152inline void PSWriter::ImplWriteTextColor( NMode nMode )
2153{
2154 if ( aColor != aTextColor )
2155 {
2156 aColor = aTextColor;
2157 ImplWriteColor( nMode );
2158 }
2159}
2160
2161void PSWriter::ImplWriteColor( NMode nMode )
2162{
2163 if ( mbGrayScale )
2164 {
2165 // writes the Color (grayscale) as a Number from 0.000 up to 1.000
2166
2167 ImplWriteF( 1000 * ( aColor.GetRed() * 77 + aColor.GetGreen() * 151 +
2168 aColor.GetBlue() * 28 + 1 ) / 65536, 3, nMode );
2169 }
2170 else
2171 {
2172 ImplWriteB1 ( aColor.GetRed() );
2173 ImplWriteB1 ( aColor.GetGreen() );
2174 ImplWriteB1 ( aColor.GetBlue() );
2175 }
2176 mpPS->WriteCharPtr( "c" ); // ( c is defined as setrgbcolor or setgray )
2177 ImplExecMode( nMode );
2178}
2179
2180void PSWriter::ImplGetMapMode( const MapMode& rMapMode )
2181{
2182 ImplWriteLine( "tm setmatrix" );
2183 double fMul = ImplGetScaling(rMapMode);
2184 double fScaleX = static_cast<double>(rMapMode.GetScaleX()) * fMul;
2185 double fScaleY = static_cast<double>(rMapMode.GetScaleY()) * fMul;
2186 ImplTranslate( rMapMode.GetOrigin().X() * fScaleX, rMapMode.GetOrigin().Y() * fScaleY );
2187 ImplScale( fScaleX, fScaleY );
2188}
2189
2190inline void PSWriter::ImplExecMode( NMode nMode )
2191{
2192 if ( nMode & PS_WRAP )
2193 {
2194 if ( mnCursorPos >= PS_LINESIZE70 )
2195 {
2196 mnCursorPos = 0;
2197 mpPS->WriteUChar( 0xa );
2198 return;
2199 }
2200 }
2201 if ( nMode & PS_SPACE )
2202 {
2203 mpPS->WriteUChar( 32 );
2204 mnCursorPos++;
2205 }
2206 if ( nMode & PS_RET )
2207 {
2208 mpPS->WriteUChar( 0xa );
2209 mnCursorPos = 0;
2210 }
2211}
2212
2213inline void PSWriter::ImplWriteLine( const char* pString, NMode nMode )
2214{
2215 sal_uInt32 i = 0;
2216 while ( pString[ i ] )
2217 {
2218 mpPS->WriteUChar( pString[ i++ ] );
2219 }
2220 mnCursorPos += i;
2221 ImplExecMode( nMode );
2222}
2223
2224double PSWriter::ImplGetScaling( const MapMode& rMapMode )
2225{
2226 double nMul;
2227 switch (rMapMode.GetMapUnit())
2228 {
2229 case MapUnit::MapPixel :
2230 case MapUnit::MapSysFont :
2231 case MapUnit::MapAppFont :
2232
2233 case MapUnit::Map100thMM :
2234 nMul = 1;
2235 break;
2236 case MapUnit::Map10thMM :
2237 nMul = 10;
2238 break;
2239 case MapUnit::MapMM :
2240 nMul = 100;
2241 break;
2242 case MapUnit::MapCM :
2243 nMul = 1000;
2244 break;
2245 case MapUnit::Map1000thInch :
2246 nMul = 2.54;
2247 break;
2248 case MapUnit::Map100thInch :
2249 nMul = 25.4;
2250 break;
2251 case MapUnit::Map10thInch :
2252 nMul = 254;
2253 break;
2254 case MapUnit::MapInch :
2255 nMul = 2540;
2256 break;
2257 case MapUnit::MapTwip :
2258 nMul = 1.76388889;
2259 break;
2260 case MapUnit::MapPoint :
2261 nMul = 35.27777778;
2262 break;
2263 default:
2264 nMul = 1.0;
2265 break;
2266 }
2267 return nMul;
2268}
2269
2270
2271void PSWriter::ImplWriteLineInfo( double fLWidth, double fMLimit,
2272 SvtGraphicStroke::CapType eLCap,
2273 SvtGraphicStroke::JoinType eJoin,
2274 SvtGraphicStroke::DashArray const & rLDash )
2275{
2276 if ( fLineWidth != fLWidth )
2277 {
2278 fLineWidth = fLWidth;
2279 ImplWriteDouble( fLineWidth );
2280 ImplWriteLine( "lw", PS_SPACE );
2281 }
2282 if ( eLineCap != eLCap )
2283 {
2284 eLineCap = eLCap;
2285 ImplWriteLong( static_cast<sal_Int32>(eLineCap) );
2286 ImplWriteLine( "lc", PS_SPACE );
2287 }
2288 if ( eJoinType != eJoin )
2289 {
2290 eJoinType = eJoin;
2291 ImplWriteLong( static_cast<sal_Int32>(eJoinType) );
2292 ImplWriteLine( "lj", PS_SPACE );
2293 }
2294 if ( eJoinType == SvtGraphicStroke::joinMiter )
2295 {
2296 if ( fMiterLimit != fMLimit )
2297 {
2298 fMiterLimit = fMLimit;
2299 ImplWriteDouble( fMiterLimit );
2300 ImplWriteLine( "ml", PS_SPACE );
2301 }
2302 }
2303 if ( aDashArray != rLDash )
2304 {
2305 aDashArray = rLDash;
2306 sal_uInt32 j, i = aDashArray.size();
2307 ImplWriteLine( "[", PS_SPACE );
2308 for ( j = 0; j < i; j++ )
2309 ImplWriteDouble( aDashArray[ j ] );
2310 ImplWriteLine( "] 0 ld" );
2311 }
2312}
2313
2314void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
2315{
2316 SvtGraphicStroke::DashArray l_aDashArray;
2317 if ( rLineInfo.GetStyle() == LineStyle::Dash )
2318 l_aDashArray.push_back( 2 );
2319 const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5);
2320 SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter);
2321 SvtGraphicStroke::CapType aCapType(SvtGraphicStroke::capButt);
2322
2323 switch(rLineInfo.GetLineJoin())
2324 {
2325 case basegfx::B2DLineJoin::NONE:
2326 // do NOT use SvtGraphicStroke::joinNone here
2327 // since it will be written as numerical value directly
2328 // and is NOT a valid EPS value
2329 break;
2330 case basegfx::B2DLineJoin::Miter:
2331 aJoinType = SvtGraphicStroke::joinMiter;
2332 break;
2333 case basegfx::B2DLineJoin::Bevel:
2334 aJoinType = SvtGraphicStroke::joinBevel;
2335 break;
2336 case basegfx::B2DLineJoin::Round:
2337 aJoinType = SvtGraphicStroke::joinRound;
2338 break;
2339 }
2340 switch(rLineInfo.GetLineCap())
2341 {
2342 default: /* css::drawing::LineCap_BUTT */
2343 {
2344 aCapType = SvtGraphicStroke::capButt;
2345 break;
2346 }
2347 case css::drawing::LineCap_ROUND:
2348 {
2349 aCapType = SvtGraphicStroke::capRound;
2350 break;
2351 }
2352 case css::drawing::LineCap_SQUARE:
2353 {
2354 aCapType = SvtGraphicStroke::capSquare;
2355 break;
2356 }
2357 }
2358
2359 ImplWriteLineInfo( fLWidth, fMiterLimit, aCapType, aJoinType, l_aDashArray );
2360}
2361
2362void PSWriter::ImplWriteLong(sal_Int32 nNumber, NMode nMode)
2363{
2364 const OString aNumber(OString::number(nNumber));
2365 mnCursorPos += aNumber.getLength();
2366 mpPS->WriteOString( aNumber );
2367 ImplExecMode(nMode);
2368}
2369
2370void PSWriter::ImplWriteDouble( double fNumber )
2371{
2372 sal_Int32 nPTemp = static_cast<sal_Int32>(fNumber);
2373 sal_Int32 nATemp = labs( static_cast<sal_Int32>( ( fNumber - nPTemp ) * 100000 ) );
2374
2375 if ( !nPTemp && nATemp && ( fNumber < 0.0 ) )
2376 mpPS->WriteChar( '-' );
2377
2378 const OString aNumber1(OString::number(nPTemp));
2379 mpPS->WriteOString( aNumber1 );
2380 mnCursorPos += aNumber1.getLength();
2381
2382 if ( nATemp )
2383 {
2384 int zCount = 0;
2385 mpPS->WriteUChar( '.' );
2386 mnCursorPos++;
2387 const OString aNumber2(OString::number(nATemp));
2388
2389 sal_Int16 n, nLen = aNumber2.getLength();
2390 if ( nLen < 8 )
2391 {
2392 mnCursorPos += 6 - nLen;
2393 for ( n = 0; n < ( 5 - nLen ); n++ )
2394 {
2395 mpPS->WriteUChar( '0' );
2396 }
2397 }
2398 mnCursorPos += nLen;
2399 for ( n = 0; n < nLen; n++ )
2400 {
2401 mpPS->WriteChar( aNumber2[n] );
2402 zCount--;
2403 if ( aNumber2[n] != '0' )
2404 zCount = 0;
2405 }
2406 if ( zCount )
2407 mpPS->SeekRel( zCount );
2408 }
2409 ImplExecMode( PS_SPACE );
2410}
2411
2412/// Writes the number to stream: nNumber / ( 10^nCount )
2413void PSWriter::ImplWriteF( sal_Int32 nNumber, sal_uInt8 nCount, NMode nMode )
2414{
2415 if ( nNumber < 0 )
2416 {
2417 mpPS->WriteUChar( '-' );
2418 nNumber = -nNumber;
2419 mnCursorPos++;
2420 }
2421 const OString aScaleFactor(OString::number(nNumber));
2422 sal_uInt32 nLen = aScaleFactor.getLength();
2423 sal_Int32 const nStSize = (nCount + 1) - nLen;
2424 static_assert(sizeof(nStSize) == sizeof((nCount + 1) - nLen)); // tdf#134667
2425 if ( nStSize >= 1 )
2426 {
2427 mpPS->WriteUChar( '0' );
2428 mnCursorPos++;
2429 }
2430 if ( nStSize >= 2 )
2431 {
2432 mpPS->WriteUChar( '.' );
2433 for (sal_Int32 i = 1; i < nStSize; ++i)
2434 {
2435 mpPS->WriteUChar( '0' );
2436 mnCursorPos++;
2437 }
2438 }
2439 mnCursorPos += nLen;
2440 for( sal_uInt32 n = 0; n < nLen; n++ )
2441 {
2442 if ( n == nLen - nCount )
2443 {
2444 mpPS->WriteUChar( '.' );
2445 mnCursorPos++;
2446 }
2447 mpPS->WriteChar( aScaleFactor[n] );
2448 }
2449 ImplExecMode( nMode );
2450}
2451
2452void PSWriter::ImplWriteByte( sal_uInt8 nNumb, NMode nMode )
2453{
2454 mpPS->WriteUChar( nNumb );
2455 mnCursorPos++;
2456 ImplExecMode( nMode );
2457}
2458
2459void PSWriter::ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode )
2460{
2461 if ( ( nNumb >> 4 ) > 9 )
2462 mpPS->WriteUChar( ( nNumb >> 4 ) + 'A' - 10 );
2463 else
2464 mpPS->WriteUChar( ( nNumb >> 4 ) + '0' );
2465
2466 if ( ( nNumb & 0xf ) > 9 )
2467 mpPS->WriteUChar( ( nNumb & 0xf ) + 'A' - 10 );
2468 else
2469 mpPS->WriteUChar( ( nNumb & 0xf ) + '0' );
2470 mnCursorPos += 2;
2471 ImplExecMode( nMode );
2472}
2473
2474// writes the sal_uInt8 nNumb as a Number from 0.000 up to 1.000
2475
2476void PSWriter::ImplWriteB1( sal_uInt8 nNumb )
2477{
2478 ImplWriteF( 1000 * ( nNumb + 1 ) / 256 );
2479}
2480
2481inline void PSWriter::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
2482{
2483 dwShift |= ( nCode << ( nOffset - nCodeLen ) );
2484 nOffset -= nCodeLen;
2485 while ( nOffset < 24 )
2486 {
2487 ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
2488 dwShift <<= 8;
2489 nOffset += 8;
2490 }
2491 if ( nCode == 257 && nOffset != 32 )
2492 ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
2493}
2494
2495void PSWriter::StartCompression()
2496{
2497 sal_uInt16 i;
2498 nDataSize = 8;
2499
2500 nClearCode = 1 << nDataSize;
2501 nEOICode = nClearCode + 1;
2502 nTableSize = nEOICode + 1;
2503 nCodeSize = nDataSize + 1;
2504
2505 nOffset = 32; // number of free unused in dwShift
2506 dwShift = 0;
2507
2508 pTable.reset(new PSLZWCTreeNode[ 4096 ]);
2509
2510 for ( i = 0; i < 4096; i++ )
2511 {
2512 pTable[ i ].pBrother = pTable[ i ].pFirstChild = nullptr;
2513 pTable[ i ].nCode = i;
2514 pTable[ i ].nValue = static_cast<sal_uInt8>( i );
2515 }
2516 pPrefix = nullptr;
2517 WriteBits( nClearCode, nCodeSize );
2518}
2519
2520void PSWriter::Compress( sal_uInt8 nCompThis )
2521{
2522 PSLZWCTreeNode* p;
2523 sal_uInt16 i;
2524 sal_uInt8 nV;
2525
2526 if( !pPrefix )
2527 {
2528 pPrefix = pTable.get() + nCompThis;
2529 }
2530 else
2531 {
2532 nV = nCompThis;
2533 for( p = pPrefix->pFirstChild; p != nullptr; p = p->pBrother )
2534 {
2535 if ( p->nValue == nV )
2536 break;
2537 }
2538
2539 if( p )
2540 pPrefix = p;
2541 else
2542 {
2543 WriteBits( pPrefix->nCode, nCodeSize );
2544
2545 if ( nTableSize == 409 )
2546 {
2547 WriteBits( nClearCode, nCodeSize );
2548
2549 for ( i = 0; i < nClearCode; i++ )
2550 pTable[ i ].pFirstChild = nullptr;
2551
2552 nCodeSize = nDataSize + 1;
2553 nTableSize = nEOICode + 1;
2554 }
2555 else
2556 {
2557 if( nTableSize == static_cast<sal_uInt16>( ( 1 << nCodeSize ) - 1 ) )
2558 nCodeSize++;
2559
2560 p = pTable.get() + ( nTableSize++ );
2561 p->pBrother = pPrefix->pFirstChild;
2562 pPrefix->pFirstChild = p;
2563 p->nValue = nV;
2564 p->pFirstChild = nullptr;
2565 }
2566
2567 pPrefix = pTable.get() + nV;
2568 }
2569 }
2570}
2571
2572void PSWriter::EndCompression()
2573{
2574 if( pPrefix )
2575 WriteBits( pPrefix->nCode, nCodeSize );
2576
2577 WriteBits( nEOICode, nCodeSize );
2578 pTable.reset();
2579}
2580
2581sal_uInt8* PSWriter::ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize )
2582{
2583 while ( nComp-- >= nSize )
2584 {
2585 sal_uInt64 i;
2586 for ( i = 0; i < nSize; i++ )
2587 {
2588 if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
2589 break;
2590 }
2591 if ( i == nSize )
2592 return pSource;
2593 pSource++;
2594 }
2595 return nullptr;
2596}
2597
2598bool PSWriter::ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uInt32 nSize )
2599{
2600 bool bRetValue = false;
2601 sal_uInt32 nBytesRead;
2602
2603 if ( nSize < 256 ) // we assume that the file is greater than 256 bytes
2604 return false;
2605
2606 if ( nSize < POSTSCRIPT_BOUNDINGSEARCH0x1000 )
2607 nBytesRead = nSize;
2608 else
2609 nBytesRead = POSTSCRIPT_BOUNDINGSEARCH0x1000;
2610
2611 sal_uInt8* pDest = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%BoundingBox:"), nBytesRead, 14 );
2612 if ( pDest )
2613 {
2614 int nSecurityCount = 100; // only 100 bytes following the bounding box will be checked
2615 nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
2616 pDest += 14;
2617 for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
2618 {
2619 int nDivision = 1;
2620 bool bDivision = false;
2621 bool bNegative = false;
2622 bool bValid = true;
2623
2624 while ( ( --nSecurityCount ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) )
2625 pDest++;
2626 sal_uInt8 nByte = *pDest;
2627 while ( nSecurityCount && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
2628 {
2629 switch ( nByte )
2630 {
2631 case '.' :
2632 if ( bDivision )
2633 bValid = false;
2634 else
2635 bDivision = true;
2636 break;
2637 case '-' :
2638 bNegative = true;
2639 break;
2640 default :
2641 if ( ( nByte < '0' ) || ( nByte > '9' ) )
2642 nSecurityCount = 1; // error parsing the bounding box values
2643 else if ( bValid )
2644 {
2645 if ( bDivision )
2646 nDivision*=10;
2647 nNumb[i] *= 10;
2648 nNumb[i] += nByte - '0';
2649 }
2650 break;
2651 }
2652 nSecurityCount--;
2653 nByte = *(++pDest);
2654 }
2655 if ( bNegative )
2656 nNumb[i] = -nNumb[i];
2657 if ( bDivision && ( nDivision != 1 ) )
2658 nNumb[i] /= nDivision;
2659 }
2660 if ( nSecurityCount)
2661 bRetValue = true;
2662 }
2663 return bRetValue;
2664}
2665
2666//================== GraphicExport - the exported function ===================
2667
2668extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) bool
2669epsGraphicExport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pFilterConfigItem )
2670{
2671 PSWriter aPSWriter;
2672 return aPSWriter.WritePS( rGraphic, rStream, pFilterConfigItem );
2673}
2674
2675
2676/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

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

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

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

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
10.1
Field 'm_pBody' is non-null
10.1
Field 'm_pBody' is non-null
10.1
Field 'm_pBody' is non-null
10.1
Field 'm_pBody' is non-null
)
11
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
12
Calling 'VclReferenceBase::release'
16
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
19
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)
13
Assuming the condition is true
14
Taking true branch
40 delete this;
15
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