view/src/nsView.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 #include "nsView.h"
     8 #include "mozilla/Attributes.h"
     9 #include "mozilla/BasicEvents.h"
    10 #include "mozilla/DebugOnly.h"
    11 #include "mozilla/IntegerPrintfMacros.h"
    12 #include "mozilla/Likely.h"
    13 #include "mozilla/Poison.h"
    14 #include "nsIWidget.h"
    15 #include "nsViewManager.h"
    16 #include "nsIFrame.h"
    17 #include "nsPresArena.h"
    18 #include "nsXULPopupManager.h"
    19 #include "nsIWidgetListener.h"
    20 #include "nsContentUtils.h" // for nsAutoScriptBlocker
    22 using namespace mozilla;
    24 nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
    25 {
    26   MOZ_COUNT_CTOR(nsView);
    28   mVis = aVisibility;
    29   // Views should be transparent by default. Not being transparent is
    30   // a promise that the view will paint all its pixels opaquely. Views
    31   // should make this promise explicitly by calling
    32   // SetViewContentTransparency.
    33   mVFlags = 0;
    34   mViewManager = aViewManager;
    35   mDirtyRegion = nullptr;
    36   mWidgetIsTopLevel = false;
    37 }
    39 void nsView::DropMouseGrabbing()
    40 {
    41   nsIPresShell* presShell = mViewManager->GetPresShell();
    42   if (presShell)
    43     presShell->ClearMouseCaptureOnView(this);
    44 }
    46 nsView::~nsView()
    47 {
    48   MOZ_COUNT_DTOR(nsView);
    50   while (GetFirstChild())
    51   {
    52     nsView* child = GetFirstChild();
    53     if (child->GetViewManager() == mViewManager) {
    54       child->Destroy();
    55     } else {
    56       // just unhook it. Someone else will want to destroy this.
    57       RemoveChild(child);
    58     }
    59   }
    61   if (mViewManager)
    62   {
    63     DropMouseGrabbing();
    65     nsView *rootView = mViewManager->GetRootView();
    67     if (rootView)
    68     {
    69       // Root views can have parents!
    70       if (mParent)
    71       {
    72         mViewManager->RemoveChild(this);
    73       }
    75       if (rootView == this)
    76       {
    77         // Inform the view manager that the root view has gone away...
    78         mViewManager->SetRootView(nullptr);
    79       }
    80     }
    81     else if (mParent)
    82     {
    83       mParent->RemoveChild(this);
    84     }
    86     mViewManager = nullptr;
    87   }
    88   else if (mParent)
    89   {
    90     mParent->RemoveChild(this);
    91   }
    93   // Destroy and release the widget
    94   DestroyWidget();
    96   delete mDirtyRegion;
    97 }
    99 class DestroyWidgetRunnable : public nsRunnable {
   100 public:
   101   NS_DECL_NSIRUNNABLE
   103   explicit DestroyWidgetRunnable(nsIWidget* aWidget) : mWidget(aWidget) {}
   105 private:
   106   nsCOMPtr<nsIWidget> mWidget;
   107 };
   109 NS_IMETHODIMP DestroyWidgetRunnable::Run()
   110 {
   111   mWidget->Destroy();
   112   mWidget = nullptr;
   113   return NS_OK;
   114 }
   117 void nsView::DestroyWidget()
   118 {
   119   if (mWindow)
   120   {
   121     // If we are not attached to a base window, we're going to tear down our
   122     // widget here. However, if we're attached to somebody elses widget, we
   123     // want to leave the widget alone: don't reset the client data or call
   124     // Destroy. Just clear our event view ptr and free our reference to it. 
   125     if (mWidgetIsTopLevel) {
   126       mWindow->SetAttachedWidgetListener(nullptr);
   127     }
   128     else {
   129       mWindow->SetWidgetListener(nullptr);
   131       nsCOMPtr<nsIRunnable> widgetDestroyer =
   132         new DestroyWidgetRunnable(mWindow);
   134       NS_DispatchToMainThread(widgetDestroyer);
   135     }
   137     NS_RELEASE(mWindow);
   138   }
   139 }
   141 nsView* nsView::GetViewFor(nsIWidget* aWidget)
   142 {
   143   NS_PRECONDITION(nullptr != aWidget, "null widget ptr");
   145   nsIWidgetListener* listener = aWidget->GetWidgetListener();
   146   if (listener) {
   147     nsView* view = listener->GetView();
   148     if (view)
   149       return view;
   150   }
   152   listener = aWidget->GetAttachedWidgetListener();
   153   return listener ? listener->GetView() : nullptr;
   154 }
   156 void nsView::Destroy()
   157 {
   158   this->~nsView();
   159   mozWritePoison(this, sizeof(*this));
   160   nsView::operator delete(this);
   161 }
   163 void nsView::SetPosition(nscoord aX, nscoord aY)
   164 {
   165   mDimBounds.x += aX - mPosX;
   166   mDimBounds.y += aY - mPosY;
   167   mPosX = aX;
   168   mPosY = aY;
   170   NS_ASSERTION(GetParent() || (aX == 0 && aY == 0),
   171                "Don't try to move the root widget to something non-zero");
   173   ResetWidgetBounds(true, false);
   174 }
   176 void nsView::ResetWidgetBounds(bool aRecurse, bool aForceSync)
   177 {
   178   if (mWindow) {
   179     if (!aForceSync) {
   180       // Don't change widget geometry synchronously, since that can
   181       // cause synchronous painting.
   182       mViewManager->PostPendingUpdate();
   183     } else {
   184       DoResetWidgetBounds(false, true);
   185     }
   186     return;
   187   }
   189   if (aRecurse) {
   190     // reposition any widgets under this view
   191     for (nsView* v = GetFirstChild(); v; v = v->GetNextSibling()) {
   192       v->ResetWidgetBounds(true, aForceSync);
   193     }
   194   }
   195 }
   197 bool nsView::IsEffectivelyVisible()
   198 {
   199   for (nsView* v = this; v; v = v->mParent) {
   200     if (v->GetVisibility() == nsViewVisibility_kHide)
   201       return false;
   202   }
   203   return true;
   204 }
   206 nsIntRect nsView::CalcWidgetBounds(nsWindowType aType)
   207 {
   208   int32_t p2a = mViewManager->AppUnitsPerDevPixel();
   210   nsRect viewBounds(mDimBounds);
   212   nsView* parent = GetParent();
   213   nsIWidget* parentWidget = nullptr;
   214   if (parent) {
   215     nsPoint offset;
   216     parentWidget = parent->GetNearestWidget(&offset, p2a);
   217     // make viewBounds be relative to the parent widget, in appunits
   218     viewBounds += offset;
   220     if (parentWidget && aType == eWindowType_popup &&
   221         IsEffectivelyVisible()) {
   222       // put offset into screen coordinates. (based on client area origin)
   223       nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
   224       viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
   225                             NSIntPixelsToAppUnits(screenPoint.y, p2a));
   226     }
   227   }
   229   // Compute widget bounds in device pixels
   230   nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
   232 #ifdef XP_MACOSX
   233   // cocoa rounds widget coordinates to the nearest global "display pixel"
   234   // integer value. So we avoid fractional display pixel values by rounding
   235   // to the nearest value that won't yield a fractional display pixel.
   236   nsIWidget* widget = parentWidget ? parentWidget : mWindow;
   237   uint32_t round;
   238   if (aType == eWindowType_popup && widget &&
   239       ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) {
   240     nsIntSize pixelRoundedSize = newBounds.Size();
   241     // round the top left and bottom right to the nearest round pixel
   242     newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round;
   243     newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round;
   244     newBounds.width =
   245       NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.XMost(), p2a) / round) * round - newBounds.x;
   246     newBounds.height =
   247       NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.YMost(), p2a) / round) * round - newBounds.y;
   248     // but if that makes the widget larger then our frame may not paint the
   249     // extra pixels, so reduce the size to the nearest round value
   250     if (newBounds.width > pixelRoundedSize.width) {
   251       newBounds.width -= round;
   252     }
   253     if (newBounds.height > pixelRoundedSize.height) {
   254       newBounds.height -= round;
   255     }
   256   }
   257 #endif
   259   // Compute where the top-left of our widget ended up relative to the parent
   260   // widget, in appunits.
   261   nsPoint roundedOffset(NSIntPixelsToAppUnits(newBounds.x, p2a),
   262                         NSIntPixelsToAppUnits(newBounds.y, p2a));
   264   // mViewToWidgetOffset is added to coordinates relative to the view origin
   265   // to get coordinates relative to the widget.
   266   // The view origin, relative to the parent widget, is at
   267   // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft().
   268   // Our widget, relative to the parent widget, is roundedOffset.
   269   mViewToWidgetOffset = nsPoint(mPosX, mPosY)
   270     - mDimBounds.TopLeft() + viewBounds.TopLeft() - roundedOffset;
   272   return newBounds;
   273 }
   275 void nsView::DoResetWidgetBounds(bool aMoveOnly,
   276                                  bool aInvalidateChangedSize) {
   277   // The geometry of a root view's widget is controlled externally,
   278   // NOT by sizing or positioning the view
   279   if (mViewManager->GetRootView() == this) {
   280     return;
   281   }
   283   NS_PRECONDITION(mWindow, "Why was this called??");
   285   // Hold this ref to make sure it stays alive.
   286   nsCOMPtr<nsIWidget> widget = mWindow;
   288   // Stash a copy of these and use them so we can handle this being deleted (say
   289   // from sync painting/flushing from Show/Move/Resize on the widget).
   290   nsIntRect newBounds;
   291   nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext();
   293   nsWindowType type = widget->WindowType();
   295   nsIntRect curBounds;
   296   widget->GetClientBounds(curBounds);
   297   bool invisiblePopup = type == eWindowType_popup &&
   298                         ((curBounds.IsEmpty() && mDimBounds.IsEmpty()) ||
   299                          mVis == nsViewVisibility_kHide);
   301   if (invisiblePopup) {
   302     // We're going to hit the early exit below, avoid calling CalcWidgetBounds.
   303   } else {
   304     newBounds = CalcWidgetBounds(type);
   305   }
   307   bool curVisibility = widget->IsVisible();
   308   bool newVisibility = IsEffectivelyVisible();
   309   if (curVisibility && !newVisibility) {
   310     widget->Show(false);
   311   }
   313   if (invisiblePopup) {
   314     // Don't manipulate empty or hidden popup widgets. For example there's no
   315     // point moving hidden comboboxes around, or doing X server roundtrips
   316     // to compute their true screen position. This could mean that WidgetToScreen
   317     // operations on these widgets don't return up-to-date values, but popup
   318     // positions aren't reliable anyway because of correction to be on or off-screen.
   319     return;
   320   }
   322   bool changedPos = curBounds.TopLeft() != newBounds.TopLeft();
   323   bool changedSize = curBounds.Size() != newBounds.Size();
   325   // Child views are never attached to top level widgets, this is safe.
   327   // Coordinates are converted to display pixels for window Move/Resize APIs,
   328   // because of the potential for device-pixel coordinate spaces for mixed
   329   // hidpi/lodpi screens to overlap each other and result in bad placement
   330   // (bug 814434).
   331   double invScale;
   333   // Bug 861270: for correct widget manipulation at arbitrary scale factors,
   334   // prefer to base scaling on widget->GetDefaultScale(). But only do this if
   335   // it matches the view manager's device context scale after allowing for the
   336   // quantization to app units, because of OS X multiscreen issues (where the
   337   // only two scales are 1.0 or 2.0, and so the quantization doesn't actually
   338   // cause problems anyhow).
   339   // In the case of a mismatch, fall back to scaling based on the dev context's
   340   // unscaledAppUnitsPerDevPixel value. On platforms where the device-pixel
   341   // scale is uniform across all displays (currently all except OS X), we'll
   342   // always use the precise value from mWindow->GetDefaultScale here.
   343   CSSToLayoutDeviceScale scale = widget->GetDefaultScale();
   344   if (NSToIntRound(60.0 / scale.scale) == dx->UnscaledAppUnitsPerDevPixel()) {
   345     invScale = 1.0 / scale.scale;
   346   } else {
   347     invScale = dx->UnscaledAppUnitsPerDevPixel() / 60.0;
   348   }
   350   if (changedPos) {
   351     if (changedSize && !aMoveOnly) {
   352       widget->ResizeClient(newBounds.x * invScale,
   353                            newBounds.y * invScale,
   354                            newBounds.width * invScale,
   355                            newBounds.height * invScale,
   356                            aInvalidateChangedSize);
   357     } else {
   358       widget->MoveClient(newBounds.x * invScale,
   359                          newBounds.y * invScale);
   360     }
   361   } else {
   362     if (changedSize && !aMoveOnly) {
   363       widget->ResizeClient(newBounds.width * invScale,
   364                            newBounds.height * invScale,
   365                            aInvalidateChangedSize);
   366     } // else do nothing!
   367   }
   369   if (!curVisibility && newVisibility) {
   370     widget->Show(true);
   371   }
   372 }
   374 void nsView::SetDimensions(const nsRect& aRect, bool aPaint, bool aResizeWidget)
   375 {
   376   nsRect dims = aRect;
   377   dims.MoveBy(mPosX, mPosY);
   379   // Don't use nsRect's operator== here, since it returns true when
   380   // both rects are empty even if they have different widths and we
   381   // have cases where that sort of thing matters to us.
   382   if (mDimBounds.TopLeft() == dims.TopLeft() &&
   383       mDimBounds.Size() == dims.Size()) {
   384     return;
   385   }
   387   mDimBounds = dims;
   389   if (aResizeWidget) {
   390     ResetWidgetBounds(false, false);
   391   }
   392 }
   394 void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible)
   395 {
   396   if (!aEffectivelyVisible)
   397   {
   398     DropMouseGrabbing();
   399   }
   401   SetForcedRepaint(true);
   403   if (nullptr != mWindow)
   404   {
   405     ResetWidgetBounds(false, false);
   406   }
   408   for (nsView* child = mFirstChild; child; child = child->mNextSibling) {
   409     if (child->mVis == nsViewVisibility_kHide) {
   410       // It was effectively hidden and still is
   411       continue;
   412     }
   413     // Our child is visible if we are
   414     child->NotifyEffectiveVisibilityChanged(aEffectivelyVisible);
   415   }
   416 }
   418 void nsView::SetVisibility(nsViewVisibility aVisibility)
   419 {
   420   mVis = aVisibility;
   421   NotifyEffectiveVisibilityChanged(IsEffectivelyVisible());
   422 }
   424 void nsView::SetFloating(bool aFloatingView)
   425 {
   426 	if (aFloatingView)
   427 		mVFlags |= NS_VIEW_FLAG_FLOATING;
   428 	else
   429 		mVFlags &= ~NS_VIEW_FLAG_FLOATING;
   430 }
   432 void nsView::InvalidateHierarchy(nsViewManager *aViewManagerParent)
   433 {
   434   if (mViewManager->GetRootView() == this)
   435     mViewManager->InvalidateHierarchy();
   437   for (nsView *child = mFirstChild; child; child = child->GetNextSibling())
   438     child->InvalidateHierarchy(aViewManagerParent);
   439 }
   441 void nsView::InsertChild(nsView *aChild, nsView *aSibling)
   442 {
   443   NS_PRECONDITION(nullptr != aChild, "null ptr");
   445   if (nullptr != aChild)
   446   {
   447     if (nullptr != aSibling)
   448     {
   449 #ifdef DEBUG
   450       NS_ASSERTION(aSibling->GetParent() == this, "tried to insert view with invalid sibling");
   451 #endif
   452       //insert after sibling
   453       aChild->SetNextSibling(aSibling->GetNextSibling());
   454       aSibling->SetNextSibling(aChild);
   455     }
   456     else
   457     {
   458       aChild->SetNextSibling(mFirstChild);
   459       mFirstChild = aChild;
   460     }
   461     aChild->SetParent(this);
   463     // If we just inserted a root view, then update the RootViewManager
   464     // on all view managers in the new subtree.
   466     nsViewManager *vm = aChild->GetViewManager();
   467     if (vm->GetRootView() == aChild)
   468     {
   469       aChild->InvalidateHierarchy(nullptr); // don't care about releasing grabs
   470     }
   471   }
   472 }
   474 void nsView::RemoveChild(nsView *child)
   475 {
   476   NS_PRECONDITION(nullptr != child, "null ptr");
   478   if (nullptr != child)
   479   {
   480     nsView* prevKid = nullptr;
   481     nsView* kid = mFirstChild;
   482     DebugOnly<bool> found = false;
   483     while (nullptr != kid) {
   484       if (kid == child) {
   485         if (nullptr != prevKid) {
   486           prevKid->SetNextSibling(kid->GetNextSibling());
   487         } else {
   488           mFirstChild = kid->GetNextSibling();
   489         }
   490         child->SetParent(nullptr);
   491         found = true;
   492         break;
   493       }
   494       prevKid = kid;
   495 	    kid = kid->GetNextSibling();
   496     }
   497     NS_ASSERTION(found, "tried to remove non child");
   499     // If we just removed a root view, then update the RootViewManager
   500     // on all view managers in the removed subtree.
   502     nsViewManager *vm = child->GetViewManager();
   503     if (vm->GetRootView() == child)
   504     {
   505       child->InvalidateHierarchy(GetViewManager());
   506     }
   507   }
   508 }
   510 // Native widgets ultimately just can't deal with the awesome power of
   511 // CSS2 z-index. However, we set the z-index on the widget anyway
   512 // because in many simple common cases the widgets do end up in the
   513 // right order. We set each widget's z-index to the z-index of the
   514 // nearest ancestor that has non-auto z-index.
   515 static void UpdateNativeWidgetZIndexes(nsView* aView, int32_t aZIndex)
   516 {
   517   if (aView->HasWidget()) {
   518     nsIWidget* widget = aView->GetWidget();
   519     if (widget->GetZIndex() != aZIndex) {
   520       widget->SetZIndex(aZIndex);
   521     }
   522   } else {
   523     for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
   524       if (v->GetZIndexIsAuto()) {
   525         UpdateNativeWidgetZIndexes(v, aZIndex);
   526       }
   527     }
   528   }
   529 }
   531 static int32_t FindNonAutoZIndex(nsView* aView)
   532 {
   533   while (aView) {
   534     if (!aView->GetZIndexIsAuto()) {
   535       return aView->GetZIndex();
   536     }
   537     aView = aView->GetParent();
   538   }
   539   return 0;
   540 }
   542 struct DefaultWidgetInitData : public nsWidgetInitData {
   543   DefaultWidgetInitData() : nsWidgetInitData()
   544   {
   545     mWindowType = eWindowType_child;
   546     clipChildren = true;
   547     clipSiblings = true;
   548   }
   549 };
   551 nsresult nsView::CreateWidget(nsWidgetInitData *aWidgetInitData,
   552                                bool aEnableDragDrop,
   553                                bool aResetVisibility)
   554 {
   555   AssertNoWindow();
   556   NS_ABORT_IF_FALSE(!aWidgetInitData ||
   557                     aWidgetInitData->mWindowType != eWindowType_popup,
   558                     "Use CreateWidgetForPopup");
   560   DefaultWidgetInitData defaultInitData;
   561   bool initDataPassedIn = !!aWidgetInitData;
   562   aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData;
   563   defaultInitData.mListenForResizes =
   564     (!initDataPassedIn && GetParent() &&
   565      GetParent()->GetViewManager() != mViewManager);
   567   nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
   569   nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext();
   571   nsIWidget* parentWidget =
   572     GetParent() ? GetParent()->GetNearestWidget(nullptr) : nullptr;
   573   if (!parentWidget) {
   574     NS_ERROR("nsView::CreateWidget without suitable parent widget??");
   575     return NS_ERROR_FAILURE;
   576   }
   578   // XXX: using aForceUseIWidgetParent=true to preserve previous
   579   // semantics.  It's not clear that it's actually needed.
   580   mWindow = parentWidget->CreateChild(trect, dx, aWidgetInitData,
   581                                       true).take();
   582   if (!mWindow) {
   583     return NS_ERROR_FAILURE;
   584   }
   586   InitializeWindow(aEnableDragDrop, aResetVisibility);
   588   return NS_OK;
   589 }
   591 nsresult nsView::CreateWidgetForParent(nsIWidget* aParentWidget,
   592                                         nsWidgetInitData *aWidgetInitData,
   593                                         bool aEnableDragDrop,
   594                                         bool aResetVisibility)
   595 {
   596   AssertNoWindow();
   597   NS_ABORT_IF_FALSE(!aWidgetInitData ||
   598                     aWidgetInitData->mWindowType != eWindowType_popup,
   599                     "Use CreateWidgetForPopup");
   600   NS_ABORT_IF_FALSE(aParentWidget, "Parent widget required");
   602   DefaultWidgetInitData defaultInitData;
   603   aWidgetInitData = aWidgetInitData ? aWidgetInitData : &defaultInitData;
   605   nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
   607   nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext();
   609   mWindow =
   610     aParentWidget->CreateChild(trect, dx, aWidgetInitData).take();
   611   if (!mWindow) {
   612     return NS_ERROR_FAILURE;
   613   }
   615   InitializeWindow(aEnableDragDrop, aResetVisibility);
   617   return NS_OK;
   618 }
   620 nsresult nsView::CreateWidgetForPopup(nsWidgetInitData *aWidgetInitData,
   621                                        nsIWidget* aParentWidget,
   622                                        bool aEnableDragDrop,
   623                                        bool aResetVisibility)
   624 {
   625   AssertNoWindow();
   626   NS_ABORT_IF_FALSE(aWidgetInitData, "Widget init data required");
   627   NS_ABORT_IF_FALSE(aWidgetInitData->mWindowType == eWindowType_popup,
   628                     "Use one of the other CreateWidget methods");
   630   nsIntRect trect = CalcWidgetBounds(aWidgetInitData->mWindowType);
   632   nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext();
   634   // XXX/cjones: having these two separate creation cases seems ... um
   635   // ... unnecessary, but it's the way the old code did it.  Please
   636   // unify them by first finding a suitable parent nsIWidget, then
   637   // getting rid of aForceUseIWidgetParent.
   638   if (aParentWidget) {
   639     // XXX: using aForceUseIWidgetParent=true to preserve previous
   640     // semantics.  It's not clear that it's actually needed.
   641     mWindow = aParentWidget->CreateChild(trect, dx, aWidgetInitData,
   642                                          true).take();
   643   }
   644   else {
   645     nsIWidget* nearestParent = GetParent() ? GetParent()->GetNearestWidget(nullptr)
   646                                            : nullptr;
   647     if (!nearestParent) {
   648       // Without a parent, we can't make a popup.  This can happen
   649       // when printing
   650       return NS_ERROR_FAILURE;
   651     }
   653     mWindow =
   654       nearestParent->CreateChild(trect, dx, aWidgetInitData).take();
   655   }
   656   if (!mWindow) {
   657     return NS_ERROR_FAILURE;
   658   }
   660   InitializeWindow(aEnableDragDrop, aResetVisibility);
   662   return NS_OK;
   663 }
   665 void
   666 nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility)
   667 {
   668   NS_ABORT_IF_FALSE(mWindow, "Must have a window to initialize");
   670   mWindow->SetWidgetListener(this);
   672   if (aEnableDragDrop) {
   673     mWindow->EnableDragDrop(true);
   674   }
   676   // propagate the z-index to the widget.
   677   UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
   679   //make sure visibility state is accurate
   681   if (aResetVisibility) {
   682     SetVisibility(GetVisibility());
   683   }
   684 }
   686 // Attach to a top level widget and start receiving mirrored events.
   687 nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget)
   688 {
   689   NS_PRECONDITION(nullptr != aWidget, "null widget ptr");
   690   /// XXXjimm This is a temporary workaround to an issue w/document
   691   // viewer (bug 513162).
   692   nsIWidgetListener* listener = aWidget->GetAttachedWidgetListener();
   693   if (listener) {
   694     nsView *oldView = listener->GetView();
   695     if (oldView) {
   696       oldView->DetachFromTopLevelWidget();
   697     }
   698   }
   700   nsRefPtr<nsDeviceContext> dx = mViewManager->GetDeviceContext();
   702   // Note, the previous device context will be released. Detaching
   703   // will not restore the old one.
   704   nsresult rv = aWidget->AttachViewToTopLevel(!nsIWidget::UsePuppetWidgets(), dx);
   705   if (NS_FAILED(rv))
   706     return rv;
   708   mWindow = aWidget;
   709   NS_ADDREF(mWindow);
   711   mWindow->SetAttachedWidgetListener(this);
   712   mWindow->EnableDragDrop(true);
   713   mWidgetIsTopLevel = true;
   715   // Refresh the view bounds
   716   CalcWidgetBounds(mWindow->WindowType());
   718   return NS_OK;
   719 }
   721 // Detach this view from an attached widget. 
   722 nsresult nsView::DetachFromTopLevelWidget()
   723 {
   724   NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!");
   725   NS_PRECONDITION(mWindow, "null mWindow for DetachFromTopLevelWidget!");
   727   mWindow->SetAttachedWidgetListener(nullptr);
   728   NS_RELEASE(mWindow);
   730   mWidgetIsTopLevel = false;
   732   return NS_OK;
   733 }
   735 void nsView::SetZIndex(bool aAuto, int32_t aZIndex)
   736 {
   737   bool oldIsAuto = GetZIndexIsAuto();
   738   mVFlags = (mVFlags & ~NS_VIEW_FLAG_AUTO_ZINDEX) | (aAuto ? NS_VIEW_FLAG_AUTO_ZINDEX : 0);
   739   mZIndex = aZIndex;
   741   if (HasWidget() || !oldIsAuto || !aAuto) {
   742     UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
   743   }
   744 }
   746 void nsView::AssertNoWindow()
   747 {
   748   // XXX: it would be nice to make this a strong assert
   749   if (MOZ_UNLIKELY(mWindow)) {
   750     NS_ERROR("We already have a window for this view? BAD");
   751     mWindow->SetWidgetListener(nullptr);
   752     mWindow->Destroy();
   753     NS_RELEASE(mWindow);
   754   }
   755 }
   757 //
   758 // internal window creation functions
   759 //
   760 void nsView::AttachWidgetEventHandler(nsIWidget* aWidget)
   761 {
   762 #ifdef DEBUG
   763   NS_ASSERTION(!aWidget->GetWidgetListener(), "Already have a widget listener");
   764 #endif
   766   aWidget->SetWidgetListener(this);
   767 }
   769 void nsView::DetachWidgetEventHandler(nsIWidget* aWidget)
   770 {
   771   NS_ASSERTION(!aWidget->GetWidgetListener() ||
   772                aWidget->GetWidgetListener()->GetView() == this, "Wrong view");
   773   aWidget->SetWidgetListener(nullptr);
   774 }
   776 #ifdef DEBUG
   777 void nsView::List(FILE* out, int32_t aIndent) const
   778 {
   779   int32_t i;
   780   for (i = aIndent; --i >= 0; ) fputs("  ", out);
   781   fprintf(out, "%p ", (void*)this);
   782   if (nullptr != mWindow) {
   783     nscoord p2a = mViewManager->AppUnitsPerDevPixel();
   784     nsIntRect rect;
   785     mWindow->GetClientBounds(rect);
   786     nsRect windowBounds = rect.ToAppUnits(p2a);
   787     mWindow->GetBounds(rect);
   788     nsRect nonclientBounds = rect.ToAppUnits(p2a);
   789     nsrefcnt widgetRefCnt = mWindow->AddRef() - 1;
   790     mWindow->Release();
   791     int32_t Z = mWindow->GetZIndex();
   792     fprintf(out, "(widget=%p[%" PRIuPTR "] z=%d pos={%d,%d,%d,%d}) ",
   793             (void*)mWindow, widgetRefCnt, Z,
   794             nonclientBounds.x, nonclientBounds.y,
   795             windowBounds.width, windowBounds.height);
   796   }
   797   nsRect brect = GetBounds();
   798   fprintf(out, "{%d,%d,%d,%d}",
   799           brect.x, brect.y, brect.width, brect.height);
   800   fprintf(out, " z=%d vis=%d frame=%p <\n",
   801           mZIndex, mVis, static_cast<void*>(mFrame));
   802   for (nsView* kid = mFirstChild; kid; kid = kid->GetNextSibling()) {
   803     NS_ASSERTION(kid->GetParent() == this, "incorrect parent");
   804     kid->List(out, aIndent + 1);
   805   }
   806   for (i = aIndent; --i >= 0; ) fputs("  ", out);
   807   fputs(">\n", out);
   808 }
   809 #endif // DEBUG
   811 nsPoint nsView::GetOffsetTo(const nsView* aOther) const
   812 {
   813   return GetOffsetTo(aOther, GetViewManager()->AppUnitsPerDevPixel());
   814 }
   816 nsPoint nsView::GetOffsetTo(const nsView* aOther, const int32_t aAPD) const
   817 {
   818   NS_ABORT_IF_FALSE(GetParent() || !aOther || aOther->GetParent() ||
   819                     this == aOther, "caller of (outer) GetOffsetTo must not "
   820                     "pass unrelated views");
   821   // We accumulate the final result in offset
   822   nsPoint offset(0, 0);
   823   // The offset currently accumulated at the current APD
   824   nsPoint docOffset(0, 0);
   825   const nsView* v = this;
   826   nsViewManager* currVM = v->GetViewManager();
   827   int32_t currAPD = currVM->AppUnitsPerDevPixel();
   828   const nsView* root = nullptr;
   829   for ( ; v != aOther && v; root = v, v = v->GetParent()) {
   830     nsViewManager* newVM = v->GetViewManager();
   831     if (newVM != currVM) {
   832       int32_t newAPD = newVM->AppUnitsPerDevPixel();
   833       if (newAPD != currAPD) {
   834         offset += docOffset.ConvertAppUnits(currAPD, aAPD);
   835         docOffset.x = docOffset.y = 0;
   836         currAPD = newAPD;
   837       }
   838       currVM = newVM;
   839     }
   840     docOffset += v->GetPosition();
   841   }
   842   offset += docOffset.ConvertAppUnits(currAPD, aAPD);
   844   if (v != aOther) {
   845     // Looks like aOther wasn't an ancestor of |this|.  So now we have
   846     // the root-VM-relative position of |this| in |offset|.  Get the
   847     // root-VM-relative position of aOther and subtract it.
   848     nsPoint negOffset = aOther->GetOffsetTo(root, aAPD);
   849     offset -= negOffset;
   850   }
   852   return offset;
   853 }
   855 nsPoint nsView::GetOffsetToWidget(nsIWidget* aWidget) const
   856 {
   857   nsPoint pt;
   858   // Get the view for widget
   859   nsView* widgetView = GetViewFor(aWidget);
   860   if (!widgetView) {
   861     return pt;
   862   }
   864   // Get the offset to the widget view in the widget view's APD
   865   // We get the offset in the widget view's APD first and then convert to our
   866   // APD afterwards so that we can include the widget view's ViewToWidgetOffset
   867   // in the sum in its native APD, and then convert the whole thing to our APD
   868   // so that we don't have to convert the APD of the relatively small
   869   // ViewToWidgetOffset by itself with a potentially large relative rounding
   870   // error.
   871   pt = -widgetView->GetOffsetTo(this);
   872   // Add in the offset to the widget.
   873   pt += widgetView->ViewToWidgetOffset();
   875   // Convert to our appunits.
   876   int32_t widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel();
   877   int32_t ourAPD = GetViewManager()->AppUnitsPerDevPixel();
   878   pt = pt.ConvertAppUnits(widgetAPD, ourAPD);
   879   return pt;
   880 }
   882 nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const
   883 {
   884   return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel());
   885 }
   887 nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset, const int32_t aAPD) const
   888 {
   889   // aOffset is based on the view's position, which ignores any chrome on
   890   // attached parent widgets.
   892   // We accumulate the final result in pt
   893   nsPoint pt(0, 0);
   894   // The offset currently accumulated at the current APD
   895   nsPoint docPt(0,0);
   896   const nsView* v = this;
   897   nsViewManager* currVM = v->GetViewManager();
   898   int32_t currAPD = currVM->AppUnitsPerDevPixel();
   899   for ( ; v && !v->HasWidget(); v = v->GetParent()) {
   900     nsViewManager* newVM = v->GetViewManager();
   901     if (newVM != currVM) {
   902       int32_t newAPD = newVM->AppUnitsPerDevPixel();
   903       if (newAPD != currAPD) {
   904         pt += docPt.ConvertAppUnits(currAPD, aAPD);
   905         docPt.x = docPt.y = 0;
   906         currAPD = newAPD;
   907       }
   908       currVM = newVM;
   909     }
   910     docPt += v->GetPosition();
   911   }
   912   if (!v) {
   913     if (aOffset) {
   914       pt += docPt.ConvertAppUnits(currAPD, aAPD);
   915       *aOffset = pt;
   916     }
   917     return nullptr;
   918   }
   920   // pt is now the offset from v's origin to this view's origin.
   921   // We add the ViewToWidgetOffset to get the offset to the widget.
   922   if (aOffset) {
   923     docPt += v->ViewToWidgetOffset();
   924     pt += docPt.ConvertAppUnits(currAPD, aAPD);
   925     *aOffset = pt;
   926   }
   927   return v->GetWidget();
   928 }
   930 bool nsView::IsRoot() const
   931 {
   932   NS_ASSERTION(mViewManager != nullptr," View manager is null in nsView::IsRoot()");
   933   return mViewManager->GetRootView() == this;
   934 }
   936 nsRect
   937 nsView::GetBoundsInParentUnits() const
   938 {
   939   nsView* parent = GetParent();
   940   nsViewManager* VM = GetViewManager();
   941   if (this != VM->GetRootView() || !parent) {
   942     return mDimBounds;
   943   }
   944   int32_t ourAPD = VM->AppUnitsPerDevPixel();
   945   int32_t parentAPD = parent->GetViewManager()->AppUnitsPerDevPixel();
   946   return mDimBounds.ConvertAppUnitsRoundOut(ourAPD, parentAPD);
   947 }
   949 nsPoint
   950 nsView::ConvertFromParentCoords(nsPoint aPt) const
   951 {
   952   const nsView* parent = GetParent();
   953   if (parent) {
   954     aPt = aPt.ConvertAppUnits(parent->GetViewManager()->AppUnitsPerDevPixel(),
   955                               GetViewManager()->AppUnitsPerDevPixel());
   956   }
   957   aPt -= GetPosition();
   958   return aPt;
   959 }
   961 static bool
   962 IsPopupWidget(nsIWidget* aWidget)
   963 {
   964   return (aWidget->WindowType() == eWindowType_popup);
   965 }
   967 nsIPresShell*
   968 nsView::GetPresShell()
   969 {
   970   return GetViewManager()->GetPresShell();
   971 }
   973 bool
   974 nsView::WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y)
   975 {
   976   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
   977   if (pm && IsPopupWidget(aWidget)) {
   978     pm->PopupMoved(mFrame, nsIntPoint(x, y));
   979     return true;
   980   }
   982   return false;
   983 }
   985 bool
   986 nsView::WindowResized(nsIWidget* aWidget, int32_t aWidth, int32_t aHeight)
   987 {
   988   // The root view may not be set if this is the resize associated with
   989   // window creation
   990   SetForcedRepaint(true);
   991   if (this == mViewManager->GetRootView()) {
   992     nsRefPtr<nsDeviceContext> devContext = mViewManager->GetDeviceContext();
   993     // ensure DPI is up-to-date, in case of window being opened and sized
   994     // on a non-default-dpi display (bug 829963)
   995     devContext->CheckDPIChange();
   996     int32_t p2a = devContext->AppUnitsPerDevPixel();
   997     mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth, p2a),
   998                                       NSIntPixelsToAppUnits(aHeight, p2a));
  1000     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1001     if (pm) {
  1002       nsIPresShell* presShell = mViewManager->GetPresShell();
  1003       if (presShell && presShell->GetDocument()) {
  1004         pm->AdjustPopupsOnWindowChange(presShell);
  1008     return true;
  1010   else if (IsPopupWidget(aWidget)) {
  1011     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1012     if (pm) {
  1013       pm->PopupResized(mFrame, nsIntSize(aWidth, aHeight));
  1014       return true;
  1018   return false;
  1021 bool
  1022 nsView::RequestWindowClose(nsIWidget* aWidget)
  1024   if (mFrame && IsPopupWidget(aWidget) &&
  1025       mFrame->GetType() == nsGkAtoms::menuPopupFrame) {
  1026     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  1027     if (pm) {
  1028       pm->HidePopup(mFrame->GetContent(), false, true, false, false);
  1029       return true;
  1033   return false;
  1036 void
  1037 nsView::WillPaintWindow(nsIWidget* aWidget)
  1039   nsRefPtr<nsViewManager> vm = mViewManager;
  1040   vm->WillPaintWindow(aWidget);
  1043 bool
  1044 nsView::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion)
  1046   NS_ASSERTION(this == nsView::GetViewFor(aWidget), "wrong view for widget?");
  1048   nsRefPtr<nsViewManager> vm = mViewManager;
  1049   bool result = vm->PaintWindow(aWidget, aRegion);
  1050   return result;
  1053 void
  1054 nsView::DidPaintWindow()
  1056   nsRefPtr<nsViewManager> vm = mViewManager;
  1057   vm->DidPaintWindow();
  1060 void
  1061 nsView::DidCompositeWindow()
  1063   nsIPresShell* presShell = mViewManager->GetPresShell();
  1064   if (presShell) {
  1065     nsAutoScriptBlocker scriptBlocker;
  1066     presShell->GetPresContext()->GetDisplayRootPresContext()->GetRootPresContext()->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE);
  1070 void
  1071 nsView::RequestRepaint()
  1073   nsIPresShell* presShell = mViewManager->GetPresShell();
  1074   if (presShell) {
  1075     presShell->ScheduleViewManagerFlush();
  1079 nsEventStatus
  1080 nsView::HandleEvent(WidgetGUIEvent* aEvent,
  1081                     bool aUseAttachedEvents)
  1083   NS_PRECONDITION(nullptr != aEvent->widget, "null widget ptr");
  1085   nsEventStatus result = nsEventStatus_eIgnore;
  1086   nsView* view;
  1087   if (aUseAttachedEvents) {
  1088     nsIWidgetListener* listener = aEvent->widget->GetAttachedWidgetListener();
  1089     view = listener ? listener->GetView() : nullptr;
  1091   else {
  1092     view = GetViewFor(aEvent->widget);
  1095   if (view) {
  1096     nsRefPtr<nsViewManager> vm = view->GetViewManager();
  1097     vm->DispatchEvent(aEvent, view, &result);
  1100   return result;

mercurial