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 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_drawinglayer.hxx" 26 27 #include <vclhelperbufferdevice.hxx> 28 #include <basegfx/range/b2drange.hxx> 29 #include <vcl/bitmapex.hxx> 30 #include <basegfx/matrix/b2dhommatrix.hxx> 31 #include <tools/stream.hxx> 32 #include <vcl/timer.hxx> 33 #include <comphelper/broadcasthelper.hxx> 34 #include <vcl/lazydelete.hxx> 35 36 ////////////////////////////////////////////////////////////////////////////// 37 // buffered VDev usage 38 39 namespace 40 { 41 typedef ::std::vector< VirtualDevice* > aBuffers; 42 43 class VDevBuffer : public Timer, protected comphelper::OBaseMutex 44 { 45 private: 46 aBuffers maBuffers; 47 48 public: 49 VDevBuffer(); 50 virtual ~VDevBuffer(); 51 52 VirtualDevice* alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono); 53 void free(VirtualDevice& rDevice); 54 55 // Timer virtuals 56 virtual void Timeout(); 57 }; 58 59 VDevBuffer::VDevBuffer() 60 : Timer(), 61 maBuffers() 62 { 63 SetTimeout(10L * 1000L); // ten seconds 64 } 65 66 VDevBuffer::~VDevBuffer() 67 { 68 ::osl::MutexGuard aGuard(m_aMutex); 69 Stop(); 70 71 while(!maBuffers.empty()) 72 { 73 delete *(maBuffers.end() - 1); 74 maBuffers.pop_back(); 75 } 76 } 77 78 VirtualDevice* VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel, bool bClear, bool bMono) 79 { 80 ::osl::MutexGuard aGuard(m_aMutex); 81 VirtualDevice* pRetval = 0; 82 83 if(!maBuffers.empty()) 84 { 85 bool bOkay(false); 86 aBuffers::iterator aFound(maBuffers.end()); 87 88 for(aBuffers::iterator a(maBuffers.begin()); a != maBuffers.end(); a++) 89 { 90 OSL_ENSURE(*a, "Empty pointer in VDevBuffer (!)"); 91 92 if((bMono && 1 == (*a)->GetBitCount()) || (!bMono && (*a)->GetBitCount() > 1)) 93 { 94 // candidate is valid due to bit depth 95 if(aFound != maBuffers.end()) 96 { 97 // already found 98 if(bOkay) 99 { 100 // found is valid 101 const bool bCandidateOkay((*a)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*a)->GetOutputHeightPixel() >= rSizePixel.getHeight()); 102 103 if(bCandidateOkay) 104 { 105 // found and candidate are valid 106 const sal_uLong aSquare((*aFound)->GetOutputWidthPixel() * (*aFound)->GetOutputHeightPixel()); 107 const sal_uLong aCandidateSquare((*a)->GetOutputWidthPixel() * (*a)->GetOutputHeightPixel()); 108 109 if(aCandidateSquare < aSquare) 110 { 111 // candidate is valid and smaller, use it 112 aFound = a; 113 } 114 } 115 else 116 { 117 // found is valid, candidate is not. Keep found 118 } 119 } 120 else 121 { 122 // found is invalid, use candidate 123 aFound = a; 124 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 125 } 126 } 127 else 128 { 129 // none yet, use candidate 130 aFound = a; 131 bOkay = (*aFound)->GetOutputWidthPixel() >= rSizePixel.getWidth() && (*aFound)->GetOutputHeightPixel() >= rSizePixel.getHeight(); 132 } 133 } 134 } 135 136 if(aFound != maBuffers.end()) 137 { 138 pRetval = *aFound; 139 maBuffers.erase(aFound); 140 141 if(bOkay) 142 { 143 if(bClear) 144 { 145 pRetval->Erase(Rectangle(0, 0, rSizePixel.getWidth(), rSizePixel.getHeight())); 146 } 147 } 148 else 149 { 150 pRetval->SetOutputSizePixel(rSizePixel, bClear); 151 } 152 } 153 } 154 155 // no success yet, create new buffer 156 if(!pRetval) 157 { 158 pRetval = (bMono) ? new VirtualDevice(rOutDev, 1) : new VirtualDevice(rOutDev); 159 pRetval->SetOutputSizePixel(rSizePixel, bClear); 160 } 161 else 162 { 163 // reused, reset some values 164 pRetval->SetMapMode(); 165 } 166 167 return pRetval; 168 } 169 170 void VDevBuffer::free(VirtualDevice& rDevice) 171 { 172 ::osl::MutexGuard aGuard(m_aMutex); 173 maBuffers.push_back(&rDevice); 174 Start(); 175 } 176 177 void VDevBuffer::Timeout() 178 { 179 ::osl::MutexGuard aGuard(m_aMutex); 180 181 while(!maBuffers.empty()) 182 { 183 delete *(maBuffers.end() - 1); 184 maBuffers.pop_back(); 185 } 186 } 187 } 188 189 ////////////////////////////////////////////////////////////////////////////// 190 // support for rendering Bitmap and BitmapEx contents 191 192 namespace drawinglayer 193 { 194 // static global VDev buffer for the VclProcessor2D's (VclMetafileProcessor2D and VclPixelProcessor2D) 195 VDevBuffer& getVDevBuffer() 196 { 197 // secure global instance with Vcl's safe desroyer of external (seen by 198 // library base) stuff, the remembered VDevs need to be deleted before 199 // Vcl's deinit 200 static vcl::DeleteOnDeinit< VDevBuffer > aVDevBuffer(new VDevBuffer()); 201 return *aVDevBuffer.get(); 202 } 203 204 impBufferDevice::impBufferDevice( 205 OutputDevice& rOutDev, 206 const basegfx::B2DRange& rRange, 207 bool bAddOffsetToMapping) 208 : mrOutDev(rOutDev), 209 mpContent(0), 210 mpMask(0), 211 mpAlpha(0) 212 { 213 basegfx::B2DRange aRangePixel(rRange); 214 aRangePixel.transform(mrOutDev.GetViewTransformation()); 215 const Rectangle aRectPixel( 216 (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()), 217 (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY())); 218 const Point aEmptyPoint; 219 maDestPixel = Rectangle(aEmptyPoint, mrOutDev.GetOutputSizePixel()); 220 maDestPixel.Intersection(aRectPixel); 221 222 if(isVisible()) 223 { 224 mpContent = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), false, false); 225 226 // #i93485# assert when copying from window to VDev is used 227 OSL_ENSURE(mrOutDev.GetOutDevType() != OUTDEV_WINDOW, 228 "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)"); 229 230 const bool bWasEnabledSrc(mrOutDev.IsMapModeEnabled()); 231 mrOutDev.EnableMapMode(false); 232 mpContent->DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), mrOutDev); 233 mrOutDev.EnableMapMode(bWasEnabledSrc); 234 235 MapMode aNewMapMode(mrOutDev.GetMapMode()); 236 237 if(bAddOffsetToMapping) 238 { 239 const Point aLogicTopLeft(mrOutDev.PixelToLogic(maDestPixel.TopLeft())); 240 aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y())); 241 } 242 243 mpContent->SetMapMode(aNewMapMode); 244 245 // copy AA flag for new target 246 mpContent->SetAntialiasing(mrOutDev.GetAntialiasing()); 247 } 248 } 249 250 impBufferDevice::~impBufferDevice() 251 { 252 if(mpContent) 253 { 254 getVDevBuffer().free(*mpContent); 255 } 256 257 if(mpMask) 258 { 259 getVDevBuffer().free(*mpMask); 260 } 261 262 if(mpAlpha) 263 { 264 getVDevBuffer().free(*mpAlpha); 265 } 266 } 267 268 void impBufferDevice::paint(double fTrans) 269 { 270 if(isVisible()) 271 { 272 const Point aEmptyPoint; 273 const Size aSizePixel(maDestPixel.GetSize()); 274 const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled()); 275 static bool bDoSaveForVisualControl(false); 276 277 mrOutDev.EnableMapMode(false); 278 mpContent->EnableMapMode(false); 279 Bitmap aContent(mpContent->GetBitmap(aEmptyPoint, aSizePixel)); 280 281 if(bDoSaveForVisualControl) 282 { 283 SvFileStream aNew((const String&)String(ByteString( "c:\\content.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 284 aNew << aContent; 285 } 286 287 if(mpAlpha) 288 { 289 mpAlpha->EnableMapMode(false); 290 const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel)); 291 292 if(bDoSaveForVisualControl) 293 { 294 SvFileStream aNew((const String&)String(ByteString( "c:\\transparence.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 295 aNew << aAlphaMask.GetBitmap(); 296 } 297 298 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 299 } 300 else if(mpMask) 301 { 302 mpMask->EnableMapMode(false); 303 const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel)); 304 305 if(bDoSaveForVisualControl) 306 { 307 SvFileStream aNew((const String&)String(ByteString( "c:\\mask.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC); 308 aNew << aMask; 309 } 310 311 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask)); 312 } 313 else if(0.0 != fTrans) 314 { 315 sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0)); 316 const AlphaMask aAlphaMask(aSizePixel, &nMaskValue); 317 mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask)); 318 } 319 else 320 { 321 mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent); 322 } 323 324 mrOutDev.EnableMapMode(bWasEnabledDst); 325 } 326 } 327 328 VirtualDevice& impBufferDevice::getContent() 329 { 330 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 331 return *mpContent; 332 } 333 334 VirtualDevice& impBufferDevice::getMask() 335 { 336 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 337 if(!mpMask) 338 { 339 mpMask = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, true); 340 mpMask->SetMapMode(mpContent->GetMapMode()); 341 342 // do NOT copy AA flag for mask! 343 } 344 345 return *mpMask; 346 } 347 348 VirtualDevice& impBufferDevice::getTransparence() 349 { 350 OSL_ENSURE(mpContent, "impBufferDevice: No content, check isVisible() before accessing (!)"); 351 if(!mpAlpha) 352 { 353 mpAlpha = getVDevBuffer().alloc(mrOutDev, maDestPixel.GetSize(), true, false); 354 mpAlpha->SetMapMode(mpContent->GetMapMode()); 355 356 // copy AA flag for new target; masking needs to be smooth 357 mpAlpha->SetAntialiasing(mpContent->GetAntialiasing()); 358 } 359 360 return *mpAlpha; 361 } 362 } // end of namespace drawinglayer 363 364 ////////////////////////////////////////////////////////////////////////////// 365 // eof 366