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 #include "precompiled_sd.hxx" 25 26 #include "SlsLayeredDevice.hxx" 27 28 #include <vcl/window.hxx> 29 #include <vcl/virdev.hxx> 30 31 #include <boost/bind.hpp> 32 #include <boost/function.hpp> 33 34 35 namespace sd { namespace slidesorter { namespace view { 36 37 namespace { 38 static const sal_Int32 gnMaximumLayerCount = 8; 39 40 class LayerInvalidator : public ILayerInvalidator 41 { 42 public: 43 LayerInvalidator ( 44 const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice, 45 const SharedSdWindow& rpTargetWindow, 46 const int nLayer) 47 : mpLayeredDevice(rpLayeredDevice), 48 mpTargetWindow(rpTargetWindow), 49 mnLayer(nLayer) 50 { 51 } 52 53 virtual void Invalidate (const Rectangle& rInvalidationBox) 54 { 55 mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer); 56 mpTargetWindow->Invalidate(rInvalidationBox); 57 } 58 59 private: 60 const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; 61 SharedSdWindow mpTargetWindow; 62 const int mnLayer; 63 }; 64 65 void DeviceCopy ( 66 OutputDevice& rTargetDevice, 67 OutputDevice& rSourceDevice, 68 const Rectangle& rBox) 69 { 70 rTargetDevice.DrawOutDev( 71 rBox.TopLeft(), 72 rBox.GetSize(), 73 rBox.TopLeft(), 74 rBox.GetSize(), 75 rSourceDevice); 76 } 77 78 79 void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction) 80 { 81 OSL_ASSERT(aFunction); 82 RectangleVector aRectangles; 83 rRegion.GetRegionRectangles(aRectangles); 84 85 if(0 == aRectangles.size()) 86 { 87 aFunction(Rectangle()); 88 } 89 else 90 { 91 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++) 92 { 93 aFunction(*aRectIter); 94 } 95 96 //Region aMutableRegionCopy (rRegion); 97 //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); 98 //Rectangle aBox; 99 //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox)) 100 // aFunction(aBox); 101 //aMutableRegionCopy.EndEnumRects(aHandle); 102 } 103 } 104 105 class Layer : private ::boost::noncopyable 106 { 107 public: 108 Layer (void); 109 ~Layer (void); 110 111 void Initialize (const SharedSdWindow& rpTargetWindow); 112 void InvalidateRectangle (const Rectangle& rInvalidationBox); 113 void InvalidateRegion (const Region& rInvalidationRegion); 114 void Validate (const MapMode& rMapMode); 115 void Repaint ( 116 OutputDevice& rTargetDevice, 117 const Rectangle& rRepaintRectangle); 118 void Resize (const Size& rSize); 119 void AddPainter (const SharedILayerPainter& rpPainter); 120 void RemovePainter (const SharedILayerPainter& rpPainter); 121 bool HasPainter (void) const; 122 void Dispose (void); 123 124 private: 125 ::boost::shared_ptr<VirtualDevice> mpLayerDevice; 126 ::std::vector<SharedILayerPainter> maPainters; 127 Region maInvalidationRegion; 128 129 void ValidateRectangle (const Rectangle& rBox); 130 }; 131 typedef ::boost::shared_ptr<Layer> SharedLayer; 132 133 134 } // end of anonymous namespace 135 136 137 class LayeredDevice::LayerContainer : public ::std::vector<SharedLayer> 138 { 139 public: 140 LayerContainer (void) {} 141 ~LayerContainer (void) {} 142 }; 143 144 145 146 147 //===== LayeredDevice ========================================================= 148 149 LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow) 150 : mpTargetWindow(rpTargetWindow), 151 mpLayers(new LayerContainer()), 152 mpBackBuffer(new VirtualDevice(*mpTargetWindow)), 153 maSavedMapMode(rpTargetWindow->GetMapMode()) 154 { 155 mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel()); 156 } 157 158 159 160 161 LayeredDevice::~LayeredDevice (void) 162 { 163 } 164 165 166 167 168 void LayeredDevice::Invalidate ( 169 const Rectangle& rInvalidationArea, 170 const sal_Int32 nLayer) 171 { 172 if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) 173 { 174 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); 175 return; 176 } 177 178 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); 179 } 180 181 182 183 184 void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea) 185 { 186 for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) 187 (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); 188 } 189 190 191 192 193 void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion) 194 { 195 for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) 196 (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion); 197 } 198 199 200 201 202 void LayeredDevice::RegisterPainter ( 203 const SharedILayerPainter& rpPainter, 204 const sal_Int32 nLayer) 205 { 206 OSL_ASSERT(mpLayers); 207 if ( ! rpPainter) 208 { 209 OSL_ASSERT(rpPainter); 210 return; 211 } 212 if (nLayer<0 || nLayer>=gnMaximumLayerCount) 213 { 214 OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount); 215 return; 216 } 217 218 // Provide the layers. 219 if (sal_uInt32(nLayer) >= mpLayers->size()) 220 { 221 const sal_Int32 nOldLayerCount (mpLayers->size()); 222 mpLayers->resize(nLayer+1); 223 224 for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex) 225 (*mpLayers)[nIndex].reset(new Layer()); 226 } 227 228 (*mpLayers)[nLayer]->AddPainter(rpPainter); 229 if (nLayer == 0) 230 (*mpLayers)[nLayer]->Initialize(mpTargetWindow); 231 232 rpPainter->SetLayerInvalidator( 233 SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer))); 234 } 235 236 237 238 239 void LayeredDevice::RemovePainter ( 240 const SharedILayerPainter& rpPainter, 241 const sal_Int32 nLayer) 242 { 243 if ( ! rpPainter) 244 { 245 OSL_ASSERT(rpPainter); 246 return; 247 } 248 if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) 249 { 250 OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); 251 return; 252 } 253 254 rpPainter->SetLayerInvalidator(SharedILayerInvalidator()); 255 256 (*mpLayers)[nLayer]->RemovePainter(rpPainter); 257 258 // Remove top most layers that do not contain any painters. 259 while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter()) 260 mpLayers->erase(mpLayers->end()-1); 261 } 262 263 264 265 266 bool LayeredDevice::HasPainter (const sal_Int32 nLayer) 267 { 268 return nLayer>=0 269 && sal_uInt32(nLayer)<mpLayers->size() 270 && (*mpLayers)[nLayer]->HasPainter(); 271 } 272 273 274 275 276 void LayeredDevice::Repaint (const Region& rRepaintRegion) 277 { 278 // Validate the contents of all layers (that have their own devices.) 279 ::std::for_each( 280 mpLayers->begin(), 281 mpLayers->end(), 282 ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode())); 283 284 ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1)); 285 } 286 287 288 289 290 void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle) 291 { 292 if (mpLayers->size() == 0) 293 return; 294 else if (mpLayers->size() == 1) 295 { 296 // Just copy the main layer into the target device. 297 (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle); 298 } 299 else 300 { 301 // Paint all layers first into the back buffer (to avoid flickering 302 // due to synchronous paints) and then copy that into the target 303 // device. 304 mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode()); 305 ::std::for_each( 306 mpLayers->begin(), 307 mpLayers->end(), 308 ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle)); 309 310 DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle); 311 } 312 } 313 314 315 316 317 void LayeredDevice::Resize (void) 318 { 319 const Size aSize (mpTargetWindow->GetSizePixel()); 320 mpBackBuffer->SetOutputSizePixel(aSize); 321 ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize)); 322 } 323 324 325 326 327 void LayeredDevice::Dispose (void) 328 { 329 ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1)); 330 mpLayers->clear(); 331 } 332 333 334 335 336 bool LayeredDevice::HandleMapModeChange (void) 337 { 338 const MapMode& rMapMode (mpTargetWindow->GetMapMode()); 339 if (maSavedMapMode == rMapMode) 340 return false; 341 342 const Rectangle aLogicWindowBox ( 343 mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel()))); 344 if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX() 345 || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY() 346 || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit()) 347 { 348 // When the scale has changed then we have to paint everything. 349 InvalidateAllLayers(aLogicWindowBox); 350 } 351 else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin()) 352 { 353 // Window has been scrolled. Adapt contents of backbuffers and 354 // layer devices. 355 const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin()); 356 mpBackBuffer->CopyArea( 357 aLogicWindowBox.TopLeft(), 358 mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode), 359 aLogicWindowBox.GetSize()); 360 361 // Invalidate the area(s) that have been exposed. 362 const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel()); 363 if (aDelta.Y() < 0) 364 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( 365 aWindowBox.Left(), 366 aWindowBox.Bottom()+aDelta.Y(), 367 aWindowBox.Right(), 368 aWindowBox.Bottom()))); 369 else if (aDelta.Y() > 0) 370 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( 371 aWindowBox.Left(), 372 aWindowBox.Top(), 373 aWindowBox.Right(), 374 aWindowBox.Top()+aDelta.Y()))); 375 if (aDelta.X() < 0) 376 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( 377 aWindowBox.Right()+aDelta.X(), 378 aWindowBox.Top(), 379 aWindowBox.Right(), 380 aWindowBox.Bottom()))); 381 else if (aDelta.X() > 0) 382 InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( 383 aWindowBox.Left(), 384 aWindowBox.Top(), 385 aWindowBox.Left()+aDelta.X(), 386 aWindowBox.Bottom()))); 387 } 388 else 389 { 390 // Can this happen? Lets trigger a warning when it does. 391 OSL_ASSERT(false); 392 } 393 394 maSavedMapMode = rMapMode; 395 396 return true; 397 } 398 399 400 401 402 //===== Layer ================================================================= 403 404 Layer::Layer (void) 405 : mpLayerDevice(), 406 maPainters(), 407 maInvalidationRegion() 408 { 409 } 410 411 412 413 414 Layer::~Layer (void) 415 { 416 } 417 418 419 420 421 void Layer::Initialize (const SharedSdWindow& rpTargetWindow) 422 { 423 #if 0 424 (void)rpTargetWindow; 425 #else 426 if ( ! mpLayerDevice) 427 { 428 mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow)); 429 mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel()); 430 } 431 #endif 432 } 433 434 435 436 437 void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox) 438 { 439 maInvalidationRegion.Union(rInvalidationBox); 440 } 441 442 443 444 445 void Layer::InvalidateRegion (const Region& rInvalidationRegion) 446 { 447 maInvalidationRegion.Union(rInvalidationRegion); 448 } 449 450 451 452 453 void Layer::Validate (const MapMode& rMapMode) 454 { 455 if (mpLayerDevice && ! maInvalidationRegion.IsEmpty()) 456 { 457 Region aRegion (maInvalidationRegion); 458 maInvalidationRegion.SetEmpty(); 459 460 mpLayerDevice->SetMapMode(rMapMode); 461 ForAllRectangles( 462 aRegion, 463 ::boost::bind(&Layer::ValidateRectangle, this, _1)); 464 } 465 } 466 467 468 469 470 void Layer::ValidateRectangle (const Rectangle& rBox) 471 { 472 if ( ! mpLayerDevice) 473 return; 474 const Region aSavedClipRegion (mpLayerDevice->GetClipRegion()); 475 mpLayerDevice->IntersectClipRegion(rBox); 476 477 for (::std::vector<SharedILayerPainter>::const_iterator 478 iPainter(maPainters.begin()), 479 iEnd(maPainters.end()); 480 iPainter!=iEnd; 481 ++iPainter) 482 { 483 (*iPainter)->Paint(*mpLayerDevice, rBox); 484 } 485 486 mpLayerDevice->SetClipRegion(aSavedClipRegion); 487 } 488 489 490 491 492 void Layer::Repaint ( 493 OutputDevice& rTargetDevice, 494 const Rectangle& rRepaintRectangle) 495 { 496 if (mpLayerDevice) 497 { 498 DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle); 499 } 500 else 501 { 502 ::std::for_each( 503 maPainters.begin(), 504 maPainters.end(), 505 ::boost::bind(&ILayerPainter::Paint, 506 _1, 507 ::boost::ref(rTargetDevice), 508 rRepaintRectangle)); 509 } 510 } 511 512 513 514 515 void Layer::Resize (const Size& rSize) 516 { 517 if (mpLayerDevice) 518 { 519 mpLayerDevice->SetOutputSizePixel(rSize); 520 maInvalidationRegion = Rectangle(Point(0,0), rSize); 521 } 522 } 523 524 525 526 527 void Layer::AddPainter (const SharedILayerPainter& rpPainter) 528 { 529 OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end()); 530 531 maPainters.push_back(rpPainter); 532 } 533 534 535 536 537 void Layer::RemovePainter (const SharedILayerPainter& rpPainter) 538 { 539 const ::std::vector<SharedILayerPainter>::iterator iPainter ( 540 ::std::find(maPainters.begin(), maPainters.end(), rpPainter)); 541 if (iPainter != maPainters.end()) 542 { 543 maPainters.erase(iPainter); 544 } 545 else 546 { 547 DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered"); 548 } 549 } 550 551 552 553 554 bool Layer::HasPainter (void) const 555 { 556 return !maPainters.empty(); 557 } 558 559 560 561 562 void Layer::Dispose (void) 563 { 564 maPainters.clear(); 565 } 566 567 568 } } } // end of namespace ::sd::slidesorter::view 569