view/src/nsViewManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/view/src/nsViewManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1142 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
    1.10 +#include "plarena.h"
    1.11 +
    1.12 +#include "nsAutoPtr.h"
    1.13 +#include "nsViewManager.h"
    1.14 +#include "nsGfxCIID.h"
    1.15 +#include "nsView.h"
    1.16 +#include "nsCOMPtr.h"
    1.17 +#include "mozilla/MouseEvents.h"
    1.18 +#include "nsRegion.h"
    1.19 +#include "nsCOMArray.h"
    1.20 +#include "nsIPluginWidget.h"
    1.21 +#include "nsXULPopupManager.h"
    1.22 +#include "nsIPresShell.h"
    1.23 +#include "nsPresContext.h"
    1.24 +#include "mozilla/StartupTimeline.h"
    1.25 +#include "GeckoProfiler.h"
    1.26 +#include "nsRefreshDriver.h"
    1.27 +#include "mozilla/Preferences.h"
    1.28 +#include "nsContentUtils.h" // for nsAutoScriptBlocker
    1.29 +#include "nsLayoutUtils.h"
    1.30 +#include "Layers.h"
    1.31 +#include "gfxPlatform.h"
    1.32 +#include "gfxPrefs.h"
    1.33 +#include "nsIDocument.h"
    1.34 +
    1.35 +/**
    1.36 +   XXX TODO XXX
    1.37 +
    1.38 +   DeCOMify newly private methods
    1.39 +   Optimize view storage
    1.40 +*/
    1.41 +
    1.42 +/**
    1.43 +   A note about platform assumptions:
    1.44 +
    1.45 +   We assume that a widget is z-ordered on top of its parent.
    1.46 +   
    1.47 +   We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
    1.48 +   we ask for a specific z-order, we don't assume that widget z-ordering actually works.
    1.49 +*/
    1.50 +
    1.51 +using namespace mozilla;
    1.52 +using namespace mozilla::layers;
    1.53 +
    1.54 +#define NSCOORD_NONE      INT32_MIN
    1.55 +
    1.56 +#undef DEBUG_MOUSE_LOCATION
    1.57 +
    1.58 +int32_t nsViewManager::mVMCount = 0;
    1.59 +
    1.60 +// Weakly held references to all of the view managers
    1.61 +nsVoidArray* nsViewManager::gViewManagers = nullptr;
    1.62 +uint32_t nsViewManager::gLastUserEventTime = 0;
    1.63 +
    1.64 +nsViewManager::nsViewManager()
    1.65 +  : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
    1.66 +{
    1.67 +  mRootViewManager = this;
    1.68 +  if (gViewManagers == nullptr) {
    1.69 +    NS_ASSERTION(mVMCount == 0, "View Manager count is incorrect");
    1.70 +    // Create an array to hold a list of view managers
    1.71 +    gViewManagers = new nsVoidArray;
    1.72 +  }
    1.73 + 
    1.74 +  gViewManagers->AppendElement(this);
    1.75 +
    1.76 +  ++mVMCount;
    1.77 +
    1.78 +  // NOTE:  we use a zeroing operator new, so all data members are
    1.79 +  // assumed to be cleared here.
    1.80 +  mHasPendingWidgetGeometryChanges = false;
    1.81 +  mRecursiveRefreshPending = false;
    1.82 +}
    1.83 +
    1.84 +nsViewManager::~nsViewManager()
    1.85 +{
    1.86 +  if (mRootView) {
    1.87 +    // Destroy any remaining views
    1.88 +    mRootView->Destroy();
    1.89 +    mRootView = nullptr;
    1.90 +  }
    1.91 +
    1.92 +  if (!IsRootVM()) {
    1.93 +    // We have a strong ref to mRootViewManager
    1.94 +    NS_RELEASE(mRootViewManager);
    1.95 +  }
    1.96 +
    1.97 +  NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
    1.98 +  --mVMCount;
    1.99 +
   1.100 +#ifdef DEBUG
   1.101 +  bool removed =
   1.102 +#endif
   1.103 +    gViewManagers->RemoveElement(this);
   1.104 +  NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers");
   1.105 +
   1.106 +  if (0 == mVMCount) {
   1.107 +    // There aren't any more view managers so
   1.108 +    // release the global array of view managers
   1.109 +   
   1.110 +    NS_ASSERTION(gViewManagers != nullptr, "About to delete null gViewManagers");
   1.111 +    delete gViewManagers;
   1.112 +    gViewManagers = nullptr;
   1.113 +  }
   1.114 +
   1.115 +  mPresShell = nullptr;
   1.116 +}
   1.117 +
   1.118 +// We don't hold a reference to the presentation context because it
   1.119 +// holds a reference to us.
   1.120 +nsresult
   1.121 +nsViewManager::Init(nsDeviceContext* aContext)
   1.122 +{
   1.123 +  NS_PRECONDITION(nullptr != aContext, "null ptr");
   1.124 +
   1.125 +  if (nullptr == aContext) {
   1.126 +    return NS_ERROR_NULL_POINTER;
   1.127 +  }
   1.128 +  if (nullptr != mContext) {
   1.129 +    return NS_ERROR_ALREADY_INITIALIZED;
   1.130 +  }
   1.131 +  mContext = aContext;
   1.132 +
   1.133 +  return NS_OK;
   1.134 +}
   1.135 +
   1.136 +nsView*
   1.137 +nsViewManager::CreateView(const nsRect& aBounds,
   1.138 +                          nsView* aParent,
   1.139 +                          nsViewVisibility aVisibilityFlag)
   1.140 +{
   1.141 +  nsView *v = new nsView(this, aVisibilityFlag);
   1.142 +  v->SetParent(aParent);
   1.143 +  v->SetPosition(aBounds.x, aBounds.y);
   1.144 +  nsRect dim(0, 0, aBounds.width, aBounds.height);
   1.145 +  v->SetDimensions(dim, false);
   1.146 +  return v;
   1.147 +}
   1.148 +
   1.149 +void
   1.150 +nsViewManager::SetRootView(nsView *aView)
   1.151 +{
   1.152 +  NS_PRECONDITION(!aView || aView->GetViewManager() == this,
   1.153 +                  "Unexpected viewmanager on root view");
   1.154 +  
   1.155 +  // Do NOT destroy the current root view. It's the caller's responsibility
   1.156 +  // to destroy it
   1.157 +  mRootView = aView;
   1.158 +
   1.159 +  if (mRootView) {
   1.160 +    nsView* parent = mRootView->GetParent();
   1.161 +    if (parent) {
   1.162 +      // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so
   1.163 +      // no need to set mRootViewManager ourselves here.
   1.164 +      parent->InsertChild(mRootView, nullptr);
   1.165 +    } else {
   1.166 +      InvalidateHierarchy();
   1.167 +    }
   1.168 +
   1.169 +    mRootView->SetZIndex(false, 0);
   1.170 +  }
   1.171 +  // Else don't touch mRootViewManager
   1.172 +}
   1.173 +
   1.174 +void
   1.175 +nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
   1.176 +{
   1.177 +  if (nullptr != mRootView) {
   1.178 +    if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
   1.179 +      nsRect dim = mRootView->GetDimensions();
   1.180 +      *aWidth = dim.width;
   1.181 +      *aHeight = dim.height;
   1.182 +    } else {
   1.183 +      *aWidth = mDelayedResize.width;
   1.184 +      *aHeight = mDelayedResize.height;
   1.185 +    }
   1.186 +  }
   1.187 +  else
   1.188 +    {
   1.189 +      *aWidth = 0;
   1.190 +      *aHeight = 0;
   1.191 +    }
   1.192 +}
   1.193 +
   1.194 +void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
   1.195 +{
   1.196 +  nsRect oldDim = mRootView->GetDimensions();
   1.197 +  nsRect newDim(0, 0, aWidth, aHeight);
   1.198 +  // We care about resizes even when one dimension is already zero.
   1.199 +  if (!oldDim.IsEqualEdges(newDim)) {
   1.200 +    // Don't resize the widget. It is already being set elsewhere.
   1.201 +    mRootView->SetDimensions(newDim, true, false);
   1.202 +    if (mPresShell)
   1.203 +      mPresShell->ResizeReflow(aWidth, aHeight);
   1.204 +  }
   1.205 +}
   1.206 +
   1.207 +void
   1.208 +nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
   1.209 +{
   1.210 +  if (mRootView) {
   1.211 +    if (mRootView->IsEffectivelyVisible() && mPresShell && mPresShell->IsVisible()) {
   1.212 +      if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
   1.213 +          mDelayedResize != nsSize(aWidth, aHeight)) {
   1.214 +        // We have a delayed resize; that now obsolete size may already have
   1.215 +        // been flushed to the PresContext so we need to update the PresContext
   1.216 +        // with the new size because if the new size is exactly the same as the
   1.217 +        // root view's current size then DoSetWindowDimensions will not
   1.218 +        // request a resize reflow (which would correct it). See bug 617076.
   1.219 +        mDelayedResize = nsSize(aWidth, aHeight);
   1.220 +        FlushDelayedResize(false);
   1.221 +      }
   1.222 +      mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
   1.223 +      DoSetWindowDimensions(aWidth, aHeight);
   1.224 +    } else {
   1.225 +      mDelayedResize.SizeTo(aWidth, aHeight);
   1.226 +      if (mPresShell && mPresShell->GetDocument()) {
   1.227 +        mPresShell->GetDocument()->SetNeedStyleFlush();
   1.228 +      }
   1.229 +    }
   1.230 +  }
   1.231 +}
   1.232 +
   1.233 +void
   1.234 +nsViewManager::FlushDelayedResize(bool aDoReflow)
   1.235 +{
   1.236 +  if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
   1.237 +    if (aDoReflow) {
   1.238 +      DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height);
   1.239 +      mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
   1.240 +    } else if (mPresShell) {
   1.241 +      nsPresContext* presContext = mPresShell->GetPresContext();
   1.242 +      if (presContext) {
   1.243 +        presContext->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize));
   1.244 +      }
   1.245 +    }
   1.246 +  }
   1.247 +}
   1.248 +
   1.249 +// Convert aIn from being relative to and in appunits of aFromView, to being
   1.250 +// relative to and in appunits of aToView.
   1.251 +static nsRegion ConvertRegionBetweenViews(const nsRegion& aIn,
   1.252 +                                          nsView* aFromView,
   1.253 +                                          nsView* aToView)
   1.254 +{
   1.255 +  nsRegion out = aIn;
   1.256 +  out.MoveBy(aFromView->GetOffsetTo(aToView));
   1.257 +  out = out.ConvertAppUnitsRoundOut(
   1.258 +    aFromView->GetViewManager()->AppUnitsPerDevPixel(),
   1.259 +    aToView->GetViewManager()->AppUnitsPerDevPixel());
   1.260 +  return out;
   1.261 +}
   1.262 +
   1.263 +nsView* nsViewManager::GetDisplayRootFor(nsView* aView)
   1.264 +{
   1.265 +  nsView *displayRoot = aView;
   1.266 +  for (;;) {
   1.267 +    nsView *displayParent = displayRoot->GetParent();
   1.268 +    if (!displayParent)
   1.269 +      return displayRoot;
   1.270 +
   1.271 +    if (displayRoot->GetFloating() && !displayParent->GetFloating())
   1.272 +      return displayRoot;
   1.273 +
   1.274 +    // If we have a combobox dropdown popup within a panel popup, both the view
   1.275 +    // for the dropdown popup and its parent will be floating, so we need to
   1.276 +    // distinguish this situation. We do this by looking for a widget. Any view
   1.277 +    // with a widget is a display root, except for plugins.
   1.278 +    nsIWidget* widget = displayRoot->GetWidget();
   1.279 +    if (widget && widget->WindowType() == eWindowType_popup) {
   1.280 +      NS_ASSERTION(displayRoot->GetFloating() && displayParent->GetFloating(),
   1.281 +        "this should only happen with floating views that have floating parents");
   1.282 +      return displayRoot;
   1.283 +    }
   1.284 +
   1.285 +    displayRoot = displayParent;
   1.286 +  }
   1.287 +}
   1.288 +
   1.289 +/**
   1.290 +   aRegion is given in device coordinates!!
   1.291 +   aContext may be null, in which case layers should be used for
   1.292 +   rendering.
   1.293 +*/
   1.294 +void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion)
   1.295 +{
   1.296 +  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
   1.297 +
   1.298 +  if (mPresShell && mPresShell->IsNeverPainting()) {
   1.299 +    return;
   1.300 +  }
   1.301 +
   1.302 +  // damageRegion is the damaged area, in twips, relative to the view origin
   1.303 +  nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
   1.304 +  // move region from widget coordinates into view coordinates
   1.305 +  damageRegion.MoveBy(-aView->ViewToWidgetOffset());
   1.306 +
   1.307 +  if (damageRegion.IsEmpty()) {
   1.308 +#ifdef DEBUG_roc
   1.309 +    nsRect viewRect = aView->GetDimensions();
   1.310 +    nsRect damageRect = damageRegion.GetBounds();
   1.311 +    printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
   1.312 +           damageRect.x, damageRect.y, damageRect.width, damageRect.height,
   1.313 +           viewRect.x, viewRect.y, viewRect.width, viewRect.height);
   1.314 +#endif
   1.315 +    return;
   1.316 +  }
   1.317 +  
   1.318 +  nsIWidget *widget = aView->GetWidget();
   1.319 +  if (!widget) {
   1.320 +    return;
   1.321 +  }
   1.322 +
   1.323 +  NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
   1.324 +  if (IsPainting()) {
   1.325 +    RootViewManager()->mRecursiveRefreshPending = true;
   1.326 +    return;
   1.327 +  }  
   1.328 +
   1.329 +  {
   1.330 +    nsAutoScriptBlocker scriptBlocker;
   1.331 +    SetPainting(true);
   1.332 +
   1.333 +    NS_ASSERTION(GetDisplayRootFor(aView) == aView,
   1.334 +                 "Widgets that we paint must all be display roots");
   1.335 +
   1.336 +    if (mPresShell) {
   1.337 +#ifdef MOZ_DUMP_PAINTING
   1.338 +      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
   1.339 +        printf_stderr("--COMPOSITE-- %p\n", mPresShell);
   1.340 +      }
   1.341 +#endif
   1.342 +      uint32_t paintFlags = nsIPresShell::PAINT_COMPOSITE;
   1.343 +      LayerManager *manager = widget->GetLayerManager();
   1.344 +      if (!manager->NeedsWidgetInvalidation()) {
   1.345 +        manager->FlushRendering();
   1.346 +      } else {
   1.347 +        mPresShell->Paint(aView, damageRegion,
   1.348 +                          paintFlags);
   1.349 +      }
   1.350 +#ifdef MOZ_DUMP_PAINTING
   1.351 +      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
   1.352 +        printf_stderr("--ENDCOMPOSITE--\n");
   1.353 +      }
   1.354 +#endif
   1.355 +      mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
   1.356 +    }
   1.357 +
   1.358 +    SetPainting(false);
   1.359 +  }
   1.360 +
   1.361 +  if (RootViewManager()->mRecursiveRefreshPending) {
   1.362 +    RootViewManager()->mRecursiveRefreshPending = false;
   1.363 +    InvalidateAllViews();
   1.364 +  }
   1.365 +}
   1.366 +
   1.367 +void
   1.368 +nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
   1.369 +                                            bool aFlushDirtyRegion)
   1.370 +{
   1.371 +  NS_ASSERTION(IsRootVM(), "Updates will be missed");
   1.372 +  if (!aView) {
   1.373 +    return;
   1.374 +  }
   1.375 +
   1.376 +  nsCOMPtr<nsIPresShell> rootShell(mPresShell);
   1.377 +  nsTArray<nsCOMPtr<nsIWidget> > widgets;
   1.378 +  aView->GetViewManager()->ProcessPendingUpdatesRecurse(aView, widgets);
   1.379 +  for (uint32_t i = 0; i < widgets.Length(); ++i) {
   1.380 +    nsView* view = nsView::GetViewFor(widgets[i]);
   1.381 +    if (view) {
   1.382 +      view->ResetWidgetBounds(false, true);
   1.383 +    }
   1.384 +  }
   1.385 +  if (rootShell->GetViewManager() != this) {
   1.386 +    return; // 'this' might have been destroyed
   1.387 +  }
   1.388 +  if (aFlushDirtyRegion) {
   1.389 +    nsAutoScriptBlocker scriptBlocker;
   1.390 +    SetPainting(true);
   1.391 +    for (uint32_t i = 0; i < widgets.Length(); ++i) {
   1.392 +      nsIWidget* widget = widgets[i];
   1.393 +      nsView* view = nsView::GetViewFor(widget);
   1.394 +      if (view) {
   1.395 +        view->GetViewManager()->ProcessPendingUpdatesPaint(widget);
   1.396 +      }
   1.397 +    }
   1.398 +    SetPainting(false);
   1.399 +  }
   1.400 +}
   1.401 +
   1.402 +void
   1.403 +nsViewManager::ProcessPendingUpdatesRecurse(nsView* aView,
   1.404 +                                            nsTArray<nsCOMPtr<nsIWidget> >& aWidgets)
   1.405 +{
   1.406 +  if (mPresShell && mPresShell->IsNeverPainting()) {
   1.407 +    return;
   1.408 +  }
   1.409 +
   1.410 +  for (nsView* childView = aView->GetFirstChild(); childView;
   1.411 +       childView = childView->GetNextSibling()) {
   1.412 +    childView->GetViewManager()->
   1.413 +      ProcessPendingUpdatesRecurse(childView, aWidgets);
   1.414 +  }
   1.415 +
   1.416 +  nsIWidget* widget = aView->GetWidget();
   1.417 +  if (widget) {
   1.418 +    aWidgets.AppendElement(widget);
   1.419 +  } else {
   1.420 +    FlushDirtyRegionToWidget(aView);
   1.421 +  }
   1.422 +}
   1.423 +
   1.424 +void
   1.425 +nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget)
   1.426 +{
   1.427 +  if (aWidget->NeedsPaint()) {
   1.428 +    // If an ancestor widget was hidden and then shown, we could
   1.429 +    // have a delayed resize to handle.
   1.430 +    for (nsViewManager *vm = this; vm;
   1.431 +         vm = vm->mRootView->GetParent()
   1.432 +           ? vm->mRootView->GetParent()->GetViewManager()
   1.433 +           : nullptr) {
   1.434 +      if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
   1.435 +          vm->mRootView->IsEffectivelyVisible() &&
   1.436 +          vm->mPresShell && vm->mPresShell->IsVisible()) {
   1.437 +        vm->FlushDelayedResize(true);
   1.438 +      }
   1.439 +    }
   1.440 +    nsView* view = nsView::GetViewFor(aWidget);
   1.441 +    if (!view) {
   1.442 +      NS_ERROR("FlushDelayedResize destroyed the nsView?");
   1.443 +      return;
   1.444 +    }
   1.445 +
   1.446 +    if (mPresShell) {
   1.447 +#ifdef MOZ_DUMP_PAINTING
   1.448 +      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
   1.449 +        printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n",
   1.450 +                      mPresShell, view, aWidget);
   1.451 +      }
   1.452 +#endif
   1.453 +
   1.454 +      mPresShell->Paint(view, nsRegion(), nsIPresShell::PAINT_LAYERS);
   1.455 +      view->SetForcedRepaint(false);
   1.456 +
   1.457 +#ifdef MOZ_DUMP_PAINTING
   1.458 +      if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
   1.459 +        printf_stderr("---- PAINT END ----\n");
   1.460 +      }
   1.461 +#endif
   1.462 +    }
   1.463 +  }
   1.464 +  FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget));
   1.465 +}
   1.466 +
   1.467 +void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
   1.468 +{
   1.469 +  NS_ASSERTION(aView->GetViewManager() == this,
   1.470 +               "FlushDirtyRegionToWidget called on view we don't own");
   1.471 +
   1.472 +  if (!aView->HasNonEmptyDirtyRegion())
   1.473 +    return;
   1.474 +
   1.475 +  nsRegion* dirtyRegion = aView->GetDirtyRegion();
   1.476 +  nsView* nearestViewWithWidget = aView;
   1.477 +  while (!nearestViewWithWidget->HasWidget() &&
   1.478 +         nearestViewWithWidget->GetParent()) {
   1.479 +    nearestViewWithWidget = nearestViewWithWidget->GetParent();
   1.480 +  }
   1.481 +  nsRegion r =
   1.482 +    ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
   1.483 +
   1.484 +  // If we draw the frame counter we need to make sure we invalidate the area
   1.485 +  // for it to make it on screen
   1.486 +  if (gfxPrefs::DrawFrameCounter()) {
   1.487 +    nsRect counterBounds = gfxPlatform::FrameCounterBounds().ToAppUnits(AppUnitsPerDevPixel());
   1.488 +    r = r.Or(r, counterBounds);
   1.489 +  }
   1.490 +
   1.491 +  nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
   1.492 +  widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
   1.493 +  dirtyRegion->SetEmpty();
   1.494 +}
   1.495 +
   1.496 +void
   1.497 +nsViewManager::InvalidateView(nsView *aView)
   1.498 +{
   1.499 +  // Mark the entire view as damaged
   1.500 +  InvalidateView(aView, aView->GetDimensions());
   1.501 +}
   1.502 +
   1.503 +static void
   1.504 +AddDirtyRegion(nsView *aView, const nsRegion &aDamagedRegion)
   1.505 +{
   1.506 +  nsRegion* dirtyRegion = aView->GetDirtyRegion();
   1.507 +  if (!dirtyRegion)
   1.508 +    return;
   1.509 +
   1.510 +  dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
   1.511 +  dirtyRegion->SimplifyOutward(8);
   1.512 +}
   1.513 +
   1.514 +void
   1.515 +nsViewManager::PostPendingUpdate()
   1.516 +{
   1.517 +  nsViewManager* rootVM = RootViewManager();
   1.518 +  rootVM->mHasPendingWidgetGeometryChanges = true;
   1.519 +  if (rootVM->mPresShell) {
   1.520 +    rootVM->mPresShell->ScheduleViewManagerFlush();
   1.521 +  }
   1.522 +}
   1.523 +
   1.524 +/**
   1.525 + * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
   1.526 + * every widget child of aWidgetView, plus aWidgetView's own widget
   1.527 + */
   1.528 +void
   1.529 +nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
   1.530 +                                    const nsRegion &aDamagedRegion)
   1.531 +{
   1.532 +  NS_ASSERTION(aWidgetView->GetViewManager() == this,
   1.533 +               "InvalidateWidgetArea called on view we don't own");
   1.534 +  nsIWidget* widget = aWidgetView->GetWidget();
   1.535 +
   1.536 +#if 0
   1.537 +  nsRect dbgBounds = aDamagedRegion.GetBounds();
   1.538 +  printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
   1.539 +    aWidgetView, aWidgetView->IsAttachedToTopLevel(),
   1.540 +    widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
   1.541 +#endif
   1.542 +
   1.543 +  // If the widget is hidden, it don't cover nothing
   1.544 +  if (widget && !widget->IsVisible()) {
   1.545 +    return;
   1.546 +  }
   1.547 +
   1.548 +  if (!widget) {
   1.549 +    // The root view or a scrolling view might not have a widget
   1.550 +    // (for example, during printing). We get here when we scroll
   1.551 +    // during printing to show selected options in a listbox, for example.
   1.552 +    return;
   1.553 +  }
   1.554 +
   1.555 +  // Update all child widgets with the damage. In the process,
   1.556 +  // accumulate the union of all the child widget areas, or at least
   1.557 +  // some subset of that.
   1.558 +  nsRegion children;
   1.559 +  if (widget->GetTransparencyMode() != eTransparencyTransparent) {
   1.560 +    for (nsIWidget* childWidget = widget->GetFirstChild();
   1.561 +         childWidget;
   1.562 +         childWidget = childWidget->GetNextSibling()) {
   1.563 +      nsView* view = nsView::GetViewFor(childWidget);
   1.564 +      NS_ASSERTION(view != aWidgetView, "will recur infinitely");
   1.565 +      nsWindowType type = childWidget->WindowType();
   1.566 +      if (view && childWidget->IsVisible() && type != eWindowType_popup) {
   1.567 +        NS_ASSERTION(type == eWindowType_plugin,
   1.568 +                     "Only plugin or popup widgets can be children!");
   1.569 +
   1.570 +        // We do not need to invalidate in plugin widgets, but we should
   1.571 +        // exclude them from the invalidation region IF we're not on
   1.572 +        // Mac. On Mac we need to draw under plugin widgets, because
   1.573 +        // plugin widgets are basically invisible
   1.574 +#ifndef XP_MACOSX
   1.575 +        // GetBounds should compensate for chrome on a toplevel widget
   1.576 +        nsIntRect bounds;
   1.577 +        childWidget->GetBounds(bounds);
   1.578 +
   1.579 +        nsTArray<nsIntRect> clipRects;
   1.580 +        childWidget->GetWindowClipRegion(&clipRects);
   1.581 +        for (uint32_t i = 0; i < clipRects.Length(); ++i) {
   1.582 +          nsRect rr = (clipRects[i] + bounds.TopLeft()).
   1.583 +            ToAppUnits(AppUnitsPerDevPixel());
   1.584 +          children.Or(children, rr - aWidgetView->ViewToWidgetOffset()); 
   1.585 +          children.SimplifyInward(20);
   1.586 +        }
   1.587 +#endif
   1.588 +      }
   1.589 +    }
   1.590 +  }
   1.591 +
   1.592 +  nsRegion leftOver;
   1.593 +  leftOver.Sub(aDamagedRegion, children);
   1.594 +
   1.595 +  if (!leftOver.IsEmpty()) {
   1.596 +    const nsRect* r;
   1.597 +    for (nsRegionRectIterator iter(leftOver); (r = iter.Next());) {
   1.598 +      nsIntRect bounds = ViewToWidget(aWidgetView, *r);
   1.599 +      widget->Invalidate(bounds);
   1.600 +    }
   1.601 +  }
   1.602 +}
   1.603 +
   1.604 +static bool
   1.605 +ShouldIgnoreInvalidation(nsViewManager* aVM)
   1.606 +{
   1.607 +  while (aVM) {
   1.608 +    nsIPresShell* shell = aVM->GetPresShell();
   1.609 +    if (!shell || shell->ShouldIgnoreInvalidation()) {
   1.610 +      return true;
   1.611 +    }
   1.612 +    nsView* view = aVM->GetRootView()->GetParent();
   1.613 +    aVM = view ? view->GetViewManager() : nullptr;
   1.614 +  }
   1.615 +  return false;
   1.616 +}
   1.617 +
   1.618 +void
   1.619 +nsViewManager::InvalidateView(nsView *aView, const nsRect &aRect)
   1.620 +{
   1.621 +  // If painting is suppressed in the presshell or an ancestor drop all
   1.622 +  // invalidates, it will invalidate everything when it unsuppresses.
   1.623 +  if (ShouldIgnoreInvalidation(this)) {
   1.624 +    return;
   1.625 +  }
   1.626 +
   1.627 +  InvalidateViewNoSuppression(aView, aRect);
   1.628 +}
   1.629 +
   1.630 +void
   1.631 +nsViewManager::InvalidateViewNoSuppression(nsView *aView,
   1.632 +                                           const nsRect &aRect)
   1.633 +{
   1.634 +  NS_PRECONDITION(nullptr != aView, "null view");
   1.635 +
   1.636 +  NS_ASSERTION(aView->GetViewManager() == this,
   1.637 +               "InvalidateViewNoSuppression called on view we don't own");
   1.638 +
   1.639 +  nsRect damagedRect(aRect);
   1.640 +  if (damagedRect.IsEmpty()) {
   1.641 +    return;
   1.642 +  }
   1.643 +
   1.644 +  nsView* displayRoot = GetDisplayRootFor(aView);
   1.645 +  nsViewManager* displayRootVM = displayRoot->GetViewManager();
   1.646 +  // Propagate the update to the displayRoot, since iframes, for example,
   1.647 +  // can overlap each other and be translucent.  So we have to possibly
   1.648 +  // invalidate our rect in each of the widgets we have lying about.
   1.649 +  damagedRect.MoveBy(aView->GetOffsetTo(displayRoot));
   1.650 +  int32_t rootAPD = displayRootVM->AppUnitsPerDevPixel();
   1.651 +  int32_t APD = AppUnitsPerDevPixel();
   1.652 +  damagedRect = damagedRect.ConvertAppUnitsRoundOut(APD, rootAPD);
   1.653 +
   1.654 +  // accumulate this rectangle in the view's dirty region, so we can
   1.655 +  // process it later.
   1.656 +  AddDirtyRegion(displayRoot, nsRegion(damagedRect));
   1.657 +}
   1.658 +
   1.659 +void
   1.660 +nsViewManager::InvalidateAllViews()
   1.661 +{
   1.662 +  if (RootViewManager() != this) {
   1.663 +    return RootViewManager()->InvalidateAllViews();
   1.664 +  }
   1.665 +  
   1.666 +  InvalidateViews(mRootView);
   1.667 +}
   1.668 +
   1.669 +void nsViewManager::InvalidateViews(nsView *aView)
   1.670 +{
   1.671 +  // Invalidate this view.
   1.672 +  InvalidateView(aView);
   1.673 +
   1.674 +  // Invalidate all children as well.
   1.675 +  nsView* childView = aView->GetFirstChild();
   1.676 +  while (nullptr != childView)  {
   1.677 +    childView->GetViewManager()->InvalidateViews(childView);
   1.678 +    childView = childView->GetNextSibling();
   1.679 +  }
   1.680 +}
   1.681 +
   1.682 +void nsViewManager::WillPaintWindow(nsIWidget* aWidget)
   1.683 +{
   1.684 +  if (aWidget) {
   1.685 +    nsView* view = nsView::GetViewFor(aWidget);
   1.686 +    LayerManager *manager = aWidget->GetLayerManager();
   1.687 +    if (view &&
   1.688 +        (view->ForcedRepaint() || !manager->NeedsWidgetInvalidation())) {
   1.689 +      ProcessPendingUpdates();
   1.690 +      // Re-get the view pointer here since the ProcessPendingUpdates might have
   1.691 +      // destroyed it during CallWillPaintOnObservers.
   1.692 +      view = nsView::GetViewFor(aWidget);
   1.693 +      if (view) {
   1.694 +        view->SetForcedRepaint(false);
   1.695 +      }
   1.696 +    }
   1.697 +  }
   1.698 +
   1.699 +  nsCOMPtr<nsIPresShell> shell = mPresShell;
   1.700 +  if (shell) {
   1.701 +    shell->WillPaintWindow();
   1.702 +  }
   1.703 +}
   1.704 +
   1.705 +bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion)
   1.706 +{
   1.707 +  if (!aWidget || !mContext)
   1.708 +    return false;
   1.709 +
   1.710 +  NS_ASSERTION(IsPaintingAllowed(),
   1.711 +               "shouldn't be receiving paint events while painting is disallowed!");
   1.712 +
   1.713 +  // Get the view pointer here since NS_WILL_PAINT might have
   1.714 +  // destroyed it during CallWillPaintOnObservers (bug 378273).
   1.715 +  nsView* view = nsView::GetViewFor(aWidget);
   1.716 +  if (view && !aRegion.IsEmpty()) {
   1.717 +    Refresh(view, aRegion);
   1.718 +  }
   1.719 +
   1.720 +  return true;
   1.721 +}
   1.722 +
   1.723 +void nsViewManager::DidPaintWindow()
   1.724 +{
   1.725 +  nsCOMPtr<nsIPresShell> shell = mPresShell;
   1.726 +  if (shell) {
   1.727 +    shell->DidPaintWindow();
   1.728 +  }
   1.729 +}
   1.730 +
   1.731 +void
   1.732 +nsViewManager::DispatchEvent(WidgetGUIEvent *aEvent,
   1.733 +                             nsView* aView,
   1.734 +                             nsEventStatus* aStatus)
   1.735 +{
   1.736 +  PROFILER_LABEL("event", "nsViewManager::DispatchEvent");
   1.737 +
   1.738 +  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   1.739 +  if ((mouseEvent &&
   1.740 +       // Ignore mouse events that we synthesize.
   1.741 +       mouseEvent->reason == WidgetMouseEvent::eReal &&
   1.742 +       // Ignore mouse exit and enter (we'll get moves if the user
   1.743 +       // is really moving the mouse) since we get them when we
   1.744 +       // create and destroy widgets.
   1.745 +       mouseEvent->message != NS_MOUSE_EXIT &&
   1.746 +       mouseEvent->message != NS_MOUSE_ENTER) ||
   1.747 +      aEvent->HasKeyEventMessage() ||
   1.748 +      aEvent->HasIMEEventMessage() ||
   1.749 +      aEvent->message == NS_PLUGIN_INPUT_EVENT) {
   1.750 +    gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
   1.751 +  }
   1.752 +
   1.753 +  // Find the view whose coordinates system we're in.
   1.754 +  nsView* view = aView;
   1.755 +  bool dispatchUsingCoordinates = aEvent->IsUsingCoordinates();
   1.756 +  if (dispatchUsingCoordinates) {
   1.757 +    // Will dispatch using coordinates. Pretty bogus but it's consistent
   1.758 +    // with what presshell does.
   1.759 +    view = GetDisplayRootFor(view);
   1.760 +  }
   1.761 +
   1.762 +  // If the view has no frame, look for a view that does.
   1.763 +  nsIFrame* frame = view->GetFrame();
   1.764 +  if (!frame &&
   1.765 +      (dispatchUsingCoordinates || aEvent->HasKeyEventMessage() ||
   1.766 +       aEvent->IsIMERelatedEvent() ||
   1.767 +       aEvent->IsNonRetargetedNativeEventDelivererForPlugin() ||
   1.768 +       aEvent->HasPluginActivationEventMessage() ||
   1.769 +       aEvent->message == NS_PLUGIN_RESOLUTION_CHANGED)) {
   1.770 +    while (view && !view->GetFrame()) {
   1.771 +      view = view->GetParent();
   1.772 +    }
   1.773 +
   1.774 +    if (view) {
   1.775 +      frame = view->GetFrame();
   1.776 +    }
   1.777 +  }
   1.778 +
   1.779 +  if (nullptr != frame) {
   1.780 +    // Hold a refcount to the presshell. The continued existence of the
   1.781 +    // presshell will delay deletion of this view hierarchy should the event
   1.782 +    // want to cause its destruction in, say, some JavaScript event handler.
   1.783 +    nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
   1.784 +    if (shell) {
   1.785 +      shell->HandleEvent(frame, aEvent, false, aStatus);
   1.786 +	  return;
   1.787 +    }
   1.788 +  }
   1.789 +
   1.790 +  *aStatus = nsEventStatus_eIgnore;
   1.791 +}
   1.792 +
   1.793 +// Recursively reparent widgets if necessary 
   1.794 +
   1.795 +void nsViewManager::ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget)
   1.796 +{
   1.797 +  NS_PRECONDITION(aNewWidget, "");
   1.798 +
   1.799 +  if (aView->HasWidget()) {
   1.800 +    // Check to see if the parent widget is the
   1.801 +    // same as the new parent. If not then reparent
   1.802 +    // the widget, otherwise there is nothing more
   1.803 +    // to do for the view and its descendants
   1.804 +    nsIWidget* widget = aView->GetWidget();
   1.805 +    nsIWidget* parentWidget = widget->GetParent();
   1.806 +    if (parentWidget) {
   1.807 +      // Child widget
   1.808 +      if (parentWidget != aNewWidget) {
   1.809 +#ifdef DEBUG
   1.810 +        nsresult rv =
   1.811 +#endif
   1.812 +          widget->SetParent(aNewWidget);
   1.813 +        NS_ASSERTION(NS_SUCCEEDED(rv), "SetParent failed!");
   1.814 +      }
   1.815 +    } else {
   1.816 +      // Toplevel widget (popup, dialog, etc)
   1.817 +      widget->ReparentNativeWidget(aNewWidget);
   1.818 +    }
   1.819 +    return;
   1.820 +  }
   1.821 +
   1.822 +  // Need to check each of the views children to see
   1.823 +  // if they have a widget and reparent it.
   1.824 +
   1.825 +  for (nsView *kid = aView->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
   1.826 +    ReparentChildWidgets(kid, aNewWidget);
   1.827 +  }
   1.828 +}
   1.829 +
   1.830 +// Reparent a view and its descendant views widgets if necessary
   1.831 +
   1.832 +void nsViewManager::ReparentWidgets(nsView* aView, nsView *aParent)
   1.833 +{
   1.834 +  NS_PRECONDITION(aParent, "Must have a parent");
   1.835 +  NS_PRECONDITION(aView, "Must have a view");
   1.836 +  
   1.837 +  // Quickly determine whether the view has pre-existing children or a
   1.838 +  // widget. In most cases the view will not have any pre-existing 
   1.839 +  // children when this is called.  Only in the case
   1.840 +  // where a view has been reparented by removing it from
   1.841 +  // a reinserting it into a new location in the view hierarchy do we
   1.842 +  // have to consider reparenting the existing widgets for the view and
   1.843 +  // it's descendants.
   1.844 +  if (aView->HasWidget() || aView->GetFirstChild()) {
   1.845 +    nsIWidget* parentWidget = aParent->GetNearestWidget(nullptr);
   1.846 +    if (parentWidget) {
   1.847 +      ReparentChildWidgets(aView, parentWidget);
   1.848 +      return;
   1.849 +    }
   1.850 +    NS_WARNING("Can not find a widget for the parent view");
   1.851 +  }
   1.852 +}
   1.853 +
   1.854 +void
   1.855 +nsViewManager::InsertChild(nsView *aParent, nsView *aChild, nsView *aSibling,
   1.856 +                           bool aAfter)
   1.857 +{
   1.858 +  NS_PRECONDITION(nullptr != aParent, "null ptr");
   1.859 +  NS_PRECONDITION(nullptr != aChild, "null ptr");
   1.860 +  NS_ASSERTION(aSibling == nullptr || aSibling->GetParent() == aParent,
   1.861 +               "tried to insert view with invalid sibling");
   1.862 +  NS_ASSERTION(!IsViewInserted(aChild), "tried to insert an already-inserted view");
   1.863 +
   1.864 +  if ((nullptr != aParent) && (nullptr != aChild))
   1.865 +    {
   1.866 +      // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
   1.867 +      // order, otherwise after 'kid' (i.e. before 'kid' in document order).
   1.868 +
   1.869 +      if (nullptr == aSibling) {
   1.870 +        if (aAfter) {
   1.871 +          // insert at end of document order, i.e., before first view
   1.872 +          // this is the common case, by far
   1.873 +          aParent->InsertChild(aChild, nullptr);
   1.874 +          ReparentWidgets(aChild, aParent);
   1.875 +        } else {
   1.876 +          // insert at beginning of document order, i.e., after last view
   1.877 +          nsView *kid = aParent->GetFirstChild();
   1.878 +          nsView *prev = nullptr;
   1.879 +          while (kid) {
   1.880 +            prev = kid;
   1.881 +            kid = kid->GetNextSibling();
   1.882 +          }
   1.883 +          // prev is last view or null if there are no children
   1.884 +          aParent->InsertChild(aChild, prev);
   1.885 +          ReparentWidgets(aChild, aParent);
   1.886 +        }
   1.887 +      } else {
   1.888 +        nsView *kid = aParent->GetFirstChild();
   1.889 +        nsView *prev = nullptr;
   1.890 +        while (kid && aSibling != kid) {
   1.891 +          //get the next sibling view
   1.892 +          prev = kid;
   1.893 +          kid = kid->GetNextSibling();
   1.894 +        }
   1.895 +        NS_ASSERTION(kid != nullptr,
   1.896 +                     "couldn't find sibling in child list");
   1.897 +        if (aAfter) {
   1.898 +          // insert after 'kid' in document order, i.e. before in view order
   1.899 +          aParent->InsertChild(aChild, prev);
   1.900 +          ReparentWidgets(aChild, aParent);
   1.901 +        } else {
   1.902 +          // insert before 'kid' in document order, i.e. after in view order
   1.903 +          aParent->InsertChild(aChild, kid);
   1.904 +          ReparentWidgets(aChild, aParent);
   1.905 +        }
   1.906 +      }
   1.907 +
   1.908 +      // if the parent view is marked as "floating", make the newly added view float as well.
   1.909 +      if (aParent->GetFloating())
   1.910 +        aChild->SetFloating(true);
   1.911 +    }
   1.912 +}
   1.913 +
   1.914 +void
   1.915 +nsViewManager::InsertChild(nsView *aParent, nsView *aChild, int32_t aZIndex)
   1.916 +{
   1.917 +  // no-one really calls this with anything other than aZIndex == 0 on a fresh view
   1.918 +  // XXX this method should simply be eliminated and its callers redirected to the real method
   1.919 +  SetViewZIndex(aChild, false, aZIndex);
   1.920 +  InsertChild(aParent, aChild, nullptr, true);
   1.921 +}
   1.922 +
   1.923 +void
   1.924 +nsViewManager::RemoveChild(nsView *aChild)
   1.925 +{
   1.926 +  NS_ASSERTION(aChild, "aChild must not be null");
   1.927 +
   1.928 +  nsView* parent = aChild->GetParent();
   1.929 +
   1.930 +  if (nullptr != parent) {
   1.931 +    NS_ASSERTION(aChild->GetViewManager() == this ||
   1.932 +                 parent->GetViewManager() == this, "wrong view manager");
   1.933 +    parent->RemoveChild(aChild);
   1.934 +  }
   1.935 +}
   1.936 +
   1.937 +void
   1.938 +nsViewManager::MoveViewTo(nsView *aView, nscoord aX, nscoord aY)
   1.939 +{
   1.940 +  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
   1.941 +  aView->SetPosition(aX, aY);
   1.942 +}
   1.943 +
   1.944 +void
   1.945 +nsViewManager::ResizeView(nsView *aView, const nsRect &aRect, bool aRepaintExposedAreaOnly)
   1.946 +{
   1.947 +  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
   1.948 +
   1.949 +  nsRect oldDimensions = aView->GetDimensions();
   1.950 +  if (!oldDimensions.IsEqualEdges(aRect)) {
   1.951 +    aView->SetDimensions(aRect, true);
   1.952 +  }
   1.953 +
   1.954 +  // Note that if layout resizes the view and the view has a custom clip
   1.955 +  // region set, then we expect layout to update the clip region too. Thus
   1.956 +  // in the case where mClipRect has been optimized away to just be a null
   1.957 +  // pointer, and this resize is implicitly changing the clip rect, it's OK
   1.958 +  // because layout will change it back again if necessary.
   1.959 +}
   1.960 +
   1.961 +void
   1.962 +nsViewManager::SetViewFloating(nsView *aView, bool aFloating)
   1.963 +{
   1.964 +  NS_ASSERTION(!(nullptr == aView), "no view");
   1.965 +
   1.966 +  aView->SetFloating(aFloating);
   1.967 +}
   1.968 +
   1.969 +void
   1.970 +nsViewManager::SetViewVisibility(nsView *aView, nsViewVisibility aVisible)
   1.971 +{
   1.972 +  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
   1.973 +
   1.974 +  if (aVisible != aView->GetVisibility()) {
   1.975 +    aView->SetVisibility(aVisible);
   1.976 +  }
   1.977 +}
   1.978 +
   1.979 +bool nsViewManager::IsViewInserted(nsView *aView)
   1.980 +{
   1.981 +  if (mRootView == aView) {
   1.982 +    return true;
   1.983 +  } else if (aView->GetParent() == nullptr) {
   1.984 +    return false;
   1.985 +  } else {
   1.986 +    nsView* view = aView->GetParent()->GetFirstChild();
   1.987 +    while (view != nullptr) {
   1.988 +      if (view == aView) {
   1.989 +        return true;
   1.990 +      }
   1.991 +      view = view->GetNextSibling();
   1.992 +    }
   1.993 +    return false;
   1.994 +  }
   1.995 +}
   1.996 +
   1.997 +void
   1.998 +nsViewManager::SetViewZIndex(nsView *aView, bool aAutoZIndex, int32_t aZIndex)
   1.999 +{
  1.1000 +  NS_ASSERTION((aView != nullptr), "no view");
  1.1001 +
  1.1002 +  // don't allow the root view's z-index to be changed. It should always be zero.
  1.1003 +  // This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
  1.1004 +  if (aView == mRootView) {
  1.1005 +    return;
  1.1006 +  }
  1.1007 +
  1.1008 +  if (aAutoZIndex) {
  1.1009 +    aZIndex = 0;
  1.1010 +  }
  1.1011 +
  1.1012 +  aView->SetZIndex(aAutoZIndex, aZIndex);
  1.1013 +}
  1.1014 +
  1.1015 +nsViewManager*
  1.1016 +nsViewManager::IncrementDisableRefreshCount()
  1.1017 +{
  1.1018 +  if (!IsRootVM()) {
  1.1019 +    return RootViewManager()->IncrementDisableRefreshCount();
  1.1020 +  }
  1.1021 +
  1.1022 +  ++mRefreshDisableCount;
  1.1023 +
  1.1024 +  return this;
  1.1025 +}
  1.1026 +
  1.1027 +void
  1.1028 +nsViewManager::DecrementDisableRefreshCount()
  1.1029 +{
  1.1030 +  NS_ASSERTION(IsRootVM(), "Should only be called on root");
  1.1031 +  --mRefreshDisableCount;
  1.1032 +  NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
  1.1033 +}
  1.1034 +
  1.1035 +void
  1.1036 +nsViewManager::GetRootWidget(nsIWidget **aWidget)
  1.1037 +{
  1.1038 +  if (!mRootView) {
  1.1039 +    *aWidget = nullptr;
  1.1040 +    return;
  1.1041 +  }
  1.1042 +  if (mRootView->HasWidget()) {
  1.1043 +    *aWidget = mRootView->GetWidget();
  1.1044 +    NS_ADDREF(*aWidget);
  1.1045 +    return;
  1.1046 +  }
  1.1047 +  if (mRootView->GetParent()) {
  1.1048 +    mRootView->GetParent()->GetViewManager()->GetRootWidget(aWidget);
  1.1049 +    return;
  1.1050 +  }
  1.1051 +  *aWidget = nullptr;
  1.1052 +}
  1.1053 +
  1.1054 +nsIntRect nsViewManager::ViewToWidget(nsView *aView, const nsRect &aRect) const
  1.1055 +{
  1.1056 +  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  1.1057 +
  1.1058 +  // account for the view's origin not lining up with the widget's
  1.1059 +  nsRect rect = aRect + aView->ViewToWidgetOffset();
  1.1060 +
  1.1061 +  // finally, convert to device coordinates.
  1.1062 +  return rect.ToOutsidePixels(AppUnitsPerDevPixel());
  1.1063 +}
  1.1064 +
  1.1065 +void
  1.1066 +nsViewManager::IsPainting(bool& aIsPainting)
  1.1067 +{
  1.1068 +  aIsPainting = IsPainting();
  1.1069 +}
  1.1070 +
  1.1071 +void
  1.1072 +nsViewManager::ProcessPendingUpdates()
  1.1073 +{
  1.1074 +  if (!IsRootVM()) {
  1.1075 +    RootViewManager()->ProcessPendingUpdates();
  1.1076 +    return;
  1.1077 +  }
  1.1078 +
  1.1079 +  mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
  1.1080 +
  1.1081 +  // Flush things like reflows by calling WillPaint on observer presShells.
  1.1082 +  if (mPresShell) {
  1.1083 +    CallWillPaintOnObservers();
  1.1084 +  }
  1.1085 +  ProcessPendingUpdatesForView(mRootView, true);
  1.1086 +}
  1.1087 +
  1.1088 +void
  1.1089 +nsViewManager::UpdateWidgetGeometry()
  1.1090 +{
  1.1091 +  if (!IsRootVM()) {
  1.1092 +    RootViewManager()->UpdateWidgetGeometry();
  1.1093 +    return;
  1.1094 +  }
  1.1095 +
  1.1096 +  if (mHasPendingWidgetGeometryChanges) {
  1.1097 +    mHasPendingWidgetGeometryChanges = false;
  1.1098 +    ProcessPendingUpdatesForView(mRootView, false);
  1.1099 +  }
  1.1100 +}
  1.1101 +
  1.1102 +void
  1.1103 +nsViewManager::CallWillPaintOnObservers()
  1.1104 +{
  1.1105 +  NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
  1.1106 +
  1.1107 +  int32_t index;
  1.1108 +  for (index = 0; index < mVMCount; index++) {
  1.1109 +    nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
  1.1110 +    if (vm->RootViewManager() == this) {
  1.1111 +      // One of our kids.
  1.1112 +      if (vm->mRootView && vm->mRootView->IsEffectivelyVisible()) {
  1.1113 +        nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
  1.1114 +        if (shell) {
  1.1115 +          shell->WillPaint();
  1.1116 +        }
  1.1117 +      }
  1.1118 +    }
  1.1119 +  }
  1.1120 +}
  1.1121 +
  1.1122 +void
  1.1123 +nsViewManager::GetLastUserEventTime(uint32_t& aTime)
  1.1124 +{
  1.1125 +  aTime = gLastUserEventTime;
  1.1126 +}
  1.1127 +
  1.1128 +void
  1.1129 +nsViewManager::InvalidateHierarchy()
  1.1130 +{
  1.1131 +  if (mRootView) {
  1.1132 +    if (!IsRootVM()) {
  1.1133 +      NS_RELEASE(mRootViewManager);
  1.1134 +    }
  1.1135 +    nsView *parent = mRootView->GetParent();
  1.1136 +    if (parent) {
  1.1137 +      mRootViewManager = parent->GetViewManager()->RootViewManager();
  1.1138 +      NS_ADDREF(mRootViewManager);
  1.1139 +      NS_ASSERTION(mRootViewManager != this,
  1.1140 +                   "Root view had a parent, but it has the same view manager");
  1.1141 +    } else {
  1.1142 +      mRootViewManager = this;
  1.1143 +    }
  1.1144 +  }
  1.1145 +}

mercurial