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/. */
8 #include "mozilla/Attributes.h"
9 #include "mozilla/BasicEvents.h"
10 #include "mozilla/DebugOnly.h"
11 #include "mozilla/Likely.h"
12 #include "mozilla/Poison.h"
13 #include "nsIWidget.h"
14 #include "nsViewManager.h"
16 #include "nsPresArena.h"
17 #include "nsXULPopupManager.h"
18 #include "nsIWidgetListener.h"
20 using namespace mozilla
;
22 nsView::nsView(nsViewManager
* aViewManager
, nsViewVisibility aVisibility
)
24 MOZ_COUNT_CTOR(nsView
);
27 // Views should be transparent by default. Not being transparent is
28 // a promise that the view will paint all its pixels opaquely. Views
29 // should make this promise explicitly by calling
30 // SetViewContentTransparency.
32 mViewManager
= aViewManager
;
33 mDirtyRegion
= nullptr;
34 mWidgetIsTopLevel
= false;
37 void nsView::DropMouseGrabbing()
39 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
41 presShell
->ClearMouseCaptureOnView(this);
46 MOZ_COUNT_DTOR(nsView
);
48 while (GetFirstChild())
50 nsView
* child
= GetFirstChild();
51 if (child
->GetViewManager() == mViewManager
) {
54 // just unhook it. Someone else will want to destroy this.
63 nsView
*rootView
= mViewManager
->GetRootView();
67 // Root views can have parents!
70 mViewManager
->RemoveChild(this);
75 // Inform the view manager that the root view has gone away...
76 mViewManager
->SetRootView(nullptr);
81 mParent
->RemoveChild(this);
84 mViewManager
= nullptr;
88 mParent
->RemoveChild(this);
91 // Destroy and release the widget
97 class DestroyWidgetRunnable
: public nsRunnable
{
101 explicit DestroyWidgetRunnable(nsIWidget
* aWidget
) : mWidget(aWidget
) {}
104 nsCOMPtr
<nsIWidget
> mWidget
;
107 NS_IMETHODIMP
DestroyWidgetRunnable::Run()
115 void nsView::DestroyWidget()
119 // If we are not attached to a base window, we're going to tear down our
120 // widget here. However, if we're attached to somebody elses widget, we
121 // want to leave the widget alone: don't reset the client data or call
122 // Destroy. Just clear our event view ptr and free our reference to it.
123 if (mWidgetIsTopLevel
) {
124 mWindow
->SetAttachedWidgetListener(nullptr);
127 mWindow
->SetWidgetListener(nullptr);
129 nsCOMPtr
<nsIRunnable
> widgetDestroyer
=
130 new DestroyWidgetRunnable(mWindow
);
132 NS_DispatchToMainThread(widgetDestroyer
);
139 nsView
* nsView::GetViewFor(nsIWidget
* aWidget
)
141 NS_PRECONDITION(nullptr != aWidget
, "null widget ptr");
143 nsIWidgetListener
* listener
= aWidget
->GetWidgetListener();
145 nsView
* view
= listener
->GetView();
150 listener
= aWidget
->GetAttachedWidgetListener();
151 return listener
? listener
->GetView() : nullptr;
154 void nsView::Destroy()
157 mozWritePoison(this, sizeof(*this));
158 nsView::operator delete(this);
161 void nsView::SetPosition(nscoord aX
, nscoord aY
)
163 mDimBounds
.x
+= aX
- mPosX
;
164 mDimBounds
.y
+= aY
- mPosY
;
168 NS_ASSERTION(GetParent() || (aX
== 0 && aY
== 0),
169 "Don't try to move the root widget to something non-zero");
171 ResetWidgetBounds(true, false);
174 void nsView::ResetWidgetBounds(bool aRecurse
, bool aForceSync
)
178 // Don't change widget geometry synchronously, since that can
179 // cause synchronous painting.
180 mViewManager
->PostPendingUpdate();
182 DoResetWidgetBounds(false, true);
188 // reposition any widgets under this view
189 for (nsView
* v
= GetFirstChild(); v
; v
= v
->GetNextSibling()) {
190 v
->ResetWidgetBounds(true, aForceSync
);
195 bool nsView::IsEffectivelyVisible()
197 for (nsView
* v
= this; v
; v
= v
->mParent
) {
198 if (v
->GetVisibility() == nsViewVisibility_kHide
)
204 nsIntRect
nsView::CalcWidgetBounds(nsWindowType aType
)
206 int32_t p2a
= mViewManager
->AppUnitsPerDevPixel();
208 nsRect
viewBounds(mDimBounds
);
210 nsView
* parent
= GetParent();
211 nsIWidget
* parentWidget
= nullptr;
214 parentWidget
= parent
->GetNearestWidget(&offset
, p2a
);
215 // make viewBounds be relative to the parent widget, in appunits
216 viewBounds
+= offset
;
218 if (parentWidget
&& aType
== eWindowType_popup
&&
219 IsEffectivelyVisible()) {
220 // put offset into screen coordinates. (based on client area origin)
221 nsIntPoint screenPoint
= parentWidget
->WidgetToScreenOffset();
222 viewBounds
+= nsPoint(NSIntPixelsToAppUnits(screenPoint
.x
, p2a
),
223 NSIntPixelsToAppUnits(screenPoint
.y
, p2a
));
227 // Compute widget bounds in device pixels
228 nsIntRect newBounds
= viewBounds
.ToNearestPixels(p2a
);
231 // cocoa rounds widget coordinates to the nearest global "display pixel"
232 // integer value. So we avoid fractional display pixel values by rounding
233 // to the nearest value that won't yield a fractional display pixel.
234 nsIWidget
* widget
= parentWidget
? parentWidget
: mWindow
;
236 if (aType
== eWindowType_popup
&& widget
&&
237 ((round
= widget
->RoundsWidgetCoordinatesTo()) > 1)) {
238 nsIntSize pixelRoundedSize
= newBounds
.Size();
239 // round the top left and bottom right to the nearest round pixel
240 newBounds
.x
= NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds
.x
, p2a
) / round
) * round
;
241 newBounds
.y
= NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds
.y
, p2a
) / round
) * round
;
243 NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds
.XMost(), p2a
) / round
) * round
- newBounds
.x
;
245 NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds
.YMost(), p2a
) / round
) * round
- newBounds
.y
;
246 // but if that makes the widget larger then our frame may not paint the
247 // extra pixels, so reduce the size to the nearest round value
248 if (newBounds
.width
> pixelRoundedSize
.width
) {
249 newBounds
.width
-= round
;
251 if (newBounds
.height
> pixelRoundedSize
.height
) {
252 newBounds
.height
-= round
;
257 // Compute where the top-left of our widget ended up relative to the parent
258 // widget, in appunits.
259 nsPoint
roundedOffset(NSIntPixelsToAppUnits(newBounds
.x
, p2a
),
260 NSIntPixelsToAppUnits(newBounds
.y
, p2a
));
262 // mViewToWidgetOffset is added to coordinates relative to the view origin
263 // to get coordinates relative to the widget.
264 // The view origin, relative to the parent widget, is at
265 // (mPosX,mPosY) - mDimBounds.TopLeft() + viewBounds.TopLeft().
266 // Our widget, relative to the parent widget, is roundedOffset.
267 mViewToWidgetOffset
= nsPoint(mPosX
, mPosY
)
268 - mDimBounds
.TopLeft() + viewBounds
.TopLeft() - roundedOffset
;
273 void nsView::DoResetWidgetBounds(bool aMoveOnly
,
274 bool aInvalidateChangedSize
) {
275 // The geometry of a root view's widget is controlled externally,
276 // NOT by sizing or positioning the view
277 if (mViewManager
->GetRootView() == this) {
281 NS_PRECONDITION(mWindow
, "Why was this called??");
283 // Hold this ref to make sure it stays alive.
284 nsCOMPtr
<nsIWidget
> widget
= mWindow
;
286 // Stash a copy of these and use them so we can handle this being deleted (say
287 // from sync painting/flushing from Show/Move/Resize on the widget).
289 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
292 widget
->GetWindowType(type
);
295 widget
->GetClientBounds(curBounds
);
296 bool invisiblePopup
= type
== eWindowType_popup
&&
297 ((curBounds
.IsEmpty() && mDimBounds
.IsEmpty()) ||
298 mVis
== nsViewVisibility_kHide
);
300 if (invisiblePopup
) {
301 // We're going to hit the early exit below, avoid calling CalcWidgetBounds.
303 newBounds
= CalcWidgetBounds(type
);
306 bool curVisibility
= widget
->IsVisible();
307 bool newVisibility
= IsEffectivelyVisible();
308 if (curVisibility
&& !newVisibility
) {
312 if (invisiblePopup
) {
313 // Don't manipulate empty or hidden popup widgets. For example there's no
314 // point moving hidden comboboxes around, or doing X server roundtrips
315 // to compute their true screen position. This could mean that WidgetToScreen
316 // operations on these widgets don't return up-to-date values, but popup
317 // positions aren't reliable anyway because of correction to be on or off-screen.
321 bool changedPos
= curBounds
.TopLeft() != newBounds
.TopLeft();
322 bool changedSize
= curBounds
.Size() != newBounds
.Size();
324 // Child views are never attached to top level widgets, this is safe.
326 // Coordinates are converted to display pixels for window Move/Resize APIs,
327 // because of the potential for device-pixel coordinate spaces for mixed
328 // hidpi/lodpi screens to overlap each other and result in bad placement
332 // Bug 861270: for correct widget manipulation at arbitrary scale factors,
333 // prefer to base scaling on widget->GetDefaultScale(). But only do this if
334 // it matches the view manager's device context scale after allowing for the
335 // quantization to app units, because of OS X multiscreen issues (where the
336 // only two scales are 1.0 or 2.0, and so the quantization doesn't actually
337 // cause problems anyhow).
338 // In the case of a mismatch, fall back to scaling based on the dev context's
339 // unscaledAppUnitsPerDevPixel value. On platforms where the device-pixel
340 // scale is uniform across all displays (currently all except OS X), we'll
341 // always use the precise value from mWindow->GetDefaultScale here.
342 CSSToLayoutDeviceScale scale
= widget
->GetDefaultScale();
343 if (NSToIntRound(60.0 / scale
.scale
) == dx
->UnscaledAppUnitsPerDevPixel()) {
344 invScale
= 1.0 / scale
.scale
;
346 invScale
= dx
->UnscaledAppUnitsPerDevPixel() / 60.0;
350 if (changedSize
&& !aMoveOnly
) {
351 widget
->ResizeClient(newBounds
.x
* invScale
,
352 newBounds
.y
* invScale
,
353 newBounds
.width
* invScale
,
354 newBounds
.height
* invScale
,
355 aInvalidateChangedSize
);
357 widget
->MoveClient(newBounds
.x
* invScale
,
358 newBounds
.y
* invScale
);
361 if (changedSize
&& !aMoveOnly
) {
362 widget
->ResizeClient(newBounds
.width
* invScale
,
363 newBounds
.height
* invScale
,
364 aInvalidateChangedSize
);
365 } // else do nothing!
368 if (!curVisibility
&& newVisibility
) {
373 void nsView::SetDimensions(const nsRect
& aRect
, bool aPaint
, bool aResizeWidget
)
376 dims
.MoveBy(mPosX
, mPosY
);
378 // Don't use nsRect's operator== here, since it returns true when
379 // both rects are empty even if they have different widths and we
380 // have cases where that sort of thing matters to us.
381 if (mDimBounds
.TopLeft() == dims
.TopLeft() &&
382 mDimBounds
.Size() == dims
.Size()) {
389 ResetWidgetBounds(false, false);
393 void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible
)
395 if (!aEffectivelyVisible
)
400 SetForcedRepaint(true);
402 if (nullptr != mWindow
)
404 ResetWidgetBounds(false, false);
407 for (nsView
* child
= mFirstChild
; child
; child
= child
->mNextSibling
) {
408 if (child
->mVis
== nsViewVisibility_kHide
) {
409 // It was effectively hidden and still is
412 // Our child is visible if we are
413 child
->NotifyEffectiveVisibilityChanged(aEffectivelyVisible
);
417 void nsView::SetVisibility(nsViewVisibility aVisibility
)
420 NotifyEffectiveVisibilityChanged(IsEffectivelyVisible());
423 void nsView::SetFloating(bool aFloatingView
)
426 mVFlags
|= NS_VIEW_FLAG_FLOATING
;
428 mVFlags
&= ~NS_VIEW_FLAG_FLOATING
;
431 void nsView::InvalidateHierarchy(nsViewManager
*aViewManagerParent
)
433 if (mViewManager
->GetRootView() == this)
434 mViewManager
->InvalidateHierarchy();
436 for (nsView
*child
= mFirstChild
; child
; child
= child
->GetNextSibling())
437 child
->InvalidateHierarchy(aViewManagerParent
);
440 void nsView::InsertChild(nsView
*aChild
, nsView
*aSibling
)
442 NS_PRECONDITION(nullptr != aChild
, "null ptr");
444 if (nullptr != aChild
)
446 if (nullptr != aSibling
)
449 NS_ASSERTION(aSibling
->GetParent() == this, "tried to insert view with invalid sibling");
451 //insert after sibling
452 aChild
->SetNextSibling(aSibling
->GetNextSibling());
453 aSibling
->SetNextSibling(aChild
);
457 aChild
->SetNextSibling(mFirstChild
);
458 mFirstChild
= aChild
;
460 aChild
->SetParent(this);
462 // If we just inserted a root view, then update the RootViewManager
463 // on all view managers in the new subtree.
465 nsViewManager
*vm
= aChild
->GetViewManager();
466 if (vm
->GetRootView() == aChild
)
468 aChild
->InvalidateHierarchy(nullptr); // don't care about releasing grabs
473 void nsView::RemoveChild(nsView
*child
)
475 NS_PRECONDITION(nullptr != child
, "null ptr");
477 if (nullptr != child
)
479 nsView
* prevKid
= nullptr;
480 nsView
* kid
= mFirstChild
;
481 DebugOnly
<bool> found
= false;
482 while (nullptr != kid
) {
484 if (nullptr != prevKid
) {
485 prevKid
->SetNextSibling(kid
->GetNextSibling());
487 mFirstChild
= kid
->GetNextSibling();
489 child
->SetParent(nullptr);
494 kid
= kid
->GetNextSibling();
496 NS_ASSERTION(found
, "tried to remove non child");
498 // If we just removed a root view, then update the RootViewManager
499 // on all view managers in the removed subtree.
501 nsViewManager
*vm
= child
->GetViewManager();
502 if (vm
->GetRootView() == child
)
504 child
->InvalidateHierarchy(GetViewManager());
509 // Native widgets ultimately just can't deal with the awesome power of
510 // CSS2 z-index. However, we set the z-index on the widget anyway
511 // because in many simple common cases the widgets do end up in the
512 // right order. We set each widget's z-index to the z-index of the
513 // nearest ancestor that has non-auto z-index.
514 static void UpdateNativeWidgetZIndexes(nsView
* aView
, int32_t aZIndex
)
516 if (aView
->HasWidget()) {
517 nsIWidget
* widget
= aView
->GetWidget();
519 widget
->GetZIndex(&curZ
);
520 if (curZ
!= aZIndex
) {
521 widget
->SetZIndex(aZIndex
);
524 for (nsView
* v
= aView
->GetFirstChild(); v
; v
= v
->GetNextSibling()) {
525 if (v
->GetZIndexIsAuto()) {
526 UpdateNativeWidgetZIndexes(v
, aZIndex
);
532 static int32_t FindNonAutoZIndex(nsView
* aView
)
535 if (!aView
->GetZIndexIsAuto()) {
536 return aView
->GetZIndex();
538 aView
= aView
->GetParent();
543 struct DefaultWidgetInitData
: public nsWidgetInitData
{
544 DefaultWidgetInitData() : nsWidgetInitData()
546 mWindowType
= eWindowType_child
;
552 nsresult
nsView::CreateWidget(nsWidgetInitData
*aWidgetInitData
,
553 bool aEnableDragDrop
,
554 bool aResetVisibility
)
557 NS_ABORT_IF_FALSE(!aWidgetInitData
||
558 aWidgetInitData
->mWindowType
!= eWindowType_popup
,
559 "Use CreateWidgetForPopup");
561 DefaultWidgetInitData defaultInitData
;
562 bool initDataPassedIn
= !!aWidgetInitData
;
563 aWidgetInitData
= aWidgetInitData
? aWidgetInitData
: &defaultInitData
;
564 defaultInitData
.mListenForResizes
=
565 (!initDataPassedIn
&& GetParent() &&
566 GetParent()->GetViewManager() != mViewManager
);
568 nsIntRect trect
= CalcWidgetBounds(aWidgetInitData
->mWindowType
);
570 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
572 nsIWidget
* parentWidget
=
573 GetParent() ? GetParent()->GetNearestWidget(nullptr) : nullptr;
575 NS_ERROR("nsView::CreateWidget without suitable parent widget??");
576 return NS_ERROR_FAILURE
;
579 // XXX: using aForceUseIWidgetParent=true to preserve previous
580 // semantics. It's not clear that it's actually needed.
581 mWindow
= parentWidget
->CreateChild(trect
, dx
, aWidgetInitData
,
584 return NS_ERROR_FAILURE
;
587 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
592 nsresult
nsView::CreateWidgetForParent(nsIWidget
* aParentWidget
,
593 nsWidgetInitData
*aWidgetInitData
,
594 bool aEnableDragDrop
,
595 bool aResetVisibility
)
598 NS_ABORT_IF_FALSE(!aWidgetInitData
||
599 aWidgetInitData
->mWindowType
!= eWindowType_popup
,
600 "Use CreateWidgetForPopup");
601 NS_ABORT_IF_FALSE(aParentWidget
, "Parent widget required");
603 DefaultWidgetInitData defaultInitData
;
604 aWidgetInitData
= aWidgetInitData
? aWidgetInitData
: &defaultInitData
;
606 nsIntRect trect
= CalcWidgetBounds(aWidgetInitData
->mWindowType
);
608 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
611 aParentWidget
->CreateChild(trect
, dx
, aWidgetInitData
).get();
613 return NS_ERROR_FAILURE
;
616 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
621 nsresult
nsView::CreateWidgetForPopup(nsWidgetInitData
*aWidgetInitData
,
622 nsIWidget
* aParentWidget
,
623 bool aEnableDragDrop
,
624 bool aResetVisibility
)
627 NS_ABORT_IF_FALSE(aWidgetInitData
, "Widget init data required");
628 NS_ABORT_IF_FALSE(aWidgetInitData
->mWindowType
== eWindowType_popup
,
629 "Use one of the other CreateWidget methods");
631 nsIntRect trect
= CalcWidgetBounds(aWidgetInitData
->mWindowType
);
633 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
635 // XXX/cjones: having these two separate creation cases seems ... um
636 // ... unnecessary, but it's the way the old code did it. Please
637 // unify them by first finding a suitable parent nsIWidget, then
638 // getting rid of aForceUseIWidgetParent.
640 // XXX: using aForceUseIWidgetParent=true to preserve previous
641 // semantics. It's not clear that it's actually needed.
642 mWindow
= aParentWidget
->CreateChild(trect
, dx
, aWidgetInitData
,
646 nsIWidget
* nearestParent
= GetParent() ? GetParent()->GetNearestWidget(nullptr)
648 if (!nearestParent
) {
649 // Without a parent, we can't make a popup. This can happen
651 return NS_ERROR_FAILURE
;
655 nearestParent
->CreateChild(trect
, dx
, aWidgetInitData
).get();
658 return NS_ERROR_FAILURE
;
661 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
667 nsView::InitializeWindow(bool aEnableDragDrop
, bool aResetVisibility
)
669 NS_ABORT_IF_FALSE(mWindow
, "Must have a window to initialize");
671 mWindow
->SetWidgetListener(this);
673 if (aEnableDragDrop
) {
674 mWindow
->EnableDragDrop(true);
677 // propagate the z-index to the widget.
678 UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
680 //make sure visibility state is accurate
682 if (aResetVisibility
) {
683 SetVisibility(GetVisibility());
687 // Attach to a top level widget and start receiving mirrored events.
688 nsresult
nsView::AttachToTopLevelWidget(nsIWidget
* aWidget
)
690 NS_PRECONDITION(nullptr != aWidget
, "null widget ptr");
691 /// XXXjimm This is a temporary workaround to an issue w/document
692 // viewer (bug 513162).
693 nsIWidgetListener
* listener
= aWidget
->GetAttachedWidgetListener();
695 nsView
*oldView
= listener
->GetView();
697 oldView
->DetachFromTopLevelWidget();
701 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
703 // Note, the previous device context will be released. Detaching
704 // will not restore the old one.
705 nsresult rv
= aWidget
->AttachViewToTopLevel(!nsIWidget::UsePuppetWidgets(), dx
);
712 mWindow
->SetAttachedWidgetListener(this);
713 mWindow
->EnableDragDrop(true);
714 mWidgetIsTopLevel
= true;
716 // Refresh the view bounds
718 mWindow
->GetWindowType(type
);
719 CalcWidgetBounds(type
);
724 // Detach this view from an attached widget.
725 nsresult
nsView::DetachFromTopLevelWidget()
727 NS_PRECONDITION(mWidgetIsTopLevel
, "Not attached currently!");
728 NS_PRECONDITION(mWindow
, "null mWindow for DetachFromTopLevelWidget!");
730 mWindow
->SetAttachedWidgetListener(nullptr);
733 mWidgetIsTopLevel
= false;
738 void nsView::SetZIndex(bool aAuto
, int32_t aZIndex
)
740 bool oldIsAuto
= GetZIndexIsAuto();
741 mVFlags
= (mVFlags
& ~NS_VIEW_FLAG_AUTO_ZINDEX
) | (aAuto
? NS_VIEW_FLAG_AUTO_ZINDEX
: 0);
744 if (HasWidget() || !oldIsAuto
|| !aAuto
) {
745 UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
749 void nsView::AssertNoWindow()
751 // XXX: it would be nice to make this a strong assert
752 if (MOZ_UNLIKELY(mWindow
)) {
753 NS_ERROR("We already have a window for this view? BAD");
754 mWindow
->SetWidgetListener(nullptr);
761 // internal window creation functions
763 void nsView::AttachWidgetEventHandler(nsIWidget
* aWidget
)
766 NS_ASSERTION(!aWidget
->GetWidgetListener(), "Already have a widget listener");
769 aWidget
->SetWidgetListener(this);
772 void nsView::DetachWidgetEventHandler(nsIWidget
* aWidget
)
774 NS_ASSERTION(!aWidget
->GetWidgetListener() ||
775 aWidget
->GetWidgetListener()->GetView() == this, "Wrong view");
776 aWidget
->SetWidgetListener(nullptr);
780 void nsView::List(FILE* out
, int32_t aIndent
) const
783 for (i
= aIndent
; --i
>= 0; ) fputs(" ", out
);
784 fprintf(out
, "%p ", (void*)this);
785 if (nullptr != mWindow
) {
786 nscoord p2a
= mViewManager
->AppUnitsPerDevPixel();
788 mWindow
->GetClientBounds(rect
);
789 nsRect windowBounds
= rect
.ToAppUnits(p2a
);
790 mWindow
->GetBounds(rect
);
791 nsRect nonclientBounds
= rect
.ToAppUnits(p2a
);
792 nsrefcnt widgetRefCnt
= mWindow
->AddRef() - 1;
795 mWindow
->GetZIndex(&Z
);
796 fprintf(out
, "(widget=%p[%d] z=%d pos={%d,%d,%d,%d}) ",
797 (void*)mWindow
, widgetRefCnt
, Z
,
798 nonclientBounds
.x
, nonclientBounds
.y
,
799 windowBounds
.width
, windowBounds
.height
);
801 nsRect brect
= GetBounds();
802 fprintf(out
, "{%d,%d,%d,%d}",
803 brect
.x
, brect
.y
, brect
.width
, brect
.height
);
804 fprintf(out
, " z=%d vis=%d frame=%p <\n",
805 mZIndex
, mVis
, static_cast<void*>(mFrame
));
806 for (nsView
* kid
= mFirstChild
; kid
; kid
= kid
->GetNextSibling()) {
807 NS_ASSERTION(kid
->GetParent() == this, "incorrect parent");
808 kid
->List(out
, aIndent
+ 1);
810 for (i
= aIndent
; --i
>= 0; ) fputs(" ", out
);
815 nsPoint
nsView::GetOffsetTo(const nsView
* aOther
) const
817 return GetOffsetTo(aOther
, GetViewManager()->AppUnitsPerDevPixel());
820 nsPoint
nsView::GetOffsetTo(const nsView
* aOther
, const int32_t aAPD
) const
822 NS_ABORT_IF_FALSE(GetParent() || !aOther
|| aOther
->GetParent() ||
823 this == aOther
, "caller of (outer) GetOffsetTo must not "
824 "pass unrelated views");
825 // We accumulate the final result in offset
826 nsPoint
offset(0, 0);
827 // The offset currently accumulated at the current APD
828 nsPoint
docOffset(0, 0);
829 const nsView
* v
= this;
830 nsViewManager
* currVM
= v
->GetViewManager();
831 int32_t currAPD
= currVM
->AppUnitsPerDevPixel();
832 const nsView
* root
= nullptr;
833 for ( ; v
!= aOther
&& v
; root
= v
, v
= v
->GetParent()) {
834 nsViewManager
* newVM
= v
->GetViewManager();
835 if (newVM
!= currVM
) {
836 int32_t newAPD
= newVM
->AppUnitsPerDevPixel();
837 if (newAPD
!= currAPD
) {
838 offset
+= docOffset
.ConvertAppUnits(currAPD
, aAPD
);
839 docOffset
.x
= docOffset
.y
= 0;
844 docOffset
+= v
->GetPosition();
846 offset
+= docOffset
.ConvertAppUnits(currAPD
, aAPD
);
849 // Looks like aOther wasn't an ancestor of |this|. So now we have
850 // the root-VM-relative position of |this| in |offset|. Get the
851 // root-VM-relative position of aOther and subtract it.
852 nsPoint negOffset
= aOther
->GetOffsetTo(root
, aAPD
);
859 nsPoint
nsView::GetOffsetToWidget(nsIWidget
* aWidget
) const
862 // Get the view for widget
863 nsView
* widgetView
= GetViewFor(aWidget
);
868 // Get the offset to the widget view in the widget view's APD
869 // We get the offset in the widget view's APD first and then convert to our
870 // APD afterwards so that we can include the widget view's ViewToWidgetOffset
871 // in the sum in its native APD, and then convert the whole thing to our APD
872 // so that we don't have to convert the APD of the relatively small
873 // ViewToWidgetOffset by itself with a potentially large relative rounding
875 pt
= -widgetView
->GetOffsetTo(this);
876 // Add in the offset to the widget.
877 pt
+= widgetView
->ViewToWidgetOffset();
879 // Convert to our appunits.
880 int32_t widgetAPD
= widgetView
->GetViewManager()->AppUnitsPerDevPixel();
881 int32_t ourAPD
= GetViewManager()->AppUnitsPerDevPixel();
882 pt
= pt
.ConvertAppUnits(widgetAPD
, ourAPD
);
886 nsIWidget
* nsView::GetNearestWidget(nsPoint
* aOffset
) const
888 return GetNearestWidget(aOffset
, GetViewManager()->AppUnitsPerDevPixel());
891 nsIWidget
* nsView::GetNearestWidget(nsPoint
* aOffset
, const int32_t aAPD
) const
893 // aOffset is based on the view's position, which ignores any chrome on
894 // attached parent widgets.
896 // We accumulate the final result in pt
898 // The offset currently accumulated at the current APD
900 const nsView
* v
= this;
901 nsViewManager
* currVM
= v
->GetViewManager();
902 int32_t currAPD
= currVM
->AppUnitsPerDevPixel();
903 for ( ; v
&& !v
->HasWidget(); v
= v
->GetParent()) {
904 nsViewManager
* newVM
= v
->GetViewManager();
905 if (newVM
!= currVM
) {
906 int32_t newAPD
= newVM
->AppUnitsPerDevPixel();
907 if (newAPD
!= currAPD
) {
908 pt
+= docPt
.ConvertAppUnits(currAPD
, aAPD
);
909 docPt
.x
= docPt
.y
= 0;
914 docPt
+= v
->GetPosition();
918 pt
+= docPt
.ConvertAppUnits(currAPD
, aAPD
);
924 // pt is now the offset from v's origin to this view's origin.
925 // We add the ViewToWidgetOffset to get the offset to the widget.
927 docPt
+= v
->ViewToWidgetOffset();
928 pt
+= docPt
.ConvertAppUnits(currAPD
, aAPD
);
931 return v
->GetWidget();
934 bool nsView::IsRoot() const
936 NS_ASSERTION(mViewManager
!= nullptr," View manager is null in nsView::IsRoot()");
937 return mViewManager
->GetRootView() == this;
941 nsView::GetBoundsInParentUnits() const
943 nsView
* parent
= GetParent();
944 nsViewManager
* VM
= GetViewManager();
945 if (this != VM
->GetRootView() || !parent
) {
948 int32_t ourAPD
= VM
->AppUnitsPerDevPixel();
949 int32_t parentAPD
= parent
->GetViewManager()->AppUnitsPerDevPixel();
950 return mDimBounds
.ConvertAppUnitsRoundOut(ourAPD
, parentAPD
);
954 nsView::ConvertFromParentCoords(nsPoint aPt
) const
956 const nsView
* parent
= GetParent();
958 aPt
= aPt
.ConvertAppUnits(parent
->GetViewManager()->AppUnitsPerDevPixel(),
959 GetViewManager()->AppUnitsPerDevPixel());
961 aPt
-= GetPosition();
966 IsPopupWidget(nsIWidget
* aWidget
)
969 aWidget
->GetWindowType(type
);
970 return (type
== eWindowType_popup
);
974 nsView::GetPresShell()
976 return GetViewManager()->GetPresShell();
980 nsView::WindowMoved(nsIWidget
* aWidget
, int32_t x
, int32_t y
)
982 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
983 if (pm
&& IsPopupWidget(aWidget
)) {
984 pm
->PopupMoved(mFrame
, nsIntPoint(x
, y
));
992 nsView::WindowResized(nsIWidget
* aWidget
, int32_t aWidth
, int32_t aHeight
)
994 // The root view may not be set if this is the resize associated with
996 SetForcedRepaint(true);
997 if (this == mViewManager
->GetRootView()) {
998 nsRefPtr
<nsDeviceContext
> devContext
= mViewManager
->GetDeviceContext();
999 // ensure DPI is up-to-date, in case of window being opened and sized
1000 // on a non-default-dpi display (bug 829963)
1001 devContext
->CheckDPIChange();
1002 int32_t p2a
= devContext
->AppUnitsPerDevPixel();
1003 mViewManager
->SetWindowDimensions(NSIntPixelsToAppUnits(aWidth
, p2a
),
1004 NSIntPixelsToAppUnits(aHeight
, p2a
));
1007 else if (IsPopupWidget(aWidget
)) {
1008 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
1010 pm
->PopupResized(mFrame
, nsIntSize(aWidth
, aHeight
));
1019 nsView::RequestWindowClose(nsIWidget
* aWidget
)
1021 if (mFrame
&& IsPopupWidget(aWidget
) &&
1022 mFrame
->GetType() == nsGkAtoms::menuPopupFrame
) {
1023 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
1025 pm
->HidePopup(mFrame
->GetContent(), false, true, false);
1034 nsView::WillPaintWindow(nsIWidget
* aWidget
)
1036 nsRefPtr
<nsViewManager
> vm
= mViewManager
;
1037 vm
->WillPaintWindow(aWidget
);
1041 nsView::PaintWindow(nsIWidget
* aWidget
, nsIntRegion aRegion
)
1043 NS_ASSERTION(this == nsView::GetViewFor(aWidget
), "wrong view for widget?");
1045 nsRefPtr
<nsViewManager
> vm
= mViewManager
;
1046 bool result
= vm
->PaintWindow(aWidget
, aRegion
);
1051 nsView::DidPaintWindow()
1053 nsRefPtr
<nsViewManager
> vm
= mViewManager
;
1054 vm
->DidPaintWindow();
1058 nsView::RequestRepaint()
1060 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
1062 presShell
->ScheduleViewManagerFlush();
1067 nsView::HandleEvent(WidgetGUIEvent
* aEvent
,
1068 bool aUseAttachedEvents
)
1070 NS_PRECONDITION(nullptr != aEvent
->widget
, "null widget ptr");
1072 nsEventStatus result
= nsEventStatus_eIgnore
;
1074 if (aUseAttachedEvents
) {
1075 nsIWidgetListener
* listener
= aEvent
->widget
->GetAttachedWidgetListener();
1076 view
= listener
? listener
->GetView() : nullptr;
1079 view
= GetViewFor(aEvent
->widget
);
1083 nsRefPtr
<nsViewManager
> vm
= view
->GetViewManager();
1084 vm
->DispatchEvent(aEvent
, view
, &result
);