view/src/nsViewManager.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
michael@0 7 #include "plarena.h"
michael@0 8
michael@0 9 #include "nsAutoPtr.h"
michael@0 10 #include "nsViewManager.h"
michael@0 11 #include "nsGfxCIID.h"
michael@0 12 #include "nsView.h"
michael@0 13 #include "nsCOMPtr.h"
michael@0 14 #include "mozilla/MouseEvents.h"
michael@0 15 #include "nsRegion.h"
michael@0 16 #include "nsCOMArray.h"
michael@0 17 #include "nsIPluginWidget.h"
michael@0 18 #include "nsXULPopupManager.h"
michael@0 19 #include "nsIPresShell.h"
michael@0 20 #include "nsPresContext.h"
michael@0 21 #include "mozilla/StartupTimeline.h"
michael@0 22 #include "GeckoProfiler.h"
michael@0 23 #include "nsRefreshDriver.h"
michael@0 24 #include "mozilla/Preferences.h"
michael@0 25 #include "nsContentUtils.h" // for nsAutoScriptBlocker
michael@0 26 #include "nsLayoutUtils.h"
michael@0 27 #include "Layers.h"
michael@0 28 #include "gfxPlatform.h"
michael@0 29 #include "gfxPrefs.h"
michael@0 30 #include "nsIDocument.h"
michael@0 31
michael@0 32 /**
michael@0 33 XXX TODO XXX
michael@0 34
michael@0 35 DeCOMify newly private methods
michael@0 36 Optimize view storage
michael@0 37 */
michael@0 38
michael@0 39 /**
michael@0 40 A note about platform assumptions:
michael@0 41
michael@0 42 We assume that a widget is z-ordered on top of its parent.
michael@0 43
michael@0 44 We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
michael@0 45 we ask for a specific z-order, we don't assume that widget z-ordering actually works.
michael@0 46 */
michael@0 47
michael@0 48 using namespace mozilla;
michael@0 49 using namespace mozilla::layers;
michael@0 50
michael@0 51 #define NSCOORD_NONE INT32_MIN
michael@0 52
michael@0 53 #undef DEBUG_MOUSE_LOCATION
michael@0 54
michael@0 55 int32_t nsViewManager::mVMCount = 0;
michael@0 56
michael@0 57 // Weakly held references to all of the view managers
michael@0 58 nsVoidArray* nsViewManager::gViewManagers = nullptr;
michael@0 59 uint32_t nsViewManager::gLastUserEventTime = 0;
michael@0 60
michael@0 61 nsViewManager::nsViewManager()
michael@0 62 : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
michael@0 63 {
michael@0 64 mRootViewManager = this;
michael@0 65 if (gViewManagers == nullptr) {
michael@0 66 NS_ASSERTION(mVMCount == 0, "View Manager count is incorrect");
michael@0 67 // Create an array to hold a list of view managers
michael@0 68 gViewManagers = new nsVoidArray;
michael@0 69 }
michael@0 70
michael@0 71 gViewManagers->AppendElement(this);
michael@0 72
michael@0 73 ++mVMCount;
michael@0 74
michael@0 75 // NOTE: we use a zeroing operator new, so all data members are
michael@0 76 // assumed to be cleared here.
michael@0 77 mHasPendingWidgetGeometryChanges = false;
michael@0 78 mRecursiveRefreshPending = false;
michael@0 79 }
michael@0 80
michael@0 81 nsViewManager::~nsViewManager()
michael@0 82 {
michael@0 83 if (mRootView) {
michael@0 84 // Destroy any remaining views
michael@0 85 mRootView->Destroy();
michael@0 86 mRootView = nullptr;
michael@0 87 }
michael@0 88
michael@0 89 if (!IsRootVM()) {
michael@0 90 // We have a strong ref to mRootViewManager
michael@0 91 NS_RELEASE(mRootViewManager);
michael@0 92 }
michael@0 93
michael@0 94 NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
michael@0 95 --mVMCount;
michael@0 96
michael@0 97 #ifdef DEBUG
michael@0 98 bool removed =
michael@0 99 #endif
michael@0 100 gViewManagers->RemoveElement(this);
michael@0 101 NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers");
michael@0 102
michael@0 103 if (0 == mVMCount) {
michael@0 104 // There aren't any more view managers so
michael@0 105 // release the global array of view managers
michael@0 106
michael@0 107 NS_ASSERTION(gViewManagers != nullptr, "About to delete null gViewManagers");
michael@0 108 delete gViewManagers;
michael@0 109 gViewManagers = nullptr;
michael@0 110 }
michael@0 111
michael@0 112 mPresShell = nullptr;
michael@0 113 }
michael@0 114
michael@0 115 // We don't hold a reference to the presentation context because it
michael@0 116 // holds a reference to us.
michael@0 117 nsresult
michael@0 118 nsViewManager::Init(nsDeviceContext* aContext)
michael@0 119 {
michael@0 120 NS_PRECONDITION(nullptr != aContext, "null ptr");
michael@0 121
michael@0 122 if (nullptr == aContext) {
michael@0 123 return NS_ERROR_NULL_POINTER;
michael@0 124 }
michael@0 125 if (nullptr != mContext) {
michael@0 126 return NS_ERROR_ALREADY_INITIALIZED;
michael@0 127 }
michael@0 128 mContext = aContext;
michael@0 129
michael@0 130 return NS_OK;
michael@0 131 }
michael@0 132
michael@0 133 nsView*
michael@0 134 nsViewManager::CreateView(const nsRect& aBounds,
michael@0 135 nsView* aParent,
michael@0 136 nsViewVisibility aVisibilityFlag)
michael@0 137 {
michael@0 138 nsView *v = new nsView(this, aVisibilityFlag);
michael@0 139 v->SetParent(aParent);
michael@0 140 v->SetPosition(aBounds.x, aBounds.y);
michael@0 141 nsRect dim(0, 0, aBounds.width, aBounds.height);
michael@0 142 v->SetDimensions(dim, false);
michael@0 143 return v;
michael@0 144 }
michael@0 145
michael@0 146 void
michael@0 147 nsViewManager::SetRootView(nsView *aView)
michael@0 148 {
michael@0 149 NS_PRECONDITION(!aView || aView->GetViewManager() == this,
michael@0 150 "Unexpected viewmanager on root view");
michael@0 151
michael@0 152 // Do NOT destroy the current root view. It's the caller's responsibility
michael@0 153 // to destroy it
michael@0 154 mRootView = aView;
michael@0 155
michael@0 156 if (mRootView) {
michael@0 157 nsView* parent = mRootView->GetParent();
michael@0 158 if (parent) {
michael@0 159 // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so
michael@0 160 // no need to set mRootViewManager ourselves here.
michael@0 161 parent->InsertChild(mRootView, nullptr);
michael@0 162 } else {
michael@0 163 InvalidateHierarchy();
michael@0 164 }
michael@0 165
michael@0 166 mRootView->SetZIndex(false, 0);
michael@0 167 }
michael@0 168 // Else don't touch mRootViewManager
michael@0 169 }
michael@0 170
michael@0 171 void
michael@0 172 nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
michael@0 173 {
michael@0 174 if (nullptr != mRootView) {
michael@0 175 if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
michael@0 176 nsRect dim = mRootView->GetDimensions();
michael@0 177 *aWidth = dim.width;
michael@0 178 *aHeight = dim.height;
michael@0 179 } else {
michael@0 180 *aWidth = mDelayedResize.width;
michael@0 181 *aHeight = mDelayedResize.height;
michael@0 182 }
michael@0 183 }
michael@0 184 else
michael@0 185 {
michael@0 186 *aWidth = 0;
michael@0 187 *aHeight = 0;
michael@0 188 }
michael@0 189 }
michael@0 190
michael@0 191 void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
michael@0 192 {
michael@0 193 nsRect oldDim = mRootView->GetDimensions();
michael@0 194 nsRect newDim(0, 0, aWidth, aHeight);
michael@0 195 // We care about resizes even when one dimension is already zero.
michael@0 196 if (!oldDim.IsEqualEdges(newDim)) {
michael@0 197 // Don't resize the widget. It is already being set elsewhere.
michael@0 198 mRootView->SetDimensions(newDim, true, false);
michael@0 199 if (mPresShell)
michael@0 200 mPresShell->ResizeReflow(aWidth, aHeight);
michael@0 201 }
michael@0 202 }
michael@0 203
michael@0 204 void
michael@0 205 nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
michael@0 206 {
michael@0 207 if (mRootView) {
michael@0 208 if (mRootView->IsEffectivelyVisible() && mPresShell && mPresShell->IsVisible()) {
michael@0 209 if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
michael@0 210 mDelayedResize != nsSize(aWidth, aHeight)) {
michael@0 211 // We have a delayed resize; that now obsolete size may already have
michael@0 212 // been flushed to the PresContext so we need to update the PresContext
michael@0 213 // with the new size because if the new size is exactly the same as the
michael@0 214 // root view's current size then DoSetWindowDimensions will not
michael@0 215 // request a resize reflow (which would correct it). See bug 617076.
michael@0 216 mDelayedResize = nsSize(aWidth, aHeight);
michael@0 217 FlushDelayedResize(false);
michael@0 218 }
michael@0 219 mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
michael@0 220 DoSetWindowDimensions(aWidth, aHeight);
michael@0 221 } else {
michael@0 222 mDelayedResize.SizeTo(aWidth, aHeight);
michael@0 223 if (mPresShell && mPresShell->GetDocument()) {
michael@0 224 mPresShell->GetDocument()->SetNeedStyleFlush();
michael@0 225 }
michael@0 226 }
michael@0 227 }
michael@0 228 }
michael@0 229
michael@0 230 void
michael@0 231 nsViewManager::FlushDelayedResize(bool aDoReflow)
michael@0 232 {
michael@0 233 if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
michael@0 234 if (aDoReflow) {
michael@0 235 DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height);
michael@0 236 mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
michael@0 237 } else if (mPresShell) {
michael@0 238 nsPresContext* presContext = mPresShell->GetPresContext();
michael@0 239 if (presContext) {
michael@0 240 presContext->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize));
michael@0 241 }
michael@0 242 }
michael@0 243 }
michael@0 244 }
michael@0 245
michael@0 246 // Convert aIn from being relative to and in appunits of aFromView, to being
michael@0 247 // relative to and in appunits of aToView.
michael@0 248 static nsRegion ConvertRegionBetweenViews(const nsRegion& aIn,
michael@0 249 nsView* aFromView,
michael@0 250 nsView* aToView)
michael@0 251 {
michael@0 252 nsRegion out = aIn;
michael@0 253 out.MoveBy(aFromView->GetOffsetTo(aToView));
michael@0 254 out = out.ConvertAppUnitsRoundOut(
michael@0 255 aFromView->GetViewManager()->AppUnitsPerDevPixel(),
michael@0 256 aToView->GetViewManager()->AppUnitsPerDevPixel());
michael@0 257 return out;
michael@0 258 }
michael@0 259
michael@0 260 nsView* nsViewManager::GetDisplayRootFor(nsView* aView)
michael@0 261 {
michael@0 262 nsView *displayRoot = aView;
michael@0 263 for (;;) {
michael@0 264 nsView *displayParent = displayRoot->GetParent();
michael@0 265 if (!displayParent)
michael@0 266 return displayRoot;
michael@0 267
michael@0 268 if (displayRoot->GetFloating() && !displayParent->GetFloating())
michael@0 269 return displayRoot;
michael@0 270
michael@0 271 // If we have a combobox dropdown popup within a panel popup, both the view
michael@0 272 // for the dropdown popup and its parent will be floating, so we need to
michael@0 273 // distinguish this situation. We do this by looking for a widget. Any view
michael@0 274 // with a widget is a display root, except for plugins.
michael@0 275 nsIWidget* widget = displayRoot->GetWidget();
michael@0 276 if (widget && widget->WindowType() == eWindowType_popup) {
michael@0 277 NS_ASSERTION(displayRoot->GetFloating() && displayParent->GetFloating(),
michael@0 278 "this should only happen with floating views that have floating parents");
michael@0 279 return displayRoot;
michael@0 280 }
michael@0 281
michael@0 282 displayRoot = displayParent;
michael@0 283 }
michael@0 284 }
michael@0 285
michael@0 286 /**
michael@0 287 aRegion is given in device coordinates!!
michael@0 288 aContext may be null, in which case layers should be used for
michael@0 289 rendering.
michael@0 290 */
michael@0 291 void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion)
michael@0 292 {
michael@0 293 NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
michael@0 294
michael@0 295 if (mPresShell && mPresShell->IsNeverPainting()) {
michael@0 296 return;
michael@0 297 }
michael@0 298
michael@0 299 // damageRegion is the damaged area, in twips, relative to the view origin
michael@0 300 nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
michael@0 301 // move region from widget coordinates into view coordinates
michael@0 302 damageRegion.MoveBy(-aView->ViewToWidgetOffset());
michael@0 303
michael@0 304 if (damageRegion.IsEmpty()) {
michael@0 305 #ifdef DEBUG_roc
michael@0 306 nsRect viewRect = aView->GetDimensions();
michael@0 307 nsRect damageRect = damageRegion.GetBounds();
michael@0 308 printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
michael@0 309 damageRect.x, damageRect.y, damageRect.width, damageRect.height,
michael@0 310 viewRect.x, viewRect.y, viewRect.width, viewRect.height);
michael@0 311 #endif
michael@0 312 return;
michael@0 313 }
michael@0 314
michael@0 315 nsIWidget *widget = aView->GetWidget();
michael@0 316 if (!widget) {
michael@0 317 return;
michael@0 318 }
michael@0 319
michael@0 320 NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
michael@0 321 if (IsPainting()) {
michael@0 322 RootViewManager()->mRecursiveRefreshPending = true;
michael@0 323 return;
michael@0 324 }
michael@0 325
michael@0 326 {
michael@0 327 nsAutoScriptBlocker scriptBlocker;
michael@0 328 SetPainting(true);
michael@0 329
michael@0 330 NS_ASSERTION(GetDisplayRootFor(aView) == aView,
michael@0 331 "Widgets that we paint must all be display roots");
michael@0 332
michael@0 333 if (mPresShell) {
michael@0 334 #ifdef MOZ_DUMP_PAINTING
michael@0 335 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
michael@0 336 printf_stderr("--COMPOSITE-- %p\n", mPresShell);
michael@0 337 }
michael@0 338 #endif
michael@0 339 uint32_t paintFlags = nsIPresShell::PAINT_COMPOSITE;
michael@0 340 LayerManager *manager = widget->GetLayerManager();
michael@0 341 if (!manager->NeedsWidgetInvalidation()) {
michael@0 342 manager->FlushRendering();
michael@0 343 } else {
michael@0 344 mPresShell->Paint(aView, damageRegion,
michael@0 345 paintFlags);
michael@0 346 }
michael@0 347 #ifdef MOZ_DUMP_PAINTING
michael@0 348 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
michael@0 349 printf_stderr("--ENDCOMPOSITE--\n");
michael@0 350 }
michael@0 351 #endif
michael@0 352 mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
michael@0 353 }
michael@0 354
michael@0 355 SetPainting(false);
michael@0 356 }
michael@0 357
michael@0 358 if (RootViewManager()->mRecursiveRefreshPending) {
michael@0 359 RootViewManager()->mRecursiveRefreshPending = false;
michael@0 360 InvalidateAllViews();
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 void
michael@0 365 nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
michael@0 366 bool aFlushDirtyRegion)
michael@0 367 {
michael@0 368 NS_ASSERTION(IsRootVM(), "Updates will be missed");
michael@0 369 if (!aView) {
michael@0 370 return;
michael@0 371 }
michael@0 372
michael@0 373 nsCOMPtr<nsIPresShell> rootShell(mPresShell);
michael@0 374 nsTArray<nsCOMPtr<nsIWidget> > widgets;
michael@0 375 aView->GetViewManager()->ProcessPendingUpdatesRecurse(aView, widgets);
michael@0 376 for (uint32_t i = 0; i < widgets.Length(); ++i) {
michael@0 377 nsView* view = nsView::GetViewFor(widgets[i]);
michael@0 378 if (view) {
michael@0 379 view->ResetWidgetBounds(false, true);
michael@0 380 }
michael@0 381 }
michael@0 382 if (rootShell->GetViewManager() != this) {
michael@0 383 return; // 'this' might have been destroyed
michael@0 384 }
michael@0 385 if (aFlushDirtyRegion) {
michael@0 386 nsAutoScriptBlocker scriptBlocker;
michael@0 387 SetPainting(true);
michael@0 388 for (uint32_t i = 0; i < widgets.Length(); ++i) {
michael@0 389 nsIWidget* widget = widgets[i];
michael@0 390 nsView* view = nsView::GetViewFor(widget);
michael@0 391 if (view) {
michael@0 392 view->GetViewManager()->ProcessPendingUpdatesPaint(widget);
michael@0 393 }
michael@0 394 }
michael@0 395 SetPainting(false);
michael@0 396 }
michael@0 397 }
michael@0 398
michael@0 399 void
michael@0 400 nsViewManager::ProcessPendingUpdatesRecurse(nsView* aView,
michael@0 401 nsTArray<nsCOMPtr<nsIWidget> >& aWidgets)
michael@0 402 {
michael@0 403 if (mPresShell && mPresShell->IsNeverPainting()) {
michael@0 404 return;
michael@0 405 }
michael@0 406
michael@0 407 for (nsView* childView = aView->GetFirstChild(); childView;
michael@0 408 childView = childView->GetNextSibling()) {
michael@0 409 childView->GetViewManager()->
michael@0 410 ProcessPendingUpdatesRecurse(childView, aWidgets);
michael@0 411 }
michael@0 412
michael@0 413 nsIWidget* widget = aView->GetWidget();
michael@0 414 if (widget) {
michael@0 415 aWidgets.AppendElement(widget);
michael@0 416 } else {
michael@0 417 FlushDirtyRegionToWidget(aView);
michael@0 418 }
michael@0 419 }
michael@0 420
michael@0 421 void
michael@0 422 nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget)
michael@0 423 {
michael@0 424 if (aWidget->NeedsPaint()) {
michael@0 425 // If an ancestor widget was hidden and then shown, we could
michael@0 426 // have a delayed resize to handle.
michael@0 427 for (nsViewManager *vm = this; vm;
michael@0 428 vm = vm->mRootView->GetParent()
michael@0 429 ? vm->mRootView->GetParent()->GetViewManager()
michael@0 430 : nullptr) {
michael@0 431 if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
michael@0 432 vm->mRootView->IsEffectivelyVisible() &&
michael@0 433 vm->mPresShell && vm->mPresShell->IsVisible()) {
michael@0 434 vm->FlushDelayedResize(true);
michael@0 435 }
michael@0 436 }
michael@0 437 nsView* view = nsView::GetViewFor(aWidget);
michael@0 438 if (!view) {
michael@0 439 NS_ERROR("FlushDelayedResize destroyed the nsView?");
michael@0 440 return;
michael@0 441 }
michael@0 442
michael@0 443 if (mPresShell) {
michael@0 444 #ifdef MOZ_DUMP_PAINTING
michael@0 445 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
michael@0 446 printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n",
michael@0 447 mPresShell, view, aWidget);
michael@0 448 }
michael@0 449 #endif
michael@0 450
michael@0 451 mPresShell->Paint(view, nsRegion(), nsIPresShell::PAINT_LAYERS);
michael@0 452 view->SetForcedRepaint(false);
michael@0 453
michael@0 454 #ifdef MOZ_DUMP_PAINTING
michael@0 455 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
michael@0 456 printf_stderr("---- PAINT END ----\n");
michael@0 457 }
michael@0 458 #endif
michael@0 459 }
michael@0 460 }
michael@0 461 FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget));
michael@0 462 }
michael@0 463
michael@0 464 void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
michael@0 465 {
michael@0 466 NS_ASSERTION(aView->GetViewManager() == this,
michael@0 467 "FlushDirtyRegionToWidget called on view we don't own");
michael@0 468
michael@0 469 if (!aView->HasNonEmptyDirtyRegion())
michael@0 470 return;
michael@0 471
michael@0 472 nsRegion* dirtyRegion = aView->GetDirtyRegion();
michael@0 473 nsView* nearestViewWithWidget = aView;
michael@0 474 while (!nearestViewWithWidget->HasWidget() &&
michael@0 475 nearestViewWithWidget->GetParent()) {
michael@0 476 nearestViewWithWidget = nearestViewWithWidget->GetParent();
michael@0 477 }
michael@0 478 nsRegion r =
michael@0 479 ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
michael@0 480
michael@0 481 // If we draw the frame counter we need to make sure we invalidate the area
michael@0 482 // for it to make it on screen
michael@0 483 if (gfxPrefs::DrawFrameCounter()) {
michael@0 484 nsRect counterBounds = gfxPlatform::FrameCounterBounds().ToAppUnits(AppUnitsPerDevPixel());
michael@0 485 r = r.Or(r, counterBounds);
michael@0 486 }
michael@0 487
michael@0 488 nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
michael@0 489 widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
michael@0 490 dirtyRegion->SetEmpty();
michael@0 491 }
michael@0 492
michael@0 493 void
michael@0 494 nsViewManager::InvalidateView(nsView *aView)
michael@0 495 {
michael@0 496 // Mark the entire view as damaged
michael@0 497 InvalidateView(aView, aView->GetDimensions());
michael@0 498 }
michael@0 499
michael@0 500 static void
michael@0 501 AddDirtyRegion(nsView *aView, const nsRegion &aDamagedRegion)
michael@0 502 {
michael@0 503 nsRegion* dirtyRegion = aView->GetDirtyRegion();
michael@0 504 if (!dirtyRegion)
michael@0 505 return;
michael@0 506
michael@0 507 dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
michael@0 508 dirtyRegion->SimplifyOutward(8);
michael@0 509 }
michael@0 510
michael@0 511 void
michael@0 512 nsViewManager::PostPendingUpdate()
michael@0 513 {
michael@0 514 nsViewManager* rootVM = RootViewManager();
michael@0 515 rootVM->mHasPendingWidgetGeometryChanges = true;
michael@0 516 if (rootVM->mPresShell) {
michael@0 517 rootVM->mPresShell->ScheduleViewManagerFlush();
michael@0 518 }
michael@0 519 }
michael@0 520
michael@0 521 /**
michael@0 522 * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
michael@0 523 * every widget child of aWidgetView, plus aWidgetView's own widget
michael@0 524 */
michael@0 525 void
michael@0 526 nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
michael@0 527 const nsRegion &aDamagedRegion)
michael@0 528 {
michael@0 529 NS_ASSERTION(aWidgetView->GetViewManager() == this,
michael@0 530 "InvalidateWidgetArea called on view we don't own");
michael@0 531 nsIWidget* widget = aWidgetView->GetWidget();
michael@0 532
michael@0 533 #if 0
michael@0 534 nsRect dbgBounds = aDamagedRegion.GetBounds();
michael@0 535 printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
michael@0 536 aWidgetView, aWidgetView->IsAttachedToTopLevel(),
michael@0 537 widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
michael@0 538 #endif
michael@0 539
michael@0 540 // If the widget is hidden, it don't cover nothing
michael@0 541 if (widget && !widget->IsVisible()) {
michael@0 542 return;
michael@0 543 }
michael@0 544
michael@0 545 if (!widget) {
michael@0 546 // The root view or a scrolling view might not have a widget
michael@0 547 // (for example, during printing). We get here when we scroll
michael@0 548 // during printing to show selected options in a listbox, for example.
michael@0 549 return;
michael@0 550 }
michael@0 551
michael@0 552 // Update all child widgets with the damage. In the process,
michael@0 553 // accumulate the union of all the child widget areas, or at least
michael@0 554 // some subset of that.
michael@0 555 nsRegion children;
michael@0 556 if (widget->GetTransparencyMode() != eTransparencyTransparent) {
michael@0 557 for (nsIWidget* childWidget = widget->GetFirstChild();
michael@0 558 childWidget;
michael@0 559 childWidget = childWidget->GetNextSibling()) {
michael@0 560 nsView* view = nsView::GetViewFor(childWidget);
michael@0 561 NS_ASSERTION(view != aWidgetView, "will recur infinitely");
michael@0 562 nsWindowType type = childWidget->WindowType();
michael@0 563 if (view && childWidget->IsVisible() && type != eWindowType_popup) {
michael@0 564 NS_ASSERTION(type == eWindowType_plugin,
michael@0 565 "Only plugin or popup widgets can be children!");
michael@0 566
michael@0 567 // We do not need to invalidate in plugin widgets, but we should
michael@0 568 // exclude them from the invalidation region IF we're not on
michael@0 569 // Mac. On Mac we need to draw under plugin widgets, because
michael@0 570 // plugin widgets are basically invisible
michael@0 571 #ifndef XP_MACOSX
michael@0 572 // GetBounds should compensate for chrome on a toplevel widget
michael@0 573 nsIntRect bounds;
michael@0 574 childWidget->GetBounds(bounds);
michael@0 575
michael@0 576 nsTArray<nsIntRect> clipRects;
michael@0 577 childWidget->GetWindowClipRegion(&clipRects);
michael@0 578 for (uint32_t i = 0; i < clipRects.Length(); ++i) {
michael@0 579 nsRect rr = (clipRects[i] + bounds.TopLeft()).
michael@0 580 ToAppUnits(AppUnitsPerDevPixel());
michael@0 581 children.Or(children, rr - aWidgetView->ViewToWidgetOffset());
michael@0 582 children.SimplifyInward(20);
michael@0 583 }
michael@0 584 #endif
michael@0 585 }
michael@0 586 }
michael@0 587 }
michael@0 588
michael@0 589 nsRegion leftOver;
michael@0 590 leftOver.Sub(aDamagedRegion, children);
michael@0 591
michael@0 592 if (!leftOver.IsEmpty()) {
michael@0 593 const nsRect* r;
michael@0 594 for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
michael@0 595 nsIntRect bounds = ViewToWidget(aWidgetView, *r);
michael@0 596 widget->Invalidate(bounds);
michael@0 597 }
michael@0 598 }
michael@0 599 }
michael@0 600
michael@0 601 static bool
michael@0 602 ShouldIgnoreInvalidation(nsViewManager* aVM)
michael@0 603 {
michael@0 604 while (aVM) {
michael@0 605 nsIPresShell* shell = aVM->GetPresShell();
michael@0 606 if (!shell || shell->ShouldIgnoreInvalidation()) {
michael@0 607 return true;
michael@0 608 }
michael@0 609 nsView* view = aVM->GetRootView()->GetParent();
michael@0 610 aVM = view ? view->GetViewManager() : nullptr;
michael@0 611 }
michael@0 612 return false;
michael@0 613 }
michael@0 614
michael@0 615 void
michael@0 616 nsViewManager::InvalidateView(nsView *aView, const nsRect &aRect)
michael@0 617 {
michael@0 618 // If painting is suppressed in the presshell or an ancestor drop all
michael@0 619 // invalidates, it will invalidate everything when it unsuppresses.
michael@0 620 if (ShouldIgnoreInvalidation(this)) {
michael@0 621 return;
michael@0 622 }
michael@0 623
michael@0 624 InvalidateViewNoSuppression(aView, aRect);
michael@0 625 }
michael@0 626
michael@0 627 void
michael@0 628 nsViewManager::InvalidateViewNoSuppression(nsView *aView,
michael@0 629 const nsRect &aRect)
michael@0 630 {
michael@0 631 NS_PRECONDITION(nullptr != aView, "null view");
michael@0 632
michael@0 633 NS_ASSERTION(aView->GetViewManager() == this,
michael@0 634 "InvalidateViewNoSuppression called on view we don't own");
michael@0 635
michael@0 636 nsRect damagedRect(aRect);
michael@0 637 if (damagedRect.IsEmpty()) {
michael@0 638 return;
michael@0 639 }
michael@0 640
michael@0 641 nsView* displayRoot = GetDisplayRootFor(aView);
michael@0 642 nsViewManager* displayRootVM = displayRoot->GetViewManager();
michael@0 643 // Propagate the update to the displayRoot, since iframes, for example,
michael@0 644 // can overlap each other and be translucent. So we have to possibly
michael@0 645 // invalidate our rect in each of the widgets we have lying about.
michael@0 646 damagedRect.MoveBy(aView->GetOffsetTo(displayRoot));
michael@0 647 int32_t rootAPD = displayRootVM->AppUnitsPerDevPixel();
michael@0 648 int32_t APD = AppUnitsPerDevPixel();
michael@0 649 damagedRect = damagedRect.ConvertAppUnitsRoundOut(APD, rootAPD);
michael@0 650
michael@0 651 // accumulate this rectangle in the view's dirty region, so we can
michael@0 652 // process it later.
michael@0 653 AddDirtyRegion(displayRoot, nsRegion(damagedRect));
michael@0 654 }
michael@0 655
michael@0 656 void
michael@0 657 nsViewManager::InvalidateAllViews()
michael@0 658 {
michael@0 659 if (RootViewManager() != this) {
michael@0 660 return RootViewManager()->InvalidateAllViews();
michael@0 661 }
michael@0 662
michael@0 663 InvalidateViews(mRootView);
michael@0 664 }
michael@0 665
michael@0 666 void nsViewManager::InvalidateViews(nsView *aView)
michael@0 667 {
michael@0 668 // Invalidate this view.
michael@0 669 InvalidateView(aView);
michael@0 670
michael@0 671 // Invalidate all children as well.
michael@0 672 nsView* childView = aView->GetFirstChild();
michael@0 673 while (nullptr != childView) {
michael@0 674 childView->GetViewManager()->InvalidateViews(childView);
michael@0 675 childView = childView->GetNextSibling();
michael@0 676 }
michael@0 677 }
michael@0 678
michael@0 679 void nsViewManager::WillPaintWindow(nsIWidget* aWidget)
michael@0 680 {
michael@0 681 if (aWidget) {
michael@0 682 nsView* view = nsView::GetViewFor(aWidget);
michael@0 683 LayerManager *manager = aWidget->GetLayerManager();
michael@0 684 if (view &&
michael@0 685 (view->ForcedRepaint() || !manager->NeedsWidgetInvalidation())) {
michael@0 686 ProcessPendingUpdates();
michael@0 687 // Re-get the view pointer here since the ProcessPendingUpdates might have
michael@0 688 // destroyed it during CallWillPaintOnObservers.
michael@0 689 view = nsView::GetViewFor(aWidget);
michael@0 690 if (view) {
michael@0 691 view->SetForcedRepaint(false);
michael@0 692 }
michael@0 693 }
michael@0 694 }
michael@0 695
michael@0 696 nsCOMPtr<nsIPresShell> shell = mPresShell;
michael@0 697 if (shell) {
michael@0 698 shell->WillPaintWindow();
michael@0 699 }
michael@0 700 }
michael@0 701
michael@0 702 bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion)
michael@0 703 {
michael@0 704 if (!aWidget || !mContext)
michael@0 705 return false;
michael@0 706
michael@0 707 NS_ASSERTION(IsPaintingAllowed(),
michael@0 708 "shouldn't be receiving paint events while painting is disallowed!");
michael@0 709
michael@0 710 // Get the view pointer here since NS_WILL_PAINT might have
michael@0 711 // destroyed it during CallWillPaintOnObservers (bug 378273).
michael@0 712 nsView* view = nsView::GetViewFor(aWidget);
michael@0 713 if (view && !aRegion.IsEmpty()) {
michael@0 714 Refresh(view, aRegion);
michael@0 715 }
michael@0 716
michael@0 717 return true;
michael@0 718 }
michael@0 719
michael@0 720 void nsViewManager::DidPaintWindow()
michael@0 721 {
michael@0 722 nsCOMPtr<nsIPresShell> shell = mPresShell;
michael@0 723 if (shell) {
michael@0 724 shell->DidPaintWindow();
michael@0 725 }
michael@0 726 }
michael@0 727
michael@0 728 void
michael@0 729 nsViewManager::DispatchEvent(WidgetGUIEvent *aEvent,
michael@0 730 nsView* aView,
michael@0 731 nsEventStatus* aStatus)
michael@0 732 {
michael@0 733 PROFILER_LABEL("event", "nsViewManager::DispatchEvent");
michael@0 734
michael@0 735 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
michael@0 736 if ((mouseEvent &&
michael@0 737 // Ignore mouse events that we synthesize.
michael@0 738 mouseEvent->reason == WidgetMouseEvent::eReal &&
michael@0 739 // Ignore mouse exit and enter (we'll get moves if the user
michael@0 740 // is really moving the mouse) since we get them when we
michael@0 741 // create and destroy widgets.
michael@0 742 mouseEvent->message != NS_MOUSE_EXIT &&
michael@0 743 mouseEvent->message != NS_MOUSE_ENTER) ||
michael@0 744 aEvent->HasKeyEventMessage() ||
michael@0 745 aEvent->HasIMEEventMessage() ||
michael@0 746 aEvent->message == NS_PLUGIN_INPUT_EVENT) {
michael@0 747 gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
michael@0 748 }
michael@0 749
michael@0 750 // Find the view whose coordinates system we're in.
michael@0 751 nsView* view = aView;
michael@0 752 bool dispatchUsingCoordinates = aEvent->IsUsingCoordinates();
michael@0 753 if (dispatchUsingCoordinates) {
michael@0 754 // Will dispatch using coordinates. Pretty bogus but it's consistent
michael@0 755 // with what presshell does.
michael@0 756 view = GetDisplayRootFor(view);
michael@0 757 }
michael@0 758
michael@0 759 // If the view has no frame, look for a view that does.
michael@0 760 nsIFrame* frame = view->GetFrame();
michael@0 761 if (!frame &&
michael@0 762 (dispatchUsingCoordinates || aEvent->HasKeyEventMessage() ||
michael@0 763 aEvent->IsIMERelatedEvent() ||
michael@0 764 aEvent->IsNonRetargetedNativeEventDelivererForPlugin() ||
michael@0 765 aEvent->HasPluginActivationEventMessage() ||
michael@0 766 aEvent->message == NS_PLUGIN_RESOLUTION_CHANGED)) {
michael@0 767 while (view && !view->GetFrame()) {
michael@0 768 view = view->GetParent();
michael@0 769 }
michael@0 770
michael@0 771 if (view) {
michael@0 772 frame = view->GetFrame();
michael@0 773 }
michael@0 774 }
michael@0 775
michael@0 776 if (nullptr != frame) {
michael@0 777 // Hold a refcount to the presshell. The continued existence of the
michael@0 778 // presshell will delay deletion of this view hierarchy should the event
michael@0 779 // want to cause its destruction in, say, some JavaScript event handler.
michael@0 780 nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
michael@0 781 if (shell) {
michael@0 782 shell->HandleEvent(frame, aEvent, false, aStatus);
michael@0 783 return;
michael@0 784 }
michael@0 785 }
michael@0 786
michael@0 787 *aStatus = nsEventStatus_eIgnore;
michael@0 788 }
michael@0 789
michael@0 790 // Recursively reparent widgets if necessary
michael@0 791
michael@0 792 void nsViewManager::ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget)
michael@0 793 {
michael@0 794 NS_PRECONDITION(aNewWidget, "");
michael@0 795
michael@0 796 if (aView->HasWidget()) {
michael@0 797 // Check to see if the parent widget is the
michael@0 798 // same as the new parent. If not then reparent
michael@0 799 // the widget, otherwise there is nothing more
michael@0 800 // to do for the view and its descendants
michael@0 801 nsIWidget* widget = aView->GetWidget();
michael@0 802 nsIWidget* parentWidget = widget->GetParent();
michael@0 803 if (parentWidget) {
michael@0 804 // Child widget
michael@0 805 if (parentWidget != aNewWidget) {
michael@0 806 #ifdef DEBUG
michael@0 807 nsresult rv =
michael@0 808 #endif
michael@0 809 widget->SetParent(aNewWidget);
michael@0 810 NS_ASSERTION(NS_SUCCEEDED(rv), "SetParent failed!");
michael@0 811 }
michael@0 812 } else {
michael@0 813 // Toplevel widget (popup, dialog, etc)
michael@0 814 widget->ReparentNativeWidget(aNewWidget);
michael@0 815 }
michael@0 816 return;
michael@0 817 }
michael@0 818
michael@0 819 // Need to check each of the views children to see
michael@0 820 // if they have a widget and reparent it.
michael@0 821
michael@0 822 for (nsView *kid = aView->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
michael@0 823 ReparentChildWidgets(kid, aNewWidget);
michael@0 824 }
michael@0 825 }
michael@0 826
michael@0 827 // Reparent a view and its descendant views widgets if necessary
michael@0 828
michael@0 829 void nsViewManager::ReparentWidgets(nsView* aView, nsView *aParent)
michael@0 830 {
michael@0 831 NS_PRECONDITION(aParent, "Must have a parent");
michael@0 832 NS_PRECONDITION(aView, "Must have a view");
michael@0 833
michael@0 834 // Quickly determine whether the view has pre-existing children or a
michael@0 835 // widget. In most cases the view will not have any pre-existing
michael@0 836 // children when this is called. Only in the case
michael@0 837 // where a view has been reparented by removing it from
michael@0 838 // a reinserting it into a new location in the view hierarchy do we
michael@0 839 // have to consider reparenting the existing widgets for the view and
michael@0 840 // it's descendants.
michael@0 841 if (aView->HasWidget() || aView->GetFirstChild()) {
michael@0 842 nsIWidget* parentWidget = aParent->GetNearestWidget(nullptr);
michael@0 843 if (parentWidget) {
michael@0 844 ReparentChildWidgets(aView, parentWidget);
michael@0 845 return;
michael@0 846 }
michael@0 847 NS_WARNING("Can not find a widget for the parent view");
michael@0 848 }
michael@0 849 }
michael@0 850
michael@0 851 void
michael@0 852 nsViewManager::InsertChild(nsView *aParent, nsView *aChild, nsView *aSibling,
michael@0 853 bool aAfter)
michael@0 854 {
michael@0 855 NS_PRECONDITION(nullptr != aParent, "null ptr");
michael@0 856 NS_PRECONDITION(nullptr != aChild, "null ptr");
michael@0 857 NS_ASSERTION(aSibling == nullptr || aSibling->GetParent() == aParent,
michael@0 858 "tried to insert view with invalid sibling");
michael@0 859 NS_ASSERTION(!IsViewInserted(aChild), "tried to insert an already-inserted view");
michael@0 860
michael@0 861 if ((nullptr != aParent) && (nullptr != aChild))
michael@0 862 {
michael@0 863 // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
michael@0 864 // order, otherwise after 'kid' (i.e. before 'kid' in document order).
michael@0 865
michael@0 866 if (nullptr == aSibling) {
michael@0 867 if (aAfter) {
michael@0 868 // insert at end of document order, i.e., before first view
michael@0 869 // this is the common case, by far
michael@0 870 aParent->InsertChild(aChild, nullptr);
michael@0 871 ReparentWidgets(aChild, aParent);
michael@0 872 } else {
michael@0 873 // insert at beginning of document order, i.e., after last view
michael@0 874 nsView *kid = aParent->GetFirstChild();
michael@0 875 nsView *prev = nullptr;
michael@0 876 while (kid) {
michael@0 877 prev = kid;
michael@0 878 kid = kid->GetNextSibling();
michael@0 879 }
michael@0 880 // prev is last view or null if there are no children
michael@0 881 aParent->InsertChild(aChild, prev);
michael@0 882 ReparentWidgets(aChild, aParent);
michael@0 883 }
michael@0 884 } else {
michael@0 885 nsView *kid = aParent->GetFirstChild();
michael@0 886 nsView *prev = nullptr;
michael@0 887 while (kid && aSibling != kid) {
michael@0 888 //get the next sibling view
michael@0 889 prev = kid;
michael@0 890 kid = kid->GetNextSibling();
michael@0 891 }
michael@0 892 NS_ASSERTION(kid != nullptr,
michael@0 893 "couldn't find sibling in child list");
michael@0 894 if (aAfter) {
michael@0 895 // insert after 'kid' in document order, i.e. before in view order
michael@0 896 aParent->InsertChild(aChild, prev);
michael@0 897 ReparentWidgets(aChild, aParent);
michael@0 898 } else {
michael@0 899 // insert before 'kid' in document order, i.e. after in view order
michael@0 900 aParent->InsertChild(aChild, kid);
michael@0 901 ReparentWidgets(aChild, aParent);
michael@0 902 }
michael@0 903 }
michael@0 904
michael@0 905 // if the parent view is marked as "floating", make the newly added view float as well.
michael@0 906 if (aParent->GetFloating())
michael@0 907 aChild->SetFloating(true);
michael@0 908 }
michael@0 909 }
michael@0 910
michael@0 911 void
michael@0 912 nsViewManager::InsertChild(nsView *aParent, nsView *aChild, int32_t aZIndex)
michael@0 913 {
michael@0 914 // no-one really calls this with anything other than aZIndex == 0 on a fresh view
michael@0 915 // XXX this method should simply be eliminated and its callers redirected to the real method
michael@0 916 SetViewZIndex(aChild, false, aZIndex);
michael@0 917 InsertChild(aParent, aChild, nullptr, true);
michael@0 918 }
michael@0 919
michael@0 920 void
michael@0 921 nsViewManager::RemoveChild(nsView *aChild)
michael@0 922 {
michael@0 923 NS_ASSERTION(aChild, "aChild must not be null");
michael@0 924
michael@0 925 nsView* parent = aChild->GetParent();
michael@0 926
michael@0 927 if (nullptr != parent) {
michael@0 928 NS_ASSERTION(aChild->GetViewManager() == this ||
michael@0 929 parent->GetViewManager() == this, "wrong view manager");
michael@0 930 parent->RemoveChild(aChild);
michael@0 931 }
michael@0 932 }
michael@0 933
michael@0 934 void
michael@0 935 nsViewManager::MoveViewTo(nsView *aView, nscoord aX, nscoord aY)
michael@0 936 {
michael@0 937 NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
michael@0 938 aView->SetPosition(aX, aY);
michael@0 939 }
michael@0 940
michael@0 941 void
michael@0 942 nsViewManager::ResizeView(nsView *aView, const nsRect &aRect, bool aRepaintExposedAreaOnly)
michael@0 943 {
michael@0 944 NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
michael@0 945
michael@0 946 nsRect oldDimensions = aView->GetDimensions();
michael@0 947 if (!oldDimensions.IsEqualEdges(aRect)) {
michael@0 948 aView->SetDimensions(aRect, true);
michael@0 949 }
michael@0 950
michael@0 951 // Note that if layout resizes the view and the view has a custom clip
michael@0 952 // region set, then we expect layout to update the clip region too. Thus
michael@0 953 // in the case where mClipRect has been optimized away to just be a null
michael@0 954 // pointer, and this resize is implicitly changing the clip rect, it's OK
michael@0 955 // because layout will change it back again if necessary.
michael@0 956 }
michael@0 957
michael@0 958 void
michael@0 959 nsViewManager::SetViewFloating(nsView *aView, bool aFloating)
michael@0 960 {
michael@0 961 NS_ASSERTION(!(nullptr == aView), "no view");
michael@0 962
michael@0 963 aView->SetFloating(aFloating);
michael@0 964 }
michael@0 965
michael@0 966 void
michael@0 967 nsViewManager::SetViewVisibility(nsView *aView, nsViewVisibility aVisible)
michael@0 968 {
michael@0 969 NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
michael@0 970
michael@0 971 if (aVisible != aView->GetVisibility()) {
michael@0 972 aView->SetVisibility(aVisible);
michael@0 973 }
michael@0 974 }
michael@0 975
michael@0 976 bool nsViewManager::IsViewInserted(nsView *aView)
michael@0 977 {
michael@0 978 if (mRootView == aView) {
michael@0 979 return true;
michael@0 980 } else if (aView->GetParent() == nullptr) {
michael@0 981 return false;
michael@0 982 } else {
michael@0 983 nsView* view = aView->GetParent()->GetFirstChild();
michael@0 984 while (view != nullptr) {
michael@0 985 if (view == aView) {
michael@0 986 return true;
michael@0 987 }
michael@0 988 view = view->GetNextSibling();
michael@0 989 }
michael@0 990 return false;
michael@0 991 }
michael@0 992 }
michael@0 993
michael@0 994 void
michael@0 995 nsViewManager::SetViewZIndex(nsView *aView, bool aAutoZIndex, int32_t aZIndex)
michael@0 996 {
michael@0 997 NS_ASSERTION((aView != nullptr), "no view");
michael@0 998
michael@0 999 // don't allow the root view's z-index to be changed. It should always be zero.
michael@0 1000 // This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
michael@0 1001 if (aView == mRootView) {
michael@0 1002 return;
michael@0 1003 }
michael@0 1004
michael@0 1005 if (aAutoZIndex) {
michael@0 1006 aZIndex = 0;
michael@0 1007 }
michael@0 1008
michael@0 1009 aView->SetZIndex(aAutoZIndex, aZIndex);
michael@0 1010 }
michael@0 1011
michael@0 1012 nsViewManager*
michael@0 1013 nsViewManager::IncrementDisableRefreshCount()
michael@0 1014 {
michael@0 1015 if (!IsRootVM()) {
michael@0 1016 return RootViewManager()->IncrementDisableRefreshCount();
michael@0 1017 }
michael@0 1018
michael@0 1019 ++mRefreshDisableCount;
michael@0 1020
michael@0 1021 return this;
michael@0 1022 }
michael@0 1023
michael@0 1024 void
michael@0 1025 nsViewManager::DecrementDisableRefreshCount()
michael@0 1026 {
michael@0 1027 NS_ASSERTION(IsRootVM(), "Should only be called on root");
michael@0 1028 --mRefreshDisableCount;
michael@0 1029 NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
michael@0 1030 }
michael@0 1031
michael@0 1032 void
michael@0 1033 nsViewManager::GetRootWidget(nsIWidget **aWidget)
michael@0 1034 {
michael@0 1035 if (!mRootView) {
michael@0 1036 *aWidget = nullptr;
michael@0 1037 return;
michael@0 1038 }
michael@0 1039 if (mRootView->HasWidget()) {
michael@0 1040 *aWidget = mRootView->GetWidget();
michael@0 1041 NS_ADDREF(*aWidget);
michael@0 1042 return;
michael@0 1043 }
michael@0 1044 if (mRootView->GetParent()) {
michael@0 1045 mRootView->GetParent()->GetViewManager()->GetRootWidget(aWidget);
michael@0 1046 return;
michael@0 1047 }
michael@0 1048 *aWidget = nullptr;
michael@0 1049 }
michael@0 1050
michael@0 1051 nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const
michael@0 1052 {
michael@0 1053 NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
michael@0 1054
michael@0 1055 // account for the view's origin not lining up with the widget's
michael@0 1056 nsRect rect = aRect + aView->ViewToWidgetOffset();
michael@0 1057
michael@0 1058 // finally, convert to device coordinates.
michael@0 1059 return rect.ToOutsidePixels(AppUnitsPerDevPixel());
michael@0 1060 }
michael@0 1061
michael@0 1062 void
michael@0 1063 nsViewManager::IsPainting(bool& aIsPainting)
michael@0 1064 {
michael@0 1065 aIsPainting = IsPainting();
michael@0 1066 }
michael@0 1067
michael@0 1068 void
michael@0 1069 nsViewManager::ProcessPendingUpdates()
michael@0 1070 {
michael@0 1071 if (!IsRootVM()) {
michael@0 1072 RootViewManager()->ProcessPendingUpdates();
michael@0 1073 return;
michael@0 1074 }
michael@0 1075
michael@0 1076 mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
michael@0 1077
michael@0 1078 // Flush things like reflows by calling WillPaint on observer presShells.
michael@0 1079 if (mPresShell) {
michael@0 1080 CallWillPaintOnObservers();
michael@0 1081 }
michael@0 1082 ProcessPendingUpdatesForView(mRootView, true);
michael@0 1083 }
michael@0 1084
michael@0 1085 void
michael@0 1086 nsViewManager::UpdateWidgetGeometry()
michael@0 1087 {
michael@0 1088 if (!IsRootVM()) {
michael@0 1089 RootViewManager()->UpdateWidgetGeometry();
michael@0 1090 return;
michael@0 1091 }
michael@0 1092
michael@0 1093 if (mHasPendingWidgetGeometryChanges) {
michael@0 1094 mHasPendingWidgetGeometryChanges = false;
michael@0 1095 ProcessPendingUpdatesForView(mRootView, false);
michael@0 1096 }
michael@0 1097 }
michael@0 1098
michael@0 1099 void
michael@0 1100 nsViewManager::CallWillPaintOnObservers()
michael@0 1101 {
michael@0 1102 NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
michael@0 1103
michael@0 1104 int32_t index;
michael@0 1105 for (index = 0; index < mVMCount; index++) {
michael@0 1106 nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
michael@0 1107 if (vm->RootViewManager() == this) {
michael@0 1108 // One of our kids.
michael@0 1109 if (vm->mRootView && vm->mRootView->IsEffectivelyVisible()) {
michael@0 1110 nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
michael@0 1111 if (shell) {
michael@0 1112 shell->WillPaint();
michael@0 1113 }
michael@0 1114 }
michael@0 1115 }
michael@0 1116 }
michael@0 1117 }
michael@0 1118
michael@0 1119 void
michael@0 1120 nsViewManager::GetLastUserEventTime(uint32_t& aTime)
michael@0 1121 {
michael@0 1122 aTime = gLastUserEventTime;
michael@0 1123 }
michael@0 1124
michael@0 1125 void
michael@0 1126 nsViewManager::InvalidateHierarchy()
michael@0 1127 {
michael@0 1128 if (mRootView) {
michael@0 1129 if (!IsRootVM()) {
michael@0 1130 NS_RELEASE(mRootViewManager);
michael@0 1131 }
michael@0 1132 nsView *parent = mRootView->GetParent();
michael@0 1133 if (parent) {
michael@0 1134 mRootViewManager = parent->GetViewManager()->RootViewManager();
michael@0 1135 NS_ADDREF(mRootViewManager);
michael@0 1136 NS_ASSERTION(mRootViewManager != this,
michael@0 1137 "Root view had a parent, but it has the same view manager");
michael@0 1138 } else {
michael@0 1139 mRootViewManager = this;
michael@0 1140 }
michael@0 1141 }
michael@0 1142 }

mercurial