1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
10 #include "nsViewManager.h"
11 #include "nsGfxCIID.h"
14 #include "mozilla/MouseEvents.h"
16 #include "nsCOMArray.h"
17 #include "nsIPluginWidget.h"
18 #include "nsXULPopupManager.h"
19 #include "nsIPresShell.h"
20 #include "nsPresContext.h"
21 #include "mozilla/StartupTimeline.h"
22 #include "GeckoProfiler.h"
23 #include "nsRefreshDriver.h"
24 #include "mozilla/Preferences.h"
25 #include "nsContentUtils.h" // for nsAutoScriptBlocker
26 #include "nsLayoutUtils.h"
28 #include "gfxPlatform.h"
30 #include "nsIDocument.h"
35 DeCOMify newly private methods
40 A note about platform assumptions:
42 We assume that a widget is z-ordered on top of its parent.
44 We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
45 we ask for a specific z-order, we don't assume that widget z-ordering actually works.
48 using namespace mozilla
;
49 using namespace mozilla::layers
;
51 #define NSCOORD_NONE INT32_MIN
53 #undef DEBUG_MOUSE_LOCATION
55 // Weakly held references to all of the view managers
56 nsTArray
<nsViewManager
*>* nsViewManager::gViewManagers
= nullptr;
57 uint32_t nsViewManager::gLastUserEventTime
= 0;
59 nsViewManager::nsViewManager()
60 : mDelayedResize(NSCOORD_NONE
, NSCOORD_NONE
)
62 mRootViewManager
= this;
63 if (gViewManagers
== nullptr) {
64 // Create an array to hold a list of view managers
65 gViewManagers
= new nsTArray
<nsViewManager
*>;
68 gViewManagers
->AppendElement(this);
70 // NOTE: we use a zeroing operator new, so all data members are
71 // assumed to be cleared here.
72 mHasPendingWidgetGeometryChanges
= false;
73 mRecursiveRefreshPending
= false;
76 nsViewManager::~nsViewManager()
79 // Destroy any remaining views
85 // We have a strong ref to mRootViewManager
86 NS_RELEASE(mRootViewManager
);
89 NS_ASSERTION(gViewManagers
!= nullptr, "About to use null gViewManagers");
94 gViewManagers
->RemoveElement(this);
95 NS_ASSERTION(removed
, "Viewmanager instance was not in the global list of viewmanagers");
97 if (gViewManagers
->IsEmpty()) {
98 // There aren't any more view managers so
99 // release the global array of view managers
100 delete gViewManagers
;
101 gViewManagers
= nullptr;
104 mPresShell
= nullptr;
107 // We don't hold a reference to the presentation context because it
108 // holds a reference to us.
110 nsViewManager::Init(nsDeviceContext
* aContext
)
112 NS_PRECONDITION(nullptr != aContext
, "null ptr");
114 if (nullptr == aContext
) {
115 return NS_ERROR_NULL_POINTER
;
117 if (nullptr != mContext
) {
118 return NS_ERROR_ALREADY_INITIALIZED
;
126 nsViewManager::CreateView(const nsRect
& aBounds
,
128 nsViewVisibility aVisibilityFlag
)
130 nsView
*v
= new nsView(this, aVisibilityFlag
);
131 v
->SetParent(aParent
);
132 v
->SetPosition(aBounds
.x
, aBounds
.y
);
133 nsRect
dim(0, 0, aBounds
.width
, aBounds
.height
);
134 v
->SetDimensions(dim
, false);
139 nsViewManager::SetRootView(nsView
*aView
)
141 NS_PRECONDITION(!aView
|| aView
->GetViewManager() == this,
142 "Unexpected viewmanager on root view");
144 // Do NOT destroy the current root view. It's the caller's responsibility
149 nsView
* parent
= mRootView
->GetParent();
151 // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so
152 // no need to set mRootViewManager ourselves here.
153 parent
->InsertChild(mRootView
, nullptr);
155 InvalidateHierarchy();
158 mRootView
->SetZIndex(false, 0);
160 // Else don't touch mRootViewManager
164 nsViewManager::GetWindowDimensions(nscoord
*aWidth
, nscoord
*aHeight
)
166 if (nullptr != mRootView
) {
167 if (mDelayedResize
== nsSize(NSCOORD_NONE
, NSCOORD_NONE
)) {
168 nsRect dim
= mRootView
->GetDimensions();
170 *aHeight
= dim
.height
;
172 *aWidth
= mDelayedResize
.width
;
173 *aHeight
= mDelayedResize
.height
;
183 void nsViewManager::DoSetWindowDimensions(nscoord aWidth
, nscoord aHeight
)
185 nsRect oldDim
= mRootView
->GetDimensions();
186 nsRect
newDim(0, 0, aWidth
, aHeight
);
187 // We care about resizes even when one dimension is already zero.
188 if (!oldDim
.IsEqualEdges(newDim
)) {
189 // Don't resize the widget. It is already being set elsewhere.
190 mRootView
->SetDimensions(newDim
, true, false);
192 mPresShell
->ResizeReflow(aWidth
, aHeight
);
197 nsViewManager::SetWindowDimensions(nscoord aWidth
, nscoord aHeight
)
200 if (mRootView
->IsEffectivelyVisible() && mPresShell
&& mPresShell
->IsVisible()) {
201 if (mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
) &&
202 mDelayedResize
!= nsSize(aWidth
, aHeight
)) {
203 // We have a delayed resize; that now obsolete size may already have
204 // been flushed to the PresContext so we need to update the PresContext
205 // with the new size because if the new size is exactly the same as the
206 // root view's current size then DoSetWindowDimensions will not
207 // request a resize reflow (which would correct it). See bug 617076.
208 mDelayedResize
= nsSize(aWidth
, aHeight
);
209 FlushDelayedResize(false);
211 mDelayedResize
.SizeTo(NSCOORD_NONE
, NSCOORD_NONE
);
212 DoSetWindowDimensions(aWidth
, aHeight
);
214 mDelayedResize
.SizeTo(aWidth
, aHeight
);
215 if (mPresShell
&& mPresShell
->GetDocument()) {
216 mPresShell
->GetDocument()->SetNeedStyleFlush();
223 nsViewManager::FlushDelayedResize(bool aDoReflow
)
225 if (mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
)) {
227 DoSetWindowDimensions(mDelayedResize
.width
, mDelayedResize
.height
);
228 mDelayedResize
.SizeTo(NSCOORD_NONE
, NSCOORD_NONE
);
229 } else if (mPresShell
) {
230 nsPresContext
* presContext
= mPresShell
->GetPresContext();
232 presContext
->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize
));
238 // Convert aIn from being relative to and in appunits of aFromView, to being
239 // relative to and in appunits of aToView.
240 static nsRegion
ConvertRegionBetweenViews(const nsRegion
& aIn
,
245 out
.MoveBy(aFromView
->GetOffsetTo(aToView
));
246 out
= out
.ConvertAppUnitsRoundOut(
247 aFromView
->GetViewManager()->AppUnitsPerDevPixel(),
248 aToView
->GetViewManager()->AppUnitsPerDevPixel());
252 nsView
* nsViewManager::GetDisplayRootFor(nsView
* aView
)
254 nsView
*displayRoot
= aView
;
256 nsView
*displayParent
= displayRoot
->GetParent();
260 if (displayRoot
->GetFloating() && !displayParent
->GetFloating())
263 // If we have a combobox dropdown popup within a panel popup, both the view
264 // for the dropdown popup and its parent will be floating, so we need to
265 // distinguish this situation. We do this by looking for a widget. Any view
266 // with a widget is a display root, except for plugins.
267 nsIWidget
* widget
= displayRoot
->GetWidget();
268 if (widget
&& widget
->WindowType() == eWindowType_popup
) {
269 NS_ASSERTION(displayRoot
->GetFloating() && displayParent
->GetFloating(),
270 "this should only happen with floating views that have floating parents");
274 displayRoot
= displayParent
;
279 aRegion is given in device coordinates!!
280 aContext may be null, in which case layers should be used for
283 void nsViewManager::Refresh(nsView
*aView
, const nsIntRegion
& aRegion
)
285 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
287 if (mPresShell
&& mPresShell
->IsNeverPainting()) {
291 // damageRegion is the damaged area, in twips, relative to the view origin
292 nsRegion damageRegion
= aRegion
.ToAppUnits(AppUnitsPerDevPixel());
293 // move region from widget coordinates into view coordinates
294 damageRegion
.MoveBy(-aView
->ViewToWidgetOffset());
296 if (damageRegion
.IsEmpty()) {
298 nsRect viewRect
= aView
->GetDimensions();
299 nsRect damageRect
= damageRegion
.GetBounds();
300 printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
301 damageRect
.x
, damageRect
.y
, damageRect
.width
, damageRect
.height
,
302 viewRect
.x
, viewRect
.y
, viewRect
.width
, viewRect
.height
);
307 nsIWidget
*widget
= aView
->GetWidget();
312 NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
314 RootViewManager()->mRecursiveRefreshPending
= true;
319 nsAutoScriptBlocker scriptBlocker
;
322 NS_ASSERTION(GetDisplayRootFor(aView
) == aView
,
323 "Widgets that we paint must all be display roots");
326 #ifdef MOZ_DUMP_PAINTING
327 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
328 printf_stderr("--COMPOSITE-- %p\n", mPresShell
);
331 uint32_t paintFlags
= nsIPresShell::PAINT_COMPOSITE
;
332 LayerManager
*manager
= widget
->GetLayerManager();
333 if (!manager
->NeedsWidgetInvalidation()) {
334 manager
->FlushRendering();
336 mPresShell
->Paint(aView
, damageRegion
,
339 #ifdef MOZ_DUMP_PAINTING
340 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
341 printf_stderr("--ENDCOMPOSITE--\n");
344 mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT
);
350 if (RootViewManager()->mRecursiveRefreshPending
) {
351 RootViewManager()->mRecursiveRefreshPending
= false;
352 InvalidateAllViews();
357 nsViewManager::ProcessPendingUpdatesForView(nsView
* aView
,
358 bool aFlushDirtyRegion
)
360 NS_ASSERTION(IsRootVM(), "Updates will be missed");
365 nsCOMPtr
<nsIPresShell
> rootShell(mPresShell
);
366 nsTArray
<nsCOMPtr
<nsIWidget
> > widgets
;
367 aView
->GetViewManager()->ProcessPendingUpdatesRecurse(aView
, widgets
);
368 for (uint32_t i
= 0; i
< widgets
.Length(); ++i
) {
369 nsView
* view
= nsView::GetViewFor(widgets
[i
]);
371 view
->ResetWidgetBounds(false, true);
374 if (rootShell
->GetViewManager() != this) {
375 return; // 'this' might have been destroyed
377 if (aFlushDirtyRegion
) {
378 nsAutoScriptBlocker scriptBlocker
;
380 for (uint32_t i
= 0; i
< widgets
.Length(); ++i
) {
381 nsIWidget
* widget
= widgets
[i
];
382 nsView
* view
= nsView::GetViewFor(widget
);
384 view
->GetViewManager()->ProcessPendingUpdatesPaint(widget
);
392 nsViewManager::ProcessPendingUpdatesRecurse(nsView
* aView
,
393 nsTArray
<nsCOMPtr
<nsIWidget
> >& aWidgets
)
395 if (mPresShell
&& mPresShell
->IsNeverPainting()) {
399 for (nsView
* childView
= aView
->GetFirstChild(); childView
;
400 childView
= childView
->GetNextSibling()) {
401 childView
->GetViewManager()->
402 ProcessPendingUpdatesRecurse(childView
, aWidgets
);
405 nsIWidget
* widget
= aView
->GetWidget();
407 aWidgets
.AppendElement(widget
);
409 FlushDirtyRegionToWidget(aView
);
414 nsViewManager::ProcessPendingUpdatesPaint(nsIWidget
* aWidget
)
416 if (aWidget
->NeedsPaint()) {
417 // If an ancestor widget was hidden and then shown, we could
418 // have a delayed resize to handle.
419 for (nsViewManager
*vm
= this; vm
;
420 vm
= vm
->mRootView
->GetParent()
421 ? vm
->mRootView
->GetParent()->GetViewManager()
423 if (vm
->mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
) &&
424 vm
->mRootView
->IsEffectivelyVisible() &&
425 vm
->mPresShell
&& vm
->mPresShell
->IsVisible()) {
426 vm
->FlushDelayedResize(true);
429 nsView
* view
= nsView::GetViewFor(aWidget
);
431 NS_ERROR("FlushDelayedResize destroyed the nsView?");
436 #ifdef MOZ_DUMP_PAINTING
437 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
438 printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n",
439 mPresShell
, view
, aWidget
);
443 mPresShell
->Paint(view
, nsRegion(), nsIPresShell::PAINT_LAYERS
);
444 view
->SetForcedRepaint(false);
446 #ifdef MOZ_DUMP_PAINTING
447 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
448 printf_stderr("---- PAINT END ----\n");
453 FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget
));
456 void nsViewManager::FlushDirtyRegionToWidget(nsView
* aView
)
458 NS_ASSERTION(aView
->GetViewManager() == this,
459 "FlushDirtyRegionToWidget called on view we don't own");
461 if (!aView
->HasNonEmptyDirtyRegion())
464 nsRegion
* dirtyRegion
= aView
->GetDirtyRegion();
465 nsView
* nearestViewWithWidget
= aView
;
466 while (!nearestViewWithWidget
->HasWidget() &&
467 nearestViewWithWidget
->GetParent()) {
468 nearestViewWithWidget
= nearestViewWithWidget
->GetParent();
471 ConvertRegionBetweenViews(*dirtyRegion
, aView
, nearestViewWithWidget
);
473 // If we draw the frame counter we need to make sure we invalidate the area
474 // for it to make it on screen
475 if (gfxPrefs::DrawFrameCounter()) {
476 nsRect counterBounds
= gfxPlatform::FrameCounterBounds().ToAppUnits(AppUnitsPerDevPixel());
477 r
= r
.Or(r
, counterBounds
);
480 nsViewManager
* widgetVM
= nearestViewWithWidget
->GetViewManager();
481 widgetVM
->InvalidateWidgetArea(nearestViewWithWidget
, r
);
482 dirtyRegion
->SetEmpty();
486 nsViewManager::InvalidateView(nsView
*aView
)
488 // Mark the entire view as damaged
489 InvalidateView(aView
, aView
->GetDimensions());
493 AddDirtyRegion(nsView
*aView
, const nsRegion
&aDamagedRegion
)
495 nsRegion
* dirtyRegion
= aView
->GetDirtyRegion();
499 dirtyRegion
->Or(*dirtyRegion
, aDamagedRegion
);
500 dirtyRegion
->SimplifyOutward(8);
504 nsViewManager::PostPendingUpdate()
506 nsViewManager
* rootVM
= RootViewManager();
507 rootVM
->mHasPendingWidgetGeometryChanges
= true;
508 if (rootVM
->mPresShell
) {
509 rootVM
->mPresShell
->ScheduleViewManagerFlush();
514 * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
515 * every widget child of aWidgetView, plus aWidgetView's own widget
518 nsViewManager::InvalidateWidgetArea(nsView
*aWidgetView
,
519 const nsRegion
&aDamagedRegion
)
521 NS_ASSERTION(aWidgetView
->GetViewManager() == this,
522 "InvalidateWidgetArea called on view we don't own");
523 nsIWidget
* widget
= aWidgetView
->GetWidget();
526 nsRect dbgBounds
= aDamagedRegion
.GetBounds();
527 printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
528 aWidgetView
, aWidgetView
->IsAttachedToTopLevel(),
529 widget
, dbgBounds
.x
, dbgBounds
.y
, dbgBounds
.width
, dbgBounds
.height
);
532 // If the widget is hidden, it don't cover nothing
533 if (widget
&& !widget
->IsVisible()) {
538 // The root view or a scrolling view might not have a widget
539 // (for example, during printing). We get here when we scroll
540 // during printing to show selected options in a listbox, for example.
544 // Update all child widgets with the damage. In the process,
545 // accumulate the union of all the child widget areas, or at least
546 // some subset of that.
548 if (widget
->GetTransparencyMode() != eTransparencyTransparent
) {
549 for (nsIWidget
* childWidget
= widget
->GetFirstChild();
551 childWidget
= childWidget
->GetNextSibling()) {
552 nsView
* view
= nsView::GetViewFor(childWidget
);
553 NS_ASSERTION(view
!= aWidgetView
, "will recur infinitely");
554 nsWindowType type
= childWidget
->WindowType();
555 if (view
&& childWidget
->IsVisible() && type
!= eWindowType_popup
) {
556 NS_ASSERTION(type
== eWindowType_plugin
,
557 "Only plugin or popup widgets can be children!");
559 // We do not need to invalidate in plugin widgets, but we should
560 // exclude them from the invalidation region IF we're not on
561 // Mac. On Mac we need to draw under plugin widgets, because
562 // plugin widgets are basically invisible
564 // GetBounds should compensate for chrome on a toplevel widget
566 childWidget
->GetBounds(bounds
);
568 nsTArray
<nsIntRect
> clipRects
;
569 childWidget
->GetWindowClipRegion(&clipRects
);
570 for (uint32_t i
= 0; i
< clipRects
.Length(); ++i
) {
571 nsRect rr
= (clipRects
[i
] + bounds
.TopLeft()).
572 ToAppUnits(AppUnitsPerDevPixel());
573 children
.Or(children
, rr
- aWidgetView
->ViewToWidgetOffset());
574 children
.SimplifyInward(20);
582 leftOver
.Sub(aDamagedRegion
, children
);
584 if (!leftOver
.IsEmpty()) {
586 for (nsRegionRectIterator
iter(leftOver
); (r
= iter
.Next());) {
587 nsIntRect bounds
= ViewToWidget(aWidgetView
, *r
);
588 widget
->Invalidate(bounds
);
594 ShouldIgnoreInvalidation(nsViewManager
* aVM
)
597 nsIPresShell
* shell
= aVM
->GetPresShell();
598 if (!shell
|| shell
->ShouldIgnoreInvalidation()) {
601 nsView
* view
= aVM
->GetRootView()->GetParent();
602 aVM
= view
? view
->GetViewManager() : nullptr;
608 nsViewManager::InvalidateView(nsView
*aView
, const nsRect
&aRect
)
610 // If painting is suppressed in the presshell or an ancestor drop all
611 // invalidates, it will invalidate everything when it unsuppresses.
612 if (ShouldIgnoreInvalidation(this)) {
616 InvalidateViewNoSuppression(aView
, aRect
);
620 nsViewManager::InvalidateViewNoSuppression(nsView
*aView
,
623 NS_PRECONDITION(nullptr != aView
, "null view");
625 NS_ASSERTION(aView
->GetViewManager() == this,
626 "InvalidateViewNoSuppression called on view we don't own");
628 nsRect
damagedRect(aRect
);
629 if (damagedRect
.IsEmpty()) {
633 nsView
* displayRoot
= GetDisplayRootFor(aView
);
634 nsViewManager
* displayRootVM
= displayRoot
->GetViewManager();
635 // Propagate the update to the displayRoot, since iframes, for example,
636 // can overlap each other and be translucent. So we have to possibly
637 // invalidate our rect in each of the widgets we have lying about.
638 damagedRect
.MoveBy(aView
->GetOffsetTo(displayRoot
));
639 int32_t rootAPD
= displayRootVM
->AppUnitsPerDevPixel();
640 int32_t APD
= AppUnitsPerDevPixel();
641 damagedRect
= damagedRect
.ConvertAppUnitsRoundOut(APD
, rootAPD
);
643 // accumulate this rectangle in the view's dirty region, so we can
645 AddDirtyRegion(displayRoot
, nsRegion(damagedRect
));
649 nsViewManager::InvalidateAllViews()
651 if (RootViewManager() != this) {
652 return RootViewManager()->InvalidateAllViews();
655 InvalidateViews(mRootView
);
658 void nsViewManager::InvalidateViews(nsView
*aView
)
660 // Invalidate this view.
661 InvalidateView(aView
);
663 // Invalidate all children as well.
664 nsView
* childView
= aView
->GetFirstChild();
665 while (nullptr != childView
) {
666 childView
->GetViewManager()->InvalidateViews(childView
);
667 childView
= childView
->GetNextSibling();
671 void nsViewManager::WillPaintWindow(nsIWidget
* aWidget
)
674 nsView
* view
= nsView::GetViewFor(aWidget
);
675 LayerManager
*manager
= aWidget
->GetLayerManager();
677 (view
->ForcedRepaint() || !manager
->NeedsWidgetInvalidation())) {
678 ProcessPendingUpdates();
679 // Re-get the view pointer here since the ProcessPendingUpdates might have
680 // destroyed it during CallWillPaintOnObservers.
681 view
= nsView::GetViewFor(aWidget
);
683 view
->SetForcedRepaint(false);
688 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
690 shell
->WillPaintWindow();
694 bool nsViewManager::PaintWindow(nsIWidget
* aWidget
, nsIntRegion aRegion
)
696 if (!aWidget
|| !mContext
)
699 NS_ASSERTION(IsPaintingAllowed(),
700 "shouldn't be receiving paint events while painting is disallowed!");
702 // Get the view pointer here since NS_WILL_PAINT might have
703 // destroyed it during CallWillPaintOnObservers (bug 378273).
704 nsView
* view
= nsView::GetViewFor(aWidget
);
705 if (view
&& !aRegion
.IsEmpty()) {
706 Refresh(view
, aRegion
);
712 void nsViewManager::DidPaintWindow()
714 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
716 shell
->DidPaintWindow();
721 nsViewManager::DispatchEvent(WidgetGUIEvent
*aEvent
,
723 nsEventStatus
* aStatus
)
725 PROFILER_LABEL("nsViewManager", "DispatchEvent",
726 js::ProfileEntry::Category::EVENTS
);
728 WidgetMouseEvent
* mouseEvent
= aEvent
->AsMouseEvent();
730 // Ignore mouse events that we synthesize.
731 mouseEvent
->reason
== WidgetMouseEvent::eReal
&&
732 // Ignore mouse exit and enter (we'll get moves if the user
733 // is really moving the mouse) since we get them when we
734 // create and destroy widgets.
735 mouseEvent
->message
!= NS_MOUSE_EXIT
&&
736 mouseEvent
->message
!= NS_MOUSE_ENTER
) ||
737 aEvent
->HasKeyEventMessage() ||
738 aEvent
->HasIMEEventMessage() ||
739 aEvent
->message
== NS_PLUGIN_INPUT_EVENT
) {
740 gLastUserEventTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
743 // Find the view whose coordinates system we're in.
744 nsView
* view
= aView
;
745 bool dispatchUsingCoordinates
= aEvent
->IsUsingCoordinates();
746 if (dispatchUsingCoordinates
) {
747 // Will dispatch using coordinates. Pretty bogus but it's consistent
748 // with what presshell does.
749 view
= GetDisplayRootFor(view
);
752 // If the view has no frame, look for a view that does.
753 nsIFrame
* frame
= view
->GetFrame();
755 (dispatchUsingCoordinates
|| aEvent
->HasKeyEventMessage() ||
756 aEvent
->IsIMERelatedEvent() ||
757 aEvent
->IsNonRetargetedNativeEventDelivererForPlugin() ||
758 aEvent
->HasPluginActivationEventMessage() ||
759 aEvent
->message
== NS_PLUGIN_RESOLUTION_CHANGED
)) {
760 while (view
&& !view
->GetFrame()) {
761 view
= view
->GetParent();
765 frame
= view
->GetFrame();
769 if (nullptr != frame
) {
770 // Hold a refcount to the presshell. The continued existence of the
771 // presshell will delay deletion of this view hierarchy should the event
772 // want to cause its destruction in, say, some JavaScript event handler.
773 nsCOMPtr
<nsIPresShell
> shell
= view
->GetViewManager()->GetPresShell();
775 shell
->HandleEvent(frame
, aEvent
, false, aStatus
);
780 *aStatus
= nsEventStatus_eIgnore
;
783 // Recursively reparent widgets if necessary
785 void nsViewManager::ReparentChildWidgets(nsView
* aView
, nsIWidget
*aNewWidget
)
787 NS_PRECONDITION(aNewWidget
, "");
789 if (aView
->HasWidget()) {
790 // Check to see if the parent widget is the
791 // same as the new parent. If not then reparent
792 // the widget, otherwise there is nothing more
793 // to do for the view and its descendants
794 nsIWidget
* widget
= aView
->GetWidget();
795 nsIWidget
* parentWidget
= widget
->GetParent();
798 if (parentWidget
!= aNewWidget
) {
802 widget
->SetParent(aNewWidget
);
803 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetParent failed!");
806 // Toplevel widget (popup, dialog, etc)
807 widget
->ReparentNativeWidget(aNewWidget
);
812 // Need to check each of the views children to see
813 // if they have a widget and reparent it.
815 for (nsView
*kid
= aView
->GetFirstChild(); kid
; kid
= kid
->GetNextSibling()) {
816 ReparentChildWidgets(kid
, aNewWidget
);
820 // Reparent a view and its descendant views widgets if necessary
822 void nsViewManager::ReparentWidgets(nsView
* aView
, nsView
*aParent
)
824 NS_PRECONDITION(aParent
, "Must have a parent");
825 NS_PRECONDITION(aView
, "Must have a view");
827 // Quickly determine whether the view has pre-existing children or a
828 // widget. In most cases the view will not have any pre-existing
829 // children when this is called. Only in the case
830 // where a view has been reparented by removing it from
831 // a reinserting it into a new location in the view hierarchy do we
832 // have to consider reparenting the existing widgets for the view and
834 if (aView
->HasWidget() || aView
->GetFirstChild()) {
835 nsIWidget
* parentWidget
= aParent
->GetNearestWidget(nullptr);
837 ReparentChildWidgets(aView
, parentWidget
);
840 NS_WARNING("Can not find a widget for the parent view");
845 nsViewManager::InsertChild(nsView
*aParent
, nsView
*aChild
, nsView
*aSibling
,
848 NS_PRECONDITION(nullptr != aParent
, "null ptr");
849 NS_PRECONDITION(nullptr != aChild
, "null ptr");
850 NS_ASSERTION(aSibling
== nullptr || aSibling
->GetParent() == aParent
,
851 "tried to insert view with invalid sibling");
852 NS_ASSERTION(!IsViewInserted(aChild
), "tried to insert an already-inserted view");
854 if ((nullptr != aParent
) && (nullptr != aChild
))
856 // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
857 // order, otherwise after 'kid' (i.e. before 'kid' in document order).
859 if (nullptr == aSibling
) {
861 // insert at end of document order, i.e., before first view
862 // this is the common case, by far
863 aParent
->InsertChild(aChild
, nullptr);
864 ReparentWidgets(aChild
, aParent
);
866 // insert at beginning of document order, i.e., after last view
867 nsView
*kid
= aParent
->GetFirstChild();
868 nsView
*prev
= nullptr;
871 kid
= kid
->GetNextSibling();
873 // prev is last view or null if there are no children
874 aParent
->InsertChild(aChild
, prev
);
875 ReparentWidgets(aChild
, aParent
);
878 nsView
*kid
= aParent
->GetFirstChild();
879 nsView
*prev
= nullptr;
880 while (kid
&& aSibling
!= kid
) {
881 //get the next sibling view
883 kid
= kid
->GetNextSibling();
885 NS_ASSERTION(kid
!= nullptr,
886 "couldn't find sibling in child list");
888 // insert after 'kid' in document order, i.e. before in view order
889 aParent
->InsertChild(aChild
, prev
);
890 ReparentWidgets(aChild
, aParent
);
892 // insert before 'kid' in document order, i.e. after in view order
893 aParent
->InsertChild(aChild
, kid
);
894 ReparentWidgets(aChild
, aParent
);
898 // if the parent view is marked as "floating", make the newly added view float as well.
899 if (aParent
->GetFloating())
900 aChild
->SetFloating(true);
905 nsViewManager::InsertChild(nsView
*aParent
, nsView
*aChild
, int32_t aZIndex
)
907 // no-one really calls this with anything other than aZIndex == 0 on a fresh view
908 // XXX this method should simply be eliminated and its callers redirected to the real method
909 SetViewZIndex(aChild
, false, aZIndex
);
910 InsertChild(aParent
, aChild
, nullptr, true);
914 nsViewManager::RemoveChild(nsView
*aChild
)
916 NS_ASSERTION(aChild
, "aChild must not be null");
918 nsView
* parent
= aChild
->GetParent();
920 if (nullptr != parent
) {
921 NS_ASSERTION(aChild
->GetViewManager() == this ||
922 parent
->GetViewManager() == this, "wrong view manager");
923 parent
->RemoveChild(aChild
);
928 nsViewManager::MoveViewTo(nsView
*aView
, nscoord aX
, nscoord aY
)
930 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
931 aView
->SetPosition(aX
, aY
);
935 nsViewManager::ResizeView(nsView
*aView
, const nsRect
&aRect
, bool aRepaintExposedAreaOnly
)
937 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
939 nsRect oldDimensions
= aView
->GetDimensions();
940 if (!oldDimensions
.IsEqualEdges(aRect
)) {
941 aView
->SetDimensions(aRect
, true);
944 // Note that if layout resizes the view and the view has a custom clip
945 // region set, then we expect layout to update the clip region too. Thus
946 // in the case where mClipRect has been optimized away to just be a null
947 // pointer, and this resize is implicitly changing the clip rect, it's OK
948 // because layout will change it back again if necessary.
952 nsViewManager::SetViewFloating(nsView
*aView
, bool aFloating
)
954 NS_ASSERTION(!(nullptr == aView
), "no view");
956 aView
->SetFloating(aFloating
);
960 nsViewManager::SetViewVisibility(nsView
*aView
, nsViewVisibility aVisible
)
962 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
964 if (aVisible
!= aView
->GetVisibility()) {
965 aView
->SetVisibility(aVisible
);
969 bool nsViewManager::IsViewInserted(nsView
*aView
)
971 if (mRootView
== aView
) {
973 } else if (aView
->GetParent() == nullptr) {
976 nsView
* view
= aView
->GetParent()->GetFirstChild();
977 while (view
!= nullptr) {
981 view
= view
->GetNextSibling();
988 nsViewManager::SetViewZIndex(nsView
*aView
, bool aAutoZIndex
, int32_t aZIndex
)
990 NS_ASSERTION((aView
!= nullptr), "no view");
992 // don't allow the root view's z-index to be changed. It should always be zero.
993 // This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
994 if (aView
== mRootView
) {
1002 aView
->SetZIndex(aAutoZIndex
, aZIndex
);
1006 nsViewManager::IncrementDisableRefreshCount()
1009 return RootViewManager()->IncrementDisableRefreshCount();
1012 ++mRefreshDisableCount
;
1018 nsViewManager::DecrementDisableRefreshCount()
1020 NS_ASSERTION(IsRootVM(), "Should only be called on root");
1021 --mRefreshDisableCount
;
1022 NS_ASSERTION(mRefreshDisableCount
>= 0, "Invalid refresh disable count!");
1026 nsViewManager::GetRootWidget(nsIWidget
**aWidget
)
1032 if (mRootView
->HasWidget()) {
1033 *aWidget
= mRootView
->GetWidget();
1034 NS_ADDREF(*aWidget
);
1037 if (mRootView
->GetParent()) {
1038 mRootView
->GetParent()->GetViewManager()->GetRootWidget(aWidget
);
1044 nsIntRect
nsViewManager::ViewToWidget(nsView
*aView
, const nsRect
&aRect
) const
1046 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
1048 // account for the view's origin not lining up with the widget's
1049 nsRect rect
= aRect
+ aView
->ViewToWidgetOffset();
1051 // finally, convert to device coordinates.
1052 return rect
.ToOutsidePixels(AppUnitsPerDevPixel());
1056 nsViewManager::IsPainting(bool& aIsPainting
)
1058 aIsPainting
= IsPainting();
1062 nsViewManager::ProcessPendingUpdates()
1065 RootViewManager()->ProcessPendingUpdates();
1069 mPresShell
->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
1071 // Flush things like reflows by calling WillPaint on observer presShells.
1073 CallWillPaintOnObservers();
1075 ProcessPendingUpdatesForView(mRootView
, true);
1079 nsViewManager::UpdateWidgetGeometry()
1082 RootViewManager()->UpdateWidgetGeometry();
1086 if (mHasPendingWidgetGeometryChanges
) {
1087 mHasPendingWidgetGeometryChanges
= false;
1088 ProcessPendingUpdatesForView(mRootView
, false);
1093 nsViewManager::CallWillPaintOnObservers()
1095 NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
1097 if (NS_WARN_IF(!gViewManagers
)) {
1102 for (index
= 0; index
< gViewManagers
->Length(); index
++) {
1103 nsViewManager
* vm
= gViewManagers
->ElementAt(index
);
1104 if (vm
->RootViewManager() == this) {
1106 if (vm
->mRootView
&& vm
->mRootView
->IsEffectivelyVisible()) {
1107 nsCOMPtr
<nsIPresShell
> shell
= vm
->GetPresShell();
1117 nsViewManager::GetLastUserEventTime(uint32_t& aTime
)
1119 aTime
= gLastUserEventTime
;
1123 nsViewManager::InvalidateHierarchy()
1127 NS_RELEASE(mRootViewManager
);
1129 nsView
*parent
= mRootView
->GetParent();
1131 mRootViewManager
= parent
->GetViewManager()->RootViewManager();
1132 NS_ADDREF(mRootViewManager
);
1133 NS_ASSERTION(mRootViewManager
!= this,
1134 "Root view had a parent, but it has the same view manager");
1136 mRootViewManager
= this;