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.

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

mercurial