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