update emoji autocorrect entries from po-files
[LibreOffice.git] / drawinglayer / source / processor2d / vclhelperbufferdevice.cxx
blob93919c0019a2110674b3919c26bf376a8bf9b83f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
28 #include <vcl/dibtools.hxx>
31 // buffered VDev usage
33 namespace
35 typedef ::std::vector< VclPtr<VirtualDevice> > aBuffers;
37 class VDevBuffer : public Timer, protected comphelper::OBaseMutex
39 private:
40 // available buffers
41 aBuffers maFreeBuffers;
43 // allocated/used buffers (remembered to allow deleting them in destructor)
44 aBuffers maUsedBuffers;
46 public:
47 VDevBuffer();
48 virtual ~VDevBuffer();
50 VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits);
51 void free(VirtualDevice& rDevice);
53 // Timer virtuals
54 virtual void Invoke() SAL_OVERRIDE;
57 VDevBuffer::VDevBuffer()
58 : Timer(),
59 maFreeBuffers(),
60 maUsedBuffers()
62 SetTimeout(10L * 1000L); // ten seconds
65 VDevBuffer::~VDevBuffer()
67 ::osl::MutexGuard aGuard(m_aMutex);
68 Stop();
70 while(!maFreeBuffers.empty())
72 (*(maFreeBuffers.end() - 1)).disposeAndClear();
73 maFreeBuffers.pop_back();
76 while(!maUsedBuffers.empty())
78 (*(maUsedBuffers.end() - 1)).disposeAndClear();
79 maUsedBuffers.pop_back();
83 VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, sal_Int32 nBits)
85 ::osl::MutexGuard aGuard(m_aMutex);
86 VirtualDevice* pRetval = 0;
88 if (nBits == 0)
89 nBits = rOutDev.GetBitCount();
91 if(!maFreeBuffers.empty())
93 bool bOkay(false);
94 aBuffers::iterator aFound(maFreeBuffers.end());
96 for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); ++a)
98 OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)");
100 if(nBits == (*a)->GetBitCount())
102 // candidate is valid due to bit depth
103 if(aFound != maFreeBuffers.end())
105 // already found
106 if(bOkay)
108 // found is valid
109 const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight());
111 if(bCandidateOkay)
113 // found and candidate are valid
114 const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel());
115 const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel());
117 if(aCandidateSquare < aSquare)
119 // candidate is valid and smaller, use it
120 aFound = a;
123 else
125 // found is valid, candidate is not. Keep found
128 else
130 // found is invalid, use candidate
131 aFound = a;
132 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
135 else
137 // none yet, use candidate
138 aFound = a;
139 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight();
144 if(aFound != maFreeBuffers.end())
146 pRetval = *aFound;
147 maFreeBuffers.erase(aFound);
149 if(bOkay)
151 if(bClear)
153 pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight()));
156 else
158 pRetval->SetOutputSizePixel(rSizePixel, bClear);
163 // no success yet, create new buffer
164 if(!pRetval)
166 pRetval = VclPtr<VirtualDevice>::Create(rOutDev, nBits);
167 pRetval->SetOutputSizePixel(rSizePixel, bClear);
169 else
171 // reused, reset some values
172 pRetval->SetMapMode();
175 // remember allocated buffer
176 maUsedBuffers.push_back(pRetval);
178 return pRetval;
181 void VDevBuffer::free(VirtualDevice& rDevice)
183 ::osl::MutexGuard aGuard(m_aMutex);
184 const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice));
185 OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)");
187 maUsedBuffers.erase(aUsedFound);
188 maFreeBuffers.push_back(&rDevice);
189 SAL_WARN_IF(maFreeBuffers.size() > 1000, "drawinglayer", "excessive cached buffers, "
190 << maFreeBuffers.size() << " entries!");
191 Start();
194 void VDevBuffer::Invoke()
196 ::osl::MutexGuard aGuard(m_aMutex);
198 while(!maFreeBuffers.empty())
200 (*(maFreeBuffers.end() - 1)).disposeAndClear();
201 maFreeBuffers.pop_back();
207 // support for rendering Bitmap and BitmapEx contents
209 namespace drawinglayer
211 // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D)
212 VDevBuffer& getVDevBuffer()
214 // secure global instance with Vcl's safe desroyer of external (seen by
215 // library base) stuff, the remembered VDevs need to be deleted before
216 // Vcl's deinit
217 static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer());
218 return *aVDevBuffer.get();
221 impBufferDevice::impBufferDevice(
222 OutputDevice& rOutDev,
223 const basegfx::B2DRange& rRange,
224 bool bAddOffsetToMapping)
225 : mrOutDev(rOutDev),
226 mpContent(0),
227 mpMask(0),
228 mpAlpha(0)
230 basegfx::B2DRange aRangePixel(rRange);
231 aRangePixel.transform(mrOutDev.GetViewTransformation());
232 const Rectangle aRectPixel(
233 (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
234 (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
235 const Point aEmptyPoint;
236 maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel());
237 maDestPixel.Intersection(aRectPixel);
239 if(isVisible())
241 #ifdef IOS
242 // Exact mechanism unknown, but for some reason SmartArt
243 // rendering, especially shadows, is broken on iOS unless
244 // we pass 'true' here. Are virtual devices always de
245 // facto cleared when created on other platforms?
246 mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
247 #else
248 mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, 0);
249 #endif
251 // #i93485# assert when copying from window to VDev is used
252 OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW,
253 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");
255 const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled());
256 mrOutDev.EnableMapMode(false);
257 mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev);
258 mrOutDev.EnableMapMode(bWasEnabledSrc);
260 MapMode aNewMapMode(mrOutDev.GetMapMode());
262 if(bAddOffsetToMapping)
264 const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft()));
265 aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
268 mpContent->SetMapMode(aNewMapMode);
270 // copy AA flag for new target
271 mpContent->SetAntialiasing(mrOutDev.GetAntialiasing());
275 impBufferDevice::~impBufferDevice()
277 if(mpContent)
279 getVDevBuffer().free(*mpContent);
282 if(mpMask)
284 getVDevBuffer().free(*mpMask);
287 if(mpAlpha)
289 getVDevBuffer().free(*mpAlpha);
293 void impBufferDevice::paint(double fTrans)
295 if(isVisible())
297 const Point aEmptyPoint;
298 const Size aSizePixel(maDestPixel.GetSize());
299 const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
300 static bool bDoSaveForVisualControl(false);
302 mrOutDev.EnableMapMode(false);
303 mpContent->EnableMapMode(false);
304 Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel));
306 if(bDoSaveForVisualControl)
308 SvFileStream aNew( "c:\\content.bmp", StreamMode::WRITE|StreamMode::TRUNC);
309 WriteDIB(aContent, aNew, false, true);
312 if(mpAlpha)
314 mpAlpha->EnableMapMode(false);
315 const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
317 if(bDoSaveForVisualControl)
319 SvFileStream aNew( "c:\\transparence.bmp", StreamMode::WRITE|StreamMode::TRUNC);
320 WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true);
323 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
325 else if(mpMask)
327 mpMask->EnableMapMode(false);
328 const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));
330 if(bDoSaveForVisualControl)
332 SvFileStream aNew( "c:\\mask.bmp", StreamMode::WRITE|StreamMode::TRUNC);
333 WriteDIB(aMask, aNew, false, true);
336 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
338 else if(0.0 != fTrans)
340 sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
341 const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
342 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
344 else
346 mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
349 mrOutDev.EnableMapMode(bWasEnabledDst);
353 VirtualDevice& impBufferDevice::getContent()
355 assert(mpContent && "impBufferDevice: No content, check isVisible() before accessing (!)");
356 return *mpContent;
359 VirtualDevice& impBufferDevice::getMask()
361 assert(mpContent && "impBufferDevice: No content, check isVisible() before accessing (!)");
362 if (!mpMask)
364 mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 1);
365 mpMask->SetMapMode(mpContent->GetMapMode());
367 // do NOT copy AA flag for mask!
370 return *mpMask;
373 VirtualDevice& impBufferDevice::getTransparence()
375 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)");
376 if(!mpAlpha)
378 mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, 0);
379 mpAlpha->SetMapMode(mpContent->GetMapMode());
381 // copy AA flag for new target; masking needs to be smooth
382 mpAlpha->SetAntialiasing(mpContent->GetAntialiasing());
385 return *mpAlpha;
387 } // end of namespace drawinglayer
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */