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