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