void nsViewManager::WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint)
{
  if (IsRefreshDriverPaintingEnabled())
    return;

  if (!aWidget || !mContext)
    return;

  // If an ancestor widget was hidden and then shown, we could
  // have a delayed resize to handle.
  for (nsViewManager *vm = this; vm;
       vm = vm->mRootView->GetParent()
              ? vm->mRootView->GetParent()->GetViewManager()
              : nullptr) {
    if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
        vm->mRootView->IsEffectivelyVisible() &&
        mPresShell && mPresShell->IsVisible()) {
      vm->FlushDelayedResize(true);
      vm->InvalidateView(vm->mRootView);
    }
  }

  // Flush things like reflows and plugin widget geometry updates by
  // calling WillPaint on observer presShells.
  nsRefPtr<nsViewManager> rootVM = RootViewManager();
  if (mPresShell) {
    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
  }

  // Flush view widget geometry updates and invalidations.
  rootVM->ProcessPendingUpdates();
}
void
nsViewManager::ProcessPendingUpdates()
{
  if (!IsRootVM()) {
    RootViewManager()->ProcessPendingUpdates();
    return;
  }

  if (IsRefreshDriverPaintingEnabled()) {
    mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
    if (mHasPendingUpdates) {
      mHasPendingUpdates = false;
      
      // Flush things like reflows and plugin widget geometry updates by
      // calling WillPaint on observer presShells.
      if (mPresShell) {
        CallWillPaintOnObservers(true);
      }
      ProcessPendingUpdatesForView(mRootView, true);
      CallDidPaintOnObserver();
    }
  } else if (mHasPendingUpdates) {
    ProcessPendingUpdatesForView(mRootView, true);
    mHasPendingUpdates = false;
  }
}
void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
                                                 bool aFlushDirtyRegion)
{
  NS_ASSERTION(IsRootVM(), "Updates will be missed");

  // Protect against a null-view.
  if (!aView) {
    return;
  }

  if (aView->HasWidget()) {
    aView->ResetWidgetBounds(false, true);
  }

  // process pending updates in child view.
  for (nsView* childView = aView->GetFirstChild(); childView;
       childView = childView->GetNextSibling()) {
    ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
  }

  // Push out updates after we've processed the children; ensures that
  // damage is applied based on the final widget geometry
  if (aFlushDirtyRegion && aView->HasNonEmptyDirtyRegion()) {
    FlushDirtyRegionToWidget(aView);
    if (IsRefreshDriverPaintingEnabled()) {
      nsIWidget *widget = aView->GetWidget();
      if (widget && widget->NeedsPaint()) {
        // If an ancestor widget was hidden and then shown, we could
        // have a delayed resize to handle.
        for (nsViewManager *vm = this; vm;
             vm = vm->mRootView->GetParent()
                    ? vm->mRootView->GetParent()->GetViewManager()
                    : nullptr) {
          if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
              vm->mRootView->IsEffectivelyVisible() &&
              mPresShell && mPresShell->IsVisible()) {
            vm->FlushDelayedResize(true);
            vm->InvalidateView(vm->mRootView);
          }
        }

        NS_ASSERTION(aView->HasWidget(), "Must have a widget!");

        SetPainting(true);
#ifdef DEBUG_INVALIDATIONS
        printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
#endif
        nsAutoScriptBlocker scriptBlocker;
        NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
        mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, true);
#ifdef DEBUG_INVALIDATIONS
        printf("---- PAINT END ----\n");
#endif
        aView->SetForcedRepaint(false);
        SetPainting(false);
      }
    }
  }
}
void
nsViewManager::UpdateWidgetGeometry()
{
  if (!IsRootVM()) {
    RootViewManager()->UpdateWidgetGeometry();
    return;
  }

  if (mHasPendingWidgetGeometryChanges) {
    if (IsRefreshDriverPaintingEnabled()) {
      mHasPendingWidgetGeometryChanges = false;
    }
    ProcessPendingUpdatesForView(mRootView, false);
    if (!IsRefreshDriverPaintingEnabled()) {
      mHasPendingWidgetGeometryChanges = false;
    }
  }
}
void nsViewManager::WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint)
{
  if (!IsRefreshDriverPaintingEnabled() && aWidget && mContext) {
    // If an ancestor widget was hidden and then shown, we could
    // have a delayed resize to handle.
    for (nsViewManager *vm = this; vm;
         vm = vm->mRootView->GetParent()
                ? vm->mRootView->GetParent()->GetViewManager()
                : nullptr) {
      if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
          vm->mRootView->IsEffectivelyVisible() &&
          mPresShell && mPresShell->IsVisible()) {
        vm->FlushDelayedResize(true);
        vm->InvalidateView(vm->mRootView);
      }
    }

    // Flush things like reflows by calling WillPaint on observer presShells.
    nsRefPtr<nsViewManager> rootVM = RootViewManager();
    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);

    // Flush view widget geometry updates and invalidations.
    rootVM->ProcessPendingUpdates();
  }

  if (aWidget && IsRefreshDriverPaintingEnabled()) {
    nsView* view = nsView::GetViewFor(aWidget);
    if (view && view->ForcedRepaint()) {
      ProcessPendingUpdates();
      // Re-get the view pointer here since the ProcessPendingUpdates might have
      // destroyed it during CallWillPaintOnObservers.
      view = nsView::GetViewFor(aWidget);
      if (view) {
        view->SetForcedRepaint(false);
      }
    }
  }

  nsCOMPtr<nsIPresShell> shell = mPresShell;
  if (shell) {
    shell->WillPaintWindow(aWillSendDidPaint);
  }
}
void
nsViewManager::ProcessPendingUpdates()
{
  if (!IsRootVM()) {
    RootViewManager()->ProcessPendingUpdates();
    return;
  }

  if (IsRefreshDriverPaintingEnabled()) {
    mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
      
    // Flush things like reflows by calling WillPaint on observer presShells.
    if (mPresShell) {
      CallWillPaintOnObservers(true);
    }
    ProcessPendingUpdatesForView(mRootView, true);
  } else {
    ProcessPendingUpdatesForView(mRootView, true);
  }
}
bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
                                uint32_t aFlags)
 {
  if (!aWidget || !mContext)
    return false;

  NS_ASSERTION(IsPaintingAllowed(),
               "shouldn't be receiving paint events while painting is disallowed!");

  if (!(aFlags & nsIWidgetListener::SENT_WILL_PAINT) && !IsRefreshDriverPaintingEnabled()) {
    WillPaintWindow(aWidget, (aFlags & nsIWidgetListener::WILL_SEND_DID_PAINT));
  }

  // Get the view pointer here since NS_WILL_PAINT might have
  // destroyed it during CallWillPaintOnObservers (bug 378273).
  nsView* view = nsView::GetViewFor(aWidget);
  if (view && !aRegion.IsEmpty()) {
    Refresh(view, aRegion, (aFlags & nsIWidgetListener::WILL_SEND_DID_PAINT));
  }

  return true;
}
/**
   aRegion is given in device coordinates!!
   aContext may be null, in which case layers should be used for
   rendering.
*/
void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
                            bool aWillSendDidPaint)
{
  NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");

  // damageRegion is the damaged area, in twips, relative to the view origin
  nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
  // move region from widget coordinates into view coordinates
  damageRegion.MoveBy(-aView->ViewToWidgetOffset());

  if (damageRegion.IsEmpty()) {
#ifdef DEBUG_roc
    nsRect viewRect = aView->GetDimensions();
    nsRect damageRect = damageRegion.GetBounds();
    printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
           damageRect.x, damageRect.y, damageRect.width, damageRect.height,
           viewRect.x, viewRect.y, viewRect.width, viewRect.height);
#endif
    return;
  }
  
  nsIWidget *widget = aView->GetWidget();
  if (!widget) {
    return;
  }

  NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
  if (IsPainting()) {
    RootViewManager()->mRecursiveRefreshPending = true;
    return;
  }  

  {
    nsAutoScriptBlocker scriptBlocker;
    SetPainting(true);

    NS_ASSERTION(GetDisplayRootFor(aView) == aView,
                 "Widgets that we paint must all be display roots");

    if (mPresShell) {
#ifdef DEBUG_INVALIDATIONS
      printf("--COMPOSITE-- %p\n", mPresShell);
#endif
      mPresShell->Paint(aView, damageRegion,
                        (IsRefreshDriverPaintingEnabled() ? 0 : nsIPresShell::PAINT_LAYERS) |
                        nsIPresShell::PAINT_COMPOSITE |
                        (aWillSendDidPaint ? nsIPresShell::PAINT_WILL_SEND_DID_PAINT : 0));
#ifdef DEBUG_INVALIDATIONS
      printf("--ENDCOMPOSITE--\n");
#endif
      mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
    }

    SetPainting(false);
  }

  if (RootViewManager()->mRecursiveRefreshPending) {
    RootViewManager()->mRecursiveRefreshPending = false;
    InvalidateAllViews();
  }
}
void nsViewManager::DidPaintWindow()
{
  if (!IsRefreshDriverPaintingEnabled()) {
    mRootViewManager->CallDidPaintOnObserver();
  }
}