1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vclhelperbufferdevice.hxx>
21 #include <basegfx/range/b2drange.hxx>
22 #include <vcl/bitmapex.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <tools/stream.hxx>
25 #include <vcl/timer.hxx>
26 #include <comphelper/broadcasthelper.hxx>
27 #include <vcl/lazydelete.hxx>
29 //////////////////////////////////////////////////////////////////////////////
30 // buffered VDev usage
34 typedef ::std::vector
< VirtualDevice
* > aBuffers
;
36 class VDevBuffer
: public Timer
, protected comphelper::OBaseMutex
40 aBuffers maFreeBuffers
;
42 // allocated/used buffers (remembered to allow deleteing them in destructor)
43 aBuffers maUsedBuffers
;
47 virtual ~VDevBuffer();
49 VirtualDevice
* alloc(OutputDevice
& rOutDev
, const Size
& rSizePixel
, bool bClear
, bool bMono
);
50 void free(VirtualDevice
& rDevice
);
53 virtual void Timeout();
56 VDevBuffer::VDevBuffer()
61 SetTimeout(10L * 1000L); // ten seconds
64 VDevBuffer::~VDevBuffer()
66 ::osl::MutexGuard
aGuard(m_aMutex
);
69 while(!maFreeBuffers
.empty())
71 delete *(maFreeBuffers
.end() - 1);
72 maFreeBuffers
.pop_back();
75 while(!maUsedBuffers
.empty())
77 delete *(maUsedBuffers
.end() - 1);
78 maUsedBuffers
.pop_back();
82 VirtualDevice
* VDevBuffer::alloc(OutputDevice
& rOutDev
, const Size
& rSizePixel
, bool bClear
, bool bMono
)
84 ::osl::MutexGuard
aGuard(m_aMutex
);
85 VirtualDevice
* pRetval
= 0;
87 if(!maFreeBuffers
.empty())
90 aBuffers::iterator
aFound(maFreeBuffers
.end());
92 for(aBuffers::iterator
a(maFreeBuffers
.begin()); a
!= maFreeBuffers
.end(); ++a
)
94 OSL_ENSURE(*a
, "Empty pointer in VDevBuffer (!)");
96 if((bMono
&& 1 == (*a
)->GetBitCount()) || (!bMono
&& (*a
)->GetBitCount() > 1))
98 // candidate is valid due to bit depth
99 if(aFound
!= maFreeBuffers
.end())
105 const bool bCandidateOkay((*a
)->GetOutputWidthPixel() >= rSizePixel
.getWidth() && (*a
)->GetOutputHeightPixel() >= rSizePixel
.getHeight());
109 // found and candidate are valid
110 const sal_uLong
aSquare((*aFound
)->GetOutputWidthPixel() * (*aFound
)->GetOutputHeightPixel());
111 const sal_uLong
aCandidateSquare((*a
)->GetOutputWidthPixel() * (*a
)->GetOutputHeightPixel());
113 if(aCandidateSquare
< aSquare
)
115 // candidate is valid and smaller, use it
121 // found is valid, candidate is not. Keep found
126 // found is invalid, use candidate
128 bOkay
= (*aFound
)->GetOutputWidthPixel() >= rSizePixel
.getWidth() && (*aFound
)->GetOutputHeightPixel() >= rSizePixel
.getHeight();
133 // none yet, use candidate
135 bOkay
= (*aFound
)->GetOutputWidthPixel() >= rSizePixel
.getWidth() && (*aFound
)->GetOutputHeightPixel() >= rSizePixel
.getHeight();
140 if(aFound
!= maFreeBuffers
.end())
143 maFreeBuffers
.erase(aFound
);
149 pRetval
->Erase(Rectangle(0, 0, rSizePixel
.getWidth(), rSizePixel
.getHeight()));
154 pRetval
->SetOutputSizePixel(rSizePixel
, bClear
);
159 // no success yet, create new buffer
162 pRetval
= (bMono
) ? new VirtualDevice(rOutDev
, 1) : new VirtualDevice(rOutDev
);
163 pRetval
->SetOutputSizePixel(rSizePixel
, bClear
);
167 // reused, reset some values
168 pRetval
->SetMapMode();
171 // remember allocated buffer
172 maUsedBuffers
.push_back(pRetval
);
177 void VDevBuffer::free(VirtualDevice
& rDevice
)
179 ::osl::MutexGuard
aGuard(m_aMutex
);
180 const aBuffers::iterator
aUsedFound(::std::find(maUsedBuffers
.begin(), maUsedBuffers
.end(), &rDevice
));
181 OSL_ENSURE(aUsedFound
!= maUsedBuffers
.end(), "OOps, non-registered buffer freed (!)");
183 maUsedBuffers
.erase(aUsedFound
);
184 maFreeBuffers
.push_back(&rDevice
);
188 void VDevBuffer::Timeout()
190 ::osl::MutexGuard
aGuard(m_aMutex
);
192 while(!maFreeBuffers
.empty())
194 delete *(maFreeBuffers
.end() - 1);
195 maFreeBuffers
.pop_back();
200 //////////////////////////////////////////////////////////////////////////////
201 // support for rendering Bitmap and BitmapEx contents
203 namespace drawinglayer
205 // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
206 VDevBuffer
& getVDevBuffer()
208 // secure global instance with Vcl's safe desroyer of external (seen by
209 // library base) stuff, the remembered VDevs need to be deleted before
211 static vcl::DeleteOnDeinit
< VDevBuffer
> aVDevBuffer(new VDevBuffer());
212 return *aVDevBuffer
.get();
215 impBufferDevice::impBufferDevice(
216 OutputDevice
& rOutDev
,
217 const basegfx::B2DRange
& rRange
,
218 bool bAddOffsetToMapping
)
224 basegfx::B2DRange
aRangePixel(rRange
);
225 aRangePixel
.transform(mrOutDev
.GetViewTransformation());
226 const Rectangle
aRectPixel(
227 (sal_Int32
)floor(aRangePixel
.getMinX()), (sal_Int32
)floor(aRangePixel
.getMinY()),
228 (sal_Int32
)ceil(aRangePixel
.getMaxX()), (sal_Int32
)ceil(aRangePixel
.getMaxY()));
229 const Point aEmptyPoint
;
230 maDestPixel
= Rectangle(aEmptyPoint
, mrOutDev
.GetOutputSizePixel());
231 maDestPixel
.Intersection(aRectPixel
);
235 mpContent
= getVDevBuffer().alloc(mrOutDev
, maDestPixel
.GetSize(), false, false);
237 // #i93485# assert when copying from window to VDev is used
238 OSL_ENSURE(mrOutDev
.GetOutDevType() != OUTDEV_WINDOW
,
239 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");
241 const bool bWasEnabledSrc(mrOutDev
.IsMapModeEnabled());
242 mrOutDev
.EnableMapMode(false);
243 mpContent
->DrawOutDev(aEmptyPoint
, maDestPixel
.GetSize(), maDestPixel
.TopLeft(), maDestPixel
.GetSize(), mrOutDev
);
244 mrOutDev
.EnableMapMode(bWasEnabledSrc
);
246 MapMode
aNewMapMode(mrOutDev
.GetMapMode());
248 if(bAddOffsetToMapping
)
250 const Point
aLogicTopLeft(mrOutDev
.PixelToLogic(maDestPixel
.TopLeft()));
251 aNewMapMode
.SetOrigin(Point(-aLogicTopLeft
.X(), -aLogicTopLeft
.Y()));
254 mpContent
->SetMapMode(aNewMapMode
);
256 // copy AA flag for new target
257 mpContent
->SetAntialiasing(mrOutDev
.GetAntialiasing());
261 impBufferDevice::~impBufferDevice()
265 getVDevBuffer().free(*mpContent
);
270 getVDevBuffer().free(*mpMask
);
275 getVDevBuffer().free(*mpAlpha
);
279 void impBufferDevice::paint(double fTrans
)
283 const Point aEmptyPoint
;
284 const Size
aSizePixel(maDestPixel
.GetSize());
285 const bool bWasEnabledDst(mrOutDev
.IsMapModeEnabled());
286 static bool bDoSaveForVisualControl(false);
288 mrOutDev
.EnableMapMode(false);
289 mpContent
->EnableMapMode(false);
290 Bitmap
aContent(mpContent
->GetBitmap(aEmptyPoint
, aSizePixel
));
292 if(bDoSaveForVisualControl
)
294 SvFileStream
aNew((const String
&)String( "c:\\content.bmp" ), STREAM_WRITE
|STREAM_TRUNC
);
300 mpAlpha
->EnableMapMode(false);
301 const AlphaMask
aAlphaMask(mpAlpha
->GetBitmap(aEmptyPoint
, aSizePixel
));
303 if(bDoSaveForVisualControl
)
305 SvFileStream
aNew((const String
&)String( "c:\\transparence.bmp" ), STREAM_WRITE
|STREAM_TRUNC
);
306 aNew
<< aAlphaMask
.GetBitmap();
309 mrOutDev
.DrawBitmapEx(maDestPixel
.TopLeft(), BitmapEx(aContent
, aAlphaMask
));
313 mpMask
->EnableMapMode(false);
314 const Bitmap
aMask(mpMask
->GetBitmap(aEmptyPoint
, aSizePixel
));
316 if(bDoSaveForVisualControl
)
318 SvFileStream
aNew((const String
&)String( "c:\\mask.bmp" ), STREAM_WRITE
|STREAM_TRUNC
);
322 mrOutDev
.DrawBitmapEx(maDestPixel
.TopLeft(), BitmapEx(aContent
, aMask
));
324 else if(0.0 != fTrans
)
326 sal_uInt8
nMaskValue((sal_uInt8
)basegfx::fround(fTrans
* 255.0));
327 const AlphaMask
aAlphaMask(aSizePixel
, &nMaskValue
);
328 mrOutDev
.DrawBitmapEx(maDestPixel
.TopLeft(), BitmapEx(aContent
, aAlphaMask
));
332 mrOutDev
.DrawBitmap(maDestPixel
.TopLeft(), aContent
);
335 mrOutDev
.EnableMapMode(bWasEnabledDst
);
339 VirtualDevice
& impBufferDevice::getContent()
341 OSL_ENSURE(mpContent
, "impBufferDevice: No content, check isVisible() before accessing (!)");
345 VirtualDevice
& impBufferDevice::getMask()
347 OSL_ENSURE(mpContent
, "impBufferDevice: No content, check isVisible() before accessing (!)");
350 mpMask
= getVDevBuffer().alloc(mrOutDev
, maDestPixel
.GetSize(), true, true);
351 mpMask
->SetMapMode(mpContent
->GetMapMode());
353 // do NOT copy AA flag for mask!
359 VirtualDevice
& impBufferDevice::getTransparence()
361 OSL_ENSURE(mpContent
, "impBufferDevice: No content, check isVisible() before accessing (!)");
364 mpAlpha
= getVDevBuffer().alloc(mrOutDev
, maDestPixel
.GetSize(), true, false);
365 mpAlpha
->SetMapMode(mpContent
->GetMapMode());
367 // copy AA flag for new target; masking needs to be smooth
368 mpAlpha
->SetAntialiasing(mpContent
->GetAntialiasing());
373 } // end of namespace drawinglayer
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */