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/IntegerPrintfMacros.h"
12 #include "mozilla/Likely.h"
13 #include "mozilla/Poison.h"
14 #include "nsIWidget.h"
15 #include "nsViewManager.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
)
26 MOZ_COUNT_CTOR(nsView
);
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.
34 mViewManager
= aViewManager
;
35 mDirtyRegion
= nullptr;
36 mWidgetIsTopLevel
= false;
39 void nsView::DropMouseGrabbing()
41 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
43 presShell
->ClearMouseCaptureOnView(this);
48 MOZ_COUNT_DTOR(nsView
);
50 while (GetFirstChild())
52 nsView
* child
= GetFirstChild();
53 if (child
->GetViewManager() == mViewManager
) {
56 // just unhook it. Someone else will want to destroy this.
65 nsView
*rootView
= mViewManager
->GetRootView();
69 // Root views can have parents!
72 mViewManager
->RemoveChild(this);
77 // Inform the view manager that the root view has gone away...
78 mViewManager
->SetRootView(nullptr);
83 mParent
->RemoveChild(this);
86 mViewManager
= nullptr;
90 mParent
->RemoveChild(this);
93 // Destroy and release the widget
99 class DestroyWidgetRunnable
: public nsRunnable
{
103 explicit DestroyWidgetRunnable(nsIWidget
* aWidget
) : mWidget(aWidget
) {}
106 nsCOMPtr
<nsIWidget
> mWidget
;
109 NS_IMETHODIMP
DestroyWidgetRunnable::Run()
117 void nsView::DestroyWidget()
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);
129 mWindow
->SetWidgetListener(nullptr);
131 nsCOMPtr
<nsIRunnable
> widgetDestroyer
=
132 new DestroyWidgetRunnable(mWindow
);
134 NS_DispatchToMainThread(widgetDestroyer
);
141 nsView
* nsView::GetViewFor(nsIWidget
* aWidget
)
143 NS_PRECONDITION(nullptr != aWidget
, "null widget ptr");
145 nsIWidgetListener
* listener
= aWidget
->GetWidgetListener();
147 nsView
* view
= listener
->GetView();
152 listener
= aWidget
->GetAttachedWidgetListener();
153 return listener
? listener
->GetView() : nullptr;
156 void nsView::Destroy()
159 mozWritePoison(this, sizeof(*this));
160 nsView::operator delete(this);
163 void nsView::SetPosition(nscoord aX
, nscoord aY
)
165 mDimBounds
.x
+= aX
- mPosX
;
166 mDimBounds
.y
+= aY
- mPosY
;
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);
176 void nsView::ResetWidgetBounds(bool aRecurse
, bool aForceSync
)
180 // Don't change widget geometry synchronously, since that can
181 // cause synchronous painting.
182 mViewManager
->PostPendingUpdate();
184 DoResetWidgetBounds(false, true);
190 // reposition any widgets under this view
191 for (nsView
* v
= GetFirstChild(); v
; v
= v
->GetNextSibling()) {
192 v
->ResetWidgetBounds(true, aForceSync
);
197 bool nsView::IsEffectivelyVisible()
199 for (nsView
* v
= this; v
; v
= v
->mParent
) {
200 if (v
->GetVisibility() == nsViewVisibility_kHide
)
206 nsIntRect
nsView::CalcWidgetBounds(nsWindowType aType
)
208 int32_t p2a
= mViewManager
->AppUnitsPerDevPixel();
210 nsRect
viewBounds(mDimBounds
);
212 nsView
* parent
= GetParent();
213 nsIWidget
* parentWidget
= nullptr;
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
));
229 // Compute widget bounds in device pixels
230 nsIntRect newBounds
= viewBounds
.ToNearestPixels(p2a
);
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
;
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
;
245 NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds
.XMost(), p2a
) / round
) * round
- newBounds
.x
;
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
;
253 if (newBounds
.height
> pixelRoundedSize
.height
) {
254 newBounds
.height
-= round
;
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
;
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) {
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).
291 nsRefPtr
<nsDeviceContext
> dx
= mViewManager
->GetDeviceContext();
293 nsWindowType type
= widget
->WindowType();
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.
304 newBounds
= CalcWidgetBounds(type
);
307 bool curVisibility
= widget
->IsVisible();
308 bool newVisibility
= IsEffectivelyVisible();
309 if (curVisibility
&& !newVisibility
) {
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.
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
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 // AppUnitsPerDevPixelAtUnitFullZoom 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
->AppUnitsPerDevPixelAtUnitFullZoom()) {
345 invScale
= 1.0 / scale
.scale
;
347 invScale
= dx
->AppUnitsPerDevPixelAtUnitFullZoom() / 60.0;
351 if (changedSize
&& !aMoveOnly
) {
352 widget
->ResizeClient(newBounds
.x
* invScale
,
353 newBounds
.y
* invScale
,
354 newBounds
.width
* invScale
,
355 newBounds
.height
* invScale
,
356 aInvalidateChangedSize
);
358 widget
->MoveClient(newBounds
.x
* invScale
,
359 newBounds
.y
* invScale
);
362 if (changedSize
&& !aMoveOnly
) {
363 widget
->ResizeClient(newBounds
.width
* invScale
,
364 newBounds
.height
* invScale
,
365 aInvalidateChangedSize
);
366 } // else do nothing!
369 if (!curVisibility
&& newVisibility
) {
374 void nsView::SetDimensions(const nsRect
& aRect
, bool aPaint
, bool aResizeWidget
)
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()) {
390 ResetWidgetBounds(false, false);
394 void nsView::NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible
)
396 if (!aEffectivelyVisible
)
401 SetForcedRepaint(true);
403 if (nullptr != mWindow
)
405 ResetWidgetBounds(false, false);
408 for (nsView
* child
= mFirstChild
; child
; child
= child
->mNextSibling
) {
409 if (child
->mVis
== nsViewVisibility_kHide
) {
410 // It was effectively hidden and still is
413 // Our child is visible if we are
414 child
->NotifyEffectiveVisibilityChanged(aEffectivelyVisible
);
418 void nsView::SetVisibility(nsViewVisibility aVisibility
)
421 NotifyEffectiveVisibilityChanged(IsEffectivelyVisible());
424 void nsView::SetFloating(bool aFloatingView
)
427 mVFlags
|= NS_VIEW_FLAG_FLOATING
;
429 mVFlags
&= ~NS_VIEW_FLAG_FLOATING
;
432 void nsView::InvalidateHierarchy(nsViewManager
*aViewManagerParent
)
434 if (mViewManager
->GetRootView() == this)
435 mViewManager
->InvalidateHierarchy();
437 for (nsView
*child
= mFirstChild
; child
; child
= child
->GetNextSibling())
438 child
->InvalidateHierarchy(aViewManagerParent
);
441 void nsView::InsertChild(nsView
*aChild
, nsView
*aSibling
)
443 NS_PRECONDITION(nullptr != aChild
, "null ptr");
445 if (nullptr != aChild
)
447 if (nullptr != aSibling
)
450 NS_ASSERTION(aSibling
->GetParent() == this, "tried to insert view with invalid sibling");
452 //insert after sibling
453 aChild
->SetNextSibling(aSibling
->GetNextSibling());
454 aSibling
->SetNextSibling(aChild
);
458 aChild
->SetNextSibling(mFirstChild
);
459 mFirstChild
= aChild
;
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
)
469 aChild
->InvalidateHierarchy(nullptr); // don't care about releasing grabs
474 void nsView::RemoveChild(nsView
*child
)
476 NS_PRECONDITION(nullptr != child
, "null ptr");
478 if (nullptr != child
)
480 nsView
* prevKid
= nullptr;
481 nsView
* kid
= mFirstChild
;
482 DebugOnly
<bool> found
= false;
483 while (nullptr != kid
) {
485 if (nullptr != prevKid
) {
486 prevKid
->SetNextSibling(kid
->GetNextSibling());
488 mFirstChild
= kid
->GetNextSibling();
490 child
->SetParent(nullptr);
495 kid
= kid
->GetNextSibling();
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
)
505 child
->InvalidateHierarchy(GetViewManager());
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
)
517 if (aView
->HasWidget()) {
518 nsIWidget
* widget
= aView
->GetWidget();
519 if (widget
->GetZIndex() != aZIndex
) {
520 widget
->SetZIndex(aZIndex
);
523 for (nsView
* v
= aView
->GetFirstChild(); v
; v
= v
->GetNextSibling()) {
524 if (v
->GetZIndexIsAuto()) {
525 UpdateNativeWidgetZIndexes(v
, aZIndex
);
531 static int32_t FindNonAutoZIndex(nsView
* aView
)
534 if (!aView
->GetZIndexIsAuto()) {
535 return aView
->GetZIndex();
537 aView
= aView
->GetParent();
542 struct DefaultWidgetInitData
: public nsWidgetInitData
{
543 DefaultWidgetInitData() : nsWidgetInitData()
545 mWindowType
= eWindowType_child
;
551 nsresult
nsView::CreateWidget(nsWidgetInitData
*aWidgetInitData
,
552 bool aEnableDragDrop
,
553 bool aResetVisibility
)
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;
574 NS_ERROR("nsView::CreateWidget without suitable parent widget??");
575 return NS_ERROR_FAILURE
;
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
,
583 return NS_ERROR_FAILURE
;
586 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
591 nsresult
nsView::CreateWidgetForParent(nsIWidget
* aParentWidget
,
592 nsWidgetInitData
*aWidgetInitData
,
593 bool aEnableDragDrop
,
594 bool aResetVisibility
)
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();
610 aParentWidget
->CreateChild(trect
, dx
, aWidgetInitData
).take();
612 return NS_ERROR_FAILURE
;
615 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
620 nsresult
nsView::CreateWidgetForPopup(nsWidgetInitData
*aWidgetInitData
,
621 nsIWidget
* aParentWidget
,
622 bool aEnableDragDrop
,
623 bool aResetVisibility
)
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.
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
,
645 nsIWidget
* nearestParent
= GetParent() ? GetParent()->GetNearestWidget(nullptr)
647 if (!nearestParent
) {
648 // Without a parent, we can't make a popup. This can happen
650 return NS_ERROR_FAILURE
;
654 nearestParent
->CreateChild(trect
, dx
, aWidgetInitData
).take();
657 return NS_ERROR_FAILURE
;
660 InitializeWindow(aEnableDragDrop
, aResetVisibility
);
666 nsView::InitializeWindow(bool aEnableDragDrop
, bool aResetVisibility
)
668 NS_ABORT_IF_FALSE(mWindow
, "Must have a window to initialize");
670 mWindow
->SetWidgetListener(this);
672 if (aEnableDragDrop
) {
673 mWindow
->EnableDragDrop(true);
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());
686 // Attach to a top level widget and start receiving mirrored events.
687 nsresult
nsView::AttachToTopLevelWidget(nsIWidget
* aWidget
)
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();
694 nsView
*oldView
= listener
->GetView();
696 oldView
->DetachFromTopLevelWidget();
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
);
711 mWindow
->SetAttachedWidgetListener(this);
712 mWindow
->EnableDragDrop(true);
713 mWidgetIsTopLevel
= true;
715 // Refresh the view bounds
716 CalcWidgetBounds(mWindow
->WindowType());
721 // Detach this view from an attached widget.
722 nsresult
nsView::DetachFromTopLevelWidget()
724 NS_PRECONDITION(mWidgetIsTopLevel
, "Not attached currently!");
725 NS_PRECONDITION(mWindow
, "null mWindow for DetachFromTopLevelWidget!");
727 mWindow
->SetAttachedWidgetListener(nullptr);
730 mWidgetIsTopLevel
= false;
735 void nsView::SetZIndex(bool aAuto
, int32_t aZIndex
)
737 bool oldIsAuto
= GetZIndexIsAuto();
738 mVFlags
= (mVFlags
& ~NS_VIEW_FLAG_AUTO_ZINDEX
) | (aAuto
? NS_VIEW_FLAG_AUTO_ZINDEX
: 0);
741 if (HasWidget() || !oldIsAuto
|| !aAuto
) {
742 UpdateNativeWidgetZIndexes(this, FindNonAutoZIndex(this));
746 void nsView::AssertNoWindow()
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);
758 // internal window creation functions
760 void nsView::AttachWidgetEventHandler(nsIWidget
* aWidget
)
763 NS_ASSERTION(!aWidget
->GetWidgetListener(), "Already have a widget listener");
766 aWidget
->SetWidgetListener(this);
769 void nsView::DetachWidgetEventHandler(nsIWidget
* aWidget
)
771 NS_ASSERTION(!aWidget
->GetWidgetListener() ||
772 aWidget
->GetWidgetListener()->GetView() == this, "Wrong view");
773 aWidget
->SetWidgetListener(nullptr);
777 void nsView::List(FILE* out
, int32_t aIndent
) const
780 for (i
= aIndent
; --i
>= 0; ) fputs(" ", out
);
781 fprintf(out
, "%p ", (void*)this);
782 if (nullptr != mWindow
) {
783 nscoord p2a
= mViewManager
->AppUnitsPerDevPixel();
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;
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
);
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);
806 for (i
= aIndent
; --i
>= 0; ) fputs(" ", out
);
811 nsPoint
nsView::GetOffsetTo(const nsView
* aOther
) const
813 return GetOffsetTo(aOther
, GetViewManager()->AppUnitsPerDevPixel());
816 nsPoint
nsView::GetOffsetTo(const nsView
* aOther
, const int32_t aAPD
) const
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;
840 docOffset
+= v
->GetPosition();
842 offset
+= docOffset
.ConvertAppUnits(currAPD
, aAPD
);
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
);
855 nsPoint
nsView::GetOffsetToWidget(nsIWidget
* aWidget
) const
858 // Get the view for widget
859 nsView
* widgetView
= GetViewFor(aWidget
);
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
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
);
882 nsIWidget
* nsView::GetNearestWidget(nsPoint
* aOffset
) const
884 return GetNearestWidget(aOffset
, GetViewManager()->AppUnitsPerDevPixel());
887 nsIWidget
* nsView::GetNearestWidget(nsPoint
* aOffset
, const int32_t aAPD
) const
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
894 // The offset currently accumulated at the current APD
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;
910 docPt
+= v
->GetPosition();
914 pt
+= docPt
.ConvertAppUnits(currAPD
, aAPD
);
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.
923 docPt
+= v
->ViewToWidgetOffset();
924 pt
+= docPt
.ConvertAppUnits(currAPD
, aAPD
);
927 return v
->GetWidget();
930 bool nsView::IsRoot() const
932 NS_ASSERTION(mViewManager
!= nullptr," View manager is null in nsView::IsRoot()");
933 return mViewManager
->GetRootView() == this;
937 nsView::GetBoundsInParentUnits() const
939 nsView
* parent
= GetParent();
940 nsViewManager
* VM
= GetViewManager();
941 if (this != VM
->GetRootView() || !parent
) {
944 int32_t ourAPD
= VM
->AppUnitsPerDevPixel();
945 int32_t parentAPD
= parent
->GetViewManager()->AppUnitsPerDevPixel();
946 return mDimBounds
.ConvertAppUnitsRoundOut(ourAPD
, parentAPD
);
950 nsView::ConvertFromParentCoords(nsPoint aPt
) const
952 const nsView
* parent
= GetParent();
954 aPt
= aPt
.ConvertAppUnits(parent
->GetViewManager()->AppUnitsPerDevPixel(),
955 GetViewManager()->AppUnitsPerDevPixel());
957 aPt
-= GetPosition();
962 IsPopupWidget(nsIWidget
* aWidget
)
964 return (aWidget
->WindowType() == eWindowType_popup
);
968 nsView::GetPresShell()
970 return GetViewManager()->GetPresShell();
974 nsView::WindowMoved(nsIWidget
* aWidget
, int32_t x
, int32_t y
)
976 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
977 if (pm
&& IsPopupWidget(aWidget
)) {
978 pm
->PopupMoved(mFrame
, nsIntPoint(x
, y
));
986 nsView::WindowResized(nsIWidget
* aWidget
, int32_t aWidth
, int32_t aHeight
)
988 // The root view may not be set if this is the resize associated with
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();
1002 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
1003 if (presShell
&& presShell
->GetDocument()) {
1004 pm
->AdjustPopupsOnWindowChange(presShell
);
1010 else if (IsPopupWidget(aWidget
)) {
1011 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
1013 pm
->PopupResized(mFrame
, nsIntSize(aWidth
, aHeight
));
1022 nsView::RequestWindowClose(nsIWidget
* aWidget
)
1024 if (mFrame
&& IsPopupWidget(aWidget
) &&
1025 mFrame
->GetType() == nsGkAtoms::menuPopupFrame
) {
1026 nsXULPopupManager
* pm
= nsXULPopupManager::GetInstance();
1028 pm
->HidePopup(mFrame
->GetContent(), false, true, false, false);
1037 nsView::WillPaintWindow(nsIWidget
* aWidget
)
1039 nsRefPtr
<nsViewManager
> vm
= mViewManager
;
1040 vm
->WillPaintWindow(aWidget
);
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
);
1054 nsView::DidPaintWindow()
1056 nsRefPtr
<nsViewManager
> vm
= mViewManager
;
1057 vm
->DidPaintWindow();
1061 nsView::DidCompositeWindow()
1063 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
1065 nsAutoScriptBlocker scriptBlocker
;
1066 presShell
->GetPresContext()->GetDisplayRootPresContext()->GetRootPresContext()->NotifyDidPaintForSubtree(nsIPresShell::PAINT_COMPOSITE
);
1071 nsView::RequestRepaint()
1073 nsIPresShell
* presShell
= mViewManager
->GetPresShell();
1075 presShell
->ScheduleViewManagerFlush();
1080 nsView::HandleEvent(WidgetGUIEvent
* aEvent
,
1081 bool aUseAttachedEvents
)
1083 NS_PRECONDITION(nullptr != aEvent
->widget
, "null widget ptr");
1085 nsEventStatus result
= nsEventStatus_eIgnore
;
1087 if (aUseAttachedEvents
) {
1088 nsIWidgetListener
* listener
= aEvent
->widget
->GetAttachedWidgetListener();
1089 view
= listener
? listener
->GetView() : nullptr;
1092 view
= GetViewFor(aEvent
->widget
);
1096 nsRefPtr
<nsViewManager
> vm
= view
->GetViewManager();
1097 vm
->DispatchEvent(aEvent
, view
, &result
);