1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_drawinglayer.hxx" 24 25 #include <vclhelperbufferdevice.hxx> 26 #include <basegfx/range/b2drange.hxx> 27 #include <vcl/bitmapex.hxx> 28 #include <basegfx/matrix/b2dhommatrix.hxx> 29 #include <tools/stream.hxx> 30 #include <vcl/timer.hxx> 31 #include <comphelper/broadcasthelper.hxx> 32 #include <vcl/lazydelete.hxx> 33 #include <vcl/dibtools.hxx> 34 35 ////////////////////////////////////////////////////////////////////////////// 36 // buffered VDev usage 37 38 namespace 39 { 40 typedef ::std::vector< VirtualDevice* > aBuffers; 41 42 class VDevBuffer : public Timer, protected comphelper::OBaseMutex 43 { 44 private: 45 // available buffers 46 aBuffers maFreeBuffers; 47 48 // allocated/used buffers (remembered to allow deleteing them in destructor) 49 aBuffers maUsedBuffers; 50 51 public: 52 VDevBuffer(); 53 virtual ~VDevBuffer(); 54 55 VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono); 56 void free(VirtualDevice& rDevice); 57 58 // Timer virtuals 59 virtual void Timeout(); 60 }; 61 VDevBuffer()62 VDevBuffer::VDevBuffer() 63 : Timer(), 64 maFreeBuffers(), 65 maUsedBuffers() 66 { 67 SetTimeout(10L * 1000L); // ten seconds 68 } 69 ~VDevBuffer()70 VDevBuffer::~VDevBuffer() 71 { 72 ::osl::MutexGuard aGuard(m_aMutex); 73 Stop(); 74 75 while(!maFreeBuffers.empty()) 76 { 77 delete *(maFreeBuffers.end() - 1); 78 maFreeBuffers.pop_back(); 79 } 80 81 while(!maUsedBuffers.empty()) 82 { 83 delete *(maUsedBuffers.end() - 1); 84 maUsedBuffers.pop_back(); 85 } 86 } 87 alloc(OutputDevice & rOutDev,const Size & rSizePixel,bool bClear,bool bMono)88 VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono) 89 { 90 ::osl::MutexGuard aGuard(m_aMutex); 91 VirtualDevice* pRetval = 0; 92 93 if(!maFreeBuffers.empty()) 94 { 95 bool bOkay(false); 96 aBuffers::iterator aFound(maFreeBuffers.end()); 97 98 for(aBuffers::iterator a(maFreeBuffers.begin()); a != maFreeBuffers.end(); a++) 99 { 100 OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)"); 101 102 if((bMono && 1 == (*a)->GetBitCount()) || (!bMono && (*a)->GetBitCount() > 1)) 103 { 104 // candidate is valid due to bit depth 105 if(aFound != maFreeBuffers.end()) 106 { 107 // already found 108 if(bOkay) 109 { 110 // found is valid 111 const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight()); 112 113 if(bCandidateOkay) 114 { 115 // found and candidate are valid 116 const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel()); 117 const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel()); 118 119 if(aCandidateSquare < aSquare) 120 { 121 // candidate is valid and smaller, use it 122 aFound = a; 123 } 124 } 125 else 126 { 127 // found is valid, candidate is not. Keep found 128 } 129 } 130 else 131 { 132 // found is invalid, use candidate 133 aFound = a; 134 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 135 } 136 } 137 else 138 { 139 // none yet, use candidate 140 aFound = a; 141 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 142 } 143 } 144 } 145 146 if(aFound != maFreeBuffers.end()) 147 { 148 pRetval = *aFound; 149 maFreeBuffers.erase(aFound); 150 151 if(bOkay) 152 { 153 if(bClear) 154 { 155 pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight())); 156 } 157 } 158 else 159 { 160 pRetval->SetOutputSizePixel(rSizePixel, bClear); 161 } 162 } 163 } 164 165 // no success yet, create new buffer 166 if(!pRetval) 167 { 168 pRetval = (bMono) ? new VirtualDevice(rOutDev, 1) : new VirtualDevice(rOutDev); 169 pRetval->SetOutputSizePixel(rSizePixel, bClear); 170 } 171 else 172 { 173 // reused, reset some values 174 pRetval->SetMapMode(); 175 } 176 177 // remember allocated buffer 178 maUsedBuffers.push_back(pRetval); 179 180 return pRetval; 181 } 182 free(VirtualDevice & rDevice)183 void VDevBuffer::free(VirtualDevice& rDevice) 184 { 185 ::osl::MutexGuard aGuard(m_aMutex); 186 const aBuffers::iterator aUsedFound(::std::find(maUsedBuffers.begin(), maUsedBuffers.end(), &rDevice)); 187 OSL_ENSURE(aUsedFound != maUsedBuffers.end(), "OOps, non-registered buffer freed (!)"); 188 189 maUsedBuffers.erase(aUsedFound); 190 maFreeBuffers.push_back(&rDevice); 191 Start(); 192 } 193 Timeout()194 void VDevBuffer::Timeout() 195 { 196 ::osl::MutexGuard aGuard(m_aMutex); 197 198 while(!maFreeBuffers.empty()) 199 { 200 delete *(maFreeBuffers.end() - 1); 201 maFreeBuffers.pop_back(); 202 } 203 } 204 } 205 206 ////////////////////////////////////////////////////////////////////////////// 207 // support for rendering Bitmap and BitmapEx contents 208 209 namespace drawinglayer 210 { 211 // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D) getVDevBuffer()212 VDevBuffer& getVDevBuffer() 213 { 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(); 219 } 220 impBufferDevice(OutputDevice & rOutDev,const basegfx::B2DRange & rRange,bool bAddOffsetToMapping)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) 229 { 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); 238 239 if(isVisible()) 240 { 241 mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false); 242 243 // #i93485# assert when copying from window to VDev is used 244 OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW, 245 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)"); 246 247 const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled()); 248 mrOutDev.EnableMapMode(false); 249 mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev); 250 mrOutDev.EnableMapMode(bWasEnabledSrc); 251 252 MapMode aNewMapMode(mrOutDev.GetMapMode()); 253 254 if(bAddOffsetToMapping) 255 { 256 const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft())); 257 aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y())); 258 } 259 260 mpContent->SetMapMode(aNewMapMode); 261 262 // copy AA flag for new target 263 mpContent->SetAntialiasing(mrOutDev.GetAntialiasing()); 264 } 265 } 266 ~impBufferDevice()267 impBufferDevice::~impBufferDevice() 268 { 269 if(mpContent) 270 { 271 getVDevBuffer().free(*mpContent); 272 } 273 274 if(mpMask) 275 { 276 getVDevBuffer().free(*mpMask); 277 } 278 279 if(mpAlpha) 280 { 281 getVDevBuffer().free(*mpAlpha); 282 } 283 } 284 paint(double fTrans)285 void impBufferDevice::paint(double fTrans) 286 { 287 if(isVisible()) 288 { 289 const Point aEmptyPoint; 290 const Size aSizePixel(maDestPixel.GetSize()); 291 const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled()); 292 static bool bDoSaveForVisualControl(false); 293 294 mrOutDev.EnableMapMode(false); 295 mpContent->EnableMapMode(false); 296 Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel)); 297 298 if(bDoSaveForVisualControl) 299 { 300 SvFileStream aNew((const String&)String(ByteString( "c:\\content.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 301 WriteDIB(aContent, aNew, false, true); 302 } 303 304 if(mpAlpha) 305 { 306 mpAlpha->EnableMapMode(false); 307 const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel)); 308 309 if(bDoSaveForVisualControl) 310 { 311 SvFileStream aNew((const String&)String(ByteString( "c:\\transparence.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 312 WriteDIB(aAlphaMask.GetBitmap(), aNew, false, true); 313 } 314 315 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 316 } 317 else if(mpMask) 318 { 319 mpMask->EnableMapMode(false); 320 const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel)); 321 322 if(bDoSaveForVisualControl) 323 { 324 SvFileStream aNew((const String&)String(ByteString( "c:\\mask.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 325 WriteDIB(aMask, aNew, false, true); 326 } 327 328 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask)); 329 } 330 else if(0.0 != fTrans) 331 { 332 sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0)); 333 const AlphaMask aAlphaMask(aSizePixel, &nMaskValue); 334 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 335 } 336 else 337 { 338 mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent); 339 } 340 341 mrOutDev.EnableMapMode(bWasEnabledDst); 342 } 343 } 344 getContent()345 VirtualDevice& impBufferDevice::getContent() 346 { 347 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 348 return *mpContent; 349 } 350 getMask()351 VirtualDevice& impBufferDevice::getMask() 352 { 353 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 354 if(!mpMask) 355 { 356 mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true); 357 mpMask->SetMapMode(mpContent->GetMapMode()); 358 359 // do NOT copy AA flag for mask! 360 } 361 362 return *mpMask; 363 } 364 getTransparence()365 VirtualDevice& impBufferDevice::getTransparence() 366 { 367 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 368 if(!mpAlpha) 369 { 370 mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false); 371 mpAlpha->SetMapMode(mpContent->GetMapMode()); 372 373 // copy AA flag for new target; masking needs to be smooth 374 mpAlpha->SetAntialiasing(mpContent->GetAntialiasing()); 375 } 376 377 return *mpAlpha; 378 } 379 } // end of namespace drawinglayer 380 381 ////////////////////////////////////////////////////////////////////////////// 382 // eof 383