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 "nsGUIEvent.h"
16 #include "nsCOMArray.h"
17 #include "nsIPluginWidget.h"
18 #include "nsXULPopupManager.h"
19 #include "nsIPresShell.h"
20 #include "nsPresContext.h"
21 #include "nsEventStateManager.h"
22 #include "mozilla/StartupTimeline.h"
23 #include "GeckoProfiler.h"
24 #include "nsRefreshDriver.h"
25 #include "mozilla/Preferences.h"
26 #include "nsContentUtils.h" // for nsAutoScriptBlocker
27 #include "nsLayoutUtils.h"
29 #include "gfxPlatform.h"
34 DeCOMify newly private methods
39 A note about platform assumptions:
41 We assume that a widget is z-ordered on top of its parent.
43 We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
44 we ask for a specific z-order, we don't assume that widget z-ordering actually works.
47 using namespace mozilla::layers
;
49 #define NSCOORD_NONE INT32_MIN
51 #undef DEBUG_MOUSE_LOCATION
53 int32_t nsViewManager::mVMCount
= 0;
55 // Weakly held references to all of the view managers
56 nsVoidArray
* 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 NS_ASSERTION(mVMCount
== 0, "View Manager count is incorrect");
65 // Create an array to hold a list of view managers
66 gViewManagers
= new nsVoidArray
;
69 gViewManagers
->AppendElement(this);
73 // NOTE: we use a zeroing operator new, so all data members are
74 // assumed to be cleared here.
75 mHasPendingWidgetGeometryChanges
= false;
76 mRecursiveRefreshPending
= false;
79 nsViewManager::~nsViewManager()
82 // Destroy any remaining views
88 // We have a strong ref to mRootViewManager
89 NS_RELEASE(mRootViewManager
);
92 NS_ASSERTION((mVMCount
> 0), "underflow of viewmanagers");
98 gViewManagers
->RemoveElement(this);
99 NS_ASSERTION(removed
, "Viewmanager instance not was not in the global list of viewmanagers");
102 // There aren't any more view managers so
103 // release the global array of view managers
105 NS_ASSERTION(gViewManagers
!= nullptr, "About to delete null gViewManagers");
106 delete gViewManagers
;
107 gViewManagers
= nullptr;
110 mPresShell
= nullptr;
113 // We don't hold a reference to the presentation context because it
114 // holds a reference to us.
116 nsViewManager::Init(nsDeviceContext
* aContext
)
118 NS_PRECONDITION(nullptr != aContext
, "null ptr");
120 if (nullptr == aContext
) {
121 return NS_ERROR_NULL_POINTER
;
123 if (nullptr != mContext
) {
124 return NS_ERROR_ALREADY_INITIALIZED
;
132 nsViewManager::CreateView(const nsRect
& aBounds
,
134 nsViewVisibility aVisibilityFlag
)
136 nsView
*v
= new nsView(this, aVisibilityFlag
);
137 v
->SetParent(aParent
);
138 v
->SetPosition(aBounds
.x
, aBounds
.y
);
139 nsRect
dim(0, 0, aBounds
.width
, aBounds
.height
);
140 v
->SetDimensions(dim
, false);
145 nsViewManager::SetRootView(nsView
*aView
)
147 NS_PRECONDITION(!aView
|| aView
->GetViewManager() == this,
148 "Unexpected viewmanager on root view");
150 // Do NOT destroy the current root view. It's the caller's responsibility
155 nsView
* parent
= mRootView
->GetParent();
157 // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so
158 // no need to set mRootViewManager ourselves here.
159 parent
->InsertChild(mRootView
, nullptr);
161 InvalidateHierarchy();
164 mRootView
->SetZIndex(false, 0);
166 // Else don't touch mRootViewManager
170 nsViewManager::GetWindowDimensions(nscoord
*aWidth
, nscoord
*aHeight
)
172 if (nullptr != mRootView
) {
173 if (mDelayedResize
== nsSize(NSCOORD_NONE
, NSCOORD_NONE
)) {
174 nsRect dim
= mRootView
->GetDimensions();
176 *aHeight
= dim
.height
;
178 *aWidth
= mDelayedResize
.width
;
179 *aHeight
= mDelayedResize
.height
;
189 void nsViewManager::DoSetWindowDimensions(nscoord aWidth
, nscoord aHeight
)
191 nsRect oldDim
= mRootView
->GetDimensions();
192 nsRect
newDim(0, 0, aWidth
, aHeight
);
193 // We care about resizes even when one dimension is already zero.
194 if (!oldDim
.IsEqualEdges(newDim
)) {
195 // Don't resize the widget. It is already being set elsewhere.
196 mRootView
->SetDimensions(newDim
, true, false);
198 mPresShell
->ResizeReflow(aWidth
, aHeight
);
203 nsViewManager::SetWindowDimensions(nscoord aWidth
, nscoord aHeight
)
206 if (mRootView
->IsEffectivelyVisible() && mPresShell
&& mPresShell
->IsVisible()) {
207 if (mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
) &&
208 mDelayedResize
!= nsSize(aWidth
, aHeight
)) {
209 // We have a delayed resize; that now obsolete size may already have
210 // been flushed to the PresContext so we need to update the PresContext
211 // with the new size because if the new size is exactly the same as the
212 // root view's current size then DoSetWindowDimensions will not
213 // request a resize reflow (which would correct it). See bug 617076.
214 mDelayedResize
= nsSize(aWidth
, aHeight
);
215 FlushDelayedResize(false);
217 mDelayedResize
.SizeTo(NSCOORD_NONE
, NSCOORD_NONE
);
218 DoSetWindowDimensions(aWidth
, aHeight
);
220 mDelayedResize
.SizeTo(aWidth
, aHeight
);
221 if (mPresShell
&& mPresShell
->GetDocument()) {
222 mPresShell
->GetDocument()->SetNeedStyleFlush();
229 nsViewManager::FlushDelayedResize(bool aDoReflow
)
231 if (mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
)) {
233 DoSetWindowDimensions(mDelayedResize
.width
, mDelayedResize
.height
);
234 mDelayedResize
.SizeTo(NSCOORD_NONE
, NSCOORD_NONE
);
235 } else if (mPresShell
) {
236 nsPresContext
* presContext
= mPresShell
->GetPresContext();
238 presContext
->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize
));
244 // Convert aIn from being relative to and in appunits of aFromView, to being
245 // relative to and in appunits of aToView.
246 static nsRegion
ConvertRegionBetweenViews(const nsRegion
& aIn
,
251 out
.MoveBy(aFromView
->GetOffsetTo(aToView
));
252 out
= out
.ConvertAppUnitsRoundOut(
253 aFromView
->GetViewManager()->AppUnitsPerDevPixel(),
254 aToView
->GetViewManager()->AppUnitsPerDevPixel());
258 nsView
* nsViewManager::GetDisplayRootFor(nsView
* aView
)
260 nsView
*displayRoot
= aView
;
262 nsView
*displayParent
= displayRoot
->GetParent();
266 if (displayRoot
->GetFloating() && !displayParent
->GetFloating())
269 // If we have a combobox dropdown popup within a panel popup, both the view
270 // for the dropdown popup and its parent will be floating, so we need to
271 // distinguish this situation. We do this by looking for a widget. Any view
272 // with a widget is a display root, except for plugins.
273 nsIWidget
* widget
= displayRoot
->GetWidget();
276 widget
->GetWindowType(type
);
277 if (type
== eWindowType_popup
) {
278 NS_ASSERTION(displayRoot
->GetFloating() && displayParent
->GetFloating(),
279 "this should only happen with floating views that have floating parents");
284 displayRoot
= displayParent
;
289 aRegion is given in device coordinates!!
290 aContext may be null, in which case layers should be used for
293 void nsViewManager::Refresh(nsView
*aView
, const nsIntRegion
& aRegion
)
295 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
297 // damageRegion is the damaged area, in twips, relative to the view origin
298 nsRegion damageRegion
= aRegion
.ToAppUnits(AppUnitsPerDevPixel());
299 // move region from widget coordinates into view coordinates
300 damageRegion
.MoveBy(-aView
->ViewToWidgetOffset());
302 if (damageRegion
.IsEmpty()) {
304 nsRect viewRect
= aView
->GetDimensions();
305 nsRect damageRect
= damageRegion
.GetBounds();
306 printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
307 damageRect
.x
, damageRect
.y
, damageRect
.width
, damageRect
.height
,
308 viewRect
.x
, viewRect
.y
, viewRect
.width
, viewRect
.height
);
313 nsIWidget
*widget
= aView
->GetWidget();
318 NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
320 RootViewManager()->mRecursiveRefreshPending
= true;
325 nsAutoScriptBlocker scriptBlocker
;
328 NS_ASSERTION(GetDisplayRootFor(aView
) == aView
,
329 "Widgets that we paint must all be display roots");
332 #ifdef MOZ_DUMP_PAINTING
333 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
334 printf("--COMPOSITE-- %p\n", mPresShell
);
337 uint32_t paintFlags
= nsIPresShell::PAINT_COMPOSITE
;
338 LayerManager
*manager
= widget
->GetLayerManager();
339 if (!manager
->NeedsWidgetInvalidation()) {
340 manager
->FlushRendering();
342 mPresShell
->Paint(aView
, damageRegion
,
345 #ifdef MOZ_DUMP_PAINTING
346 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
347 printf("--ENDCOMPOSITE--\n");
350 mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT
);
356 if (RootViewManager()->mRecursiveRefreshPending
) {
357 RootViewManager()->mRecursiveRefreshPending
= false;
358 InvalidateAllViews();
362 void nsViewManager::ProcessPendingUpdatesForView(nsView
* aView
,
363 bool aFlushDirtyRegion
)
365 NS_ASSERTION(IsRootVM(), "Updates will be missed");
367 // Protect against a null-view.
372 if (aView
->HasWidget()) {
373 aView
->ResetWidgetBounds(false, true);
376 // process pending updates in child view.
377 for (nsView
* childView
= aView
->GetFirstChild(); childView
;
378 childView
= childView
->GetNextSibling()) {
379 ProcessPendingUpdatesForView(childView
, aFlushDirtyRegion
);
382 // Push out updates after we've processed the children; ensures that
383 // damage is applied based on the final widget geometry
384 if (aFlushDirtyRegion
) {
385 nsIWidget
*widget
= aView
->GetWidget();
386 if (widget
&& widget
->NeedsPaint()) {
387 // If an ancestor widget was hidden and then shown, we could
388 // have a delayed resize to handle.
389 for (nsViewManager
*vm
= this; vm
;
390 vm
= vm
->mRootView
->GetParent()
391 ? vm
->mRootView
->GetParent()->GetViewManager()
393 if (vm
->mDelayedResize
!= nsSize(NSCOORD_NONE
, NSCOORD_NONE
) &&
394 vm
->mRootView
->IsEffectivelyVisible() &&
395 mPresShell
&& mPresShell
->IsVisible()) {
396 vm
->FlushDelayedResize(true);
400 NS_ASSERTION(aView
->HasWidget(), "Must have a widget!");
402 #ifdef MOZ_DUMP_PAINTING
403 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
404 printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell
, aView
, widget
);
407 nsAutoScriptBlocker scriptBlocker
;
408 NS_ASSERTION(aView
->HasWidget(), "Must have a widget!");
410 mPresShell
->Paint(aView
, nsRegion(),
411 nsIPresShell::PAINT_LAYERS
);
412 #ifdef MOZ_DUMP_PAINTING
413 if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
414 printf("---- PAINT END ----\n");
417 aView
->SetForcedRepaint(false);
419 FlushDirtyRegionToWidget(aView
);
421 FlushDirtyRegionToWidget(aView
);
426 void nsViewManager::FlushDirtyRegionToWidget(nsView
* aView
)
428 if (!aView
->HasNonEmptyDirtyRegion())
431 nsRegion
* dirtyRegion
= aView
->GetDirtyRegion();
432 nsView
* nearestViewWithWidget
= aView
;
433 while (!nearestViewWithWidget
->HasWidget() &&
434 nearestViewWithWidget
->GetParent()) {
435 nearestViewWithWidget
= nearestViewWithWidget
->GetParent();
438 ConvertRegionBetweenViews(*dirtyRegion
, aView
, nearestViewWithWidget
);
440 // If we draw the frame counter we need to make sure we invalidate the area
441 // for it to make it on screen
442 if (gfxPlatform::DrawFrameCounter()) {
443 nsRect counterBounds
= gfxPlatform::FrameCounterBounds().ToAppUnits(AppUnitsPerDevPixel());
444 r
= r
.Or(r
, counterBounds
);
447 nsViewManager
* widgetVM
= nearestViewWithWidget
->GetViewManager();
448 widgetVM
->InvalidateWidgetArea(nearestViewWithWidget
, r
);
449 dirtyRegion
->SetEmpty();
453 nsViewManager::InvalidateView(nsView
*aView
)
455 // Mark the entire view as damaged
456 InvalidateView(aView
, aView
->GetDimensions());
460 AddDirtyRegion(nsView
*aView
, const nsRegion
&aDamagedRegion
)
462 nsRegion
* dirtyRegion
= aView
->GetDirtyRegion();
466 dirtyRegion
->Or(*dirtyRegion
, aDamagedRegion
);
467 dirtyRegion
->SimplifyOutward(8);
471 nsViewManager::PostPendingUpdate()
473 nsViewManager
* rootVM
= RootViewManager();
474 rootVM
->mHasPendingWidgetGeometryChanges
= true;
475 if (rootVM
->mPresShell
) {
476 rootVM
->mPresShell
->ScheduleViewManagerFlush();
481 * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
482 * every widget child of aWidgetView, plus aWidgetView's own widget
485 nsViewManager::InvalidateWidgetArea(nsView
*aWidgetView
,
486 const nsRegion
&aDamagedRegion
)
488 NS_ASSERTION(aWidgetView
->GetViewManager() == this,
489 "InvalidateWidgetArea called on view we don't own");
490 nsIWidget
* widget
= aWidgetView
->GetWidget();
493 nsRect dbgBounds
= aDamagedRegion
.GetBounds();
494 printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
495 aWidgetView
, aWidgetView
->IsAttachedToTopLevel(),
496 widget
, dbgBounds
.x
, dbgBounds
.y
, dbgBounds
.width
, dbgBounds
.height
);
499 // If the widget is hidden, it don't cover nothing
500 if (widget
&& !widget
->IsVisible()) {
505 // The root view or a scrolling view might not have a widget
506 // (for example, during printing). We get here when we scroll
507 // during printing to show selected options in a listbox, for example.
511 // Update all child widgets with the damage. In the process,
512 // accumulate the union of all the child widget areas, or at least
513 // some subset of that.
515 if (widget
->GetTransparencyMode() != eTransparencyTransparent
) {
516 for (nsIWidget
* childWidget
= widget
->GetFirstChild();
518 childWidget
= childWidget
->GetNextSibling()) {
519 nsView
* view
= nsView::GetViewFor(childWidget
);
520 NS_ASSERTION(view
!= aWidgetView
, "will recur infinitely");
522 childWidget
->GetWindowType(type
);
523 if (view
&& childWidget
->IsVisible() && type
!= eWindowType_popup
) {
524 NS_ASSERTION(type
== eWindowType_plugin
,
525 "Only plugin or popup widgets can be children!");
527 // We do not need to invalidate in plugin widgets, but we should
528 // exclude them from the invalidation region IF we're not on
529 // Mac. On Mac we need to draw under plugin widgets, because
530 // plugin widgets are basically invisible
532 // GetBounds should compensate for chrome on a toplevel widget
534 childWidget
->GetBounds(bounds
);
536 nsTArray
<nsIntRect
> clipRects
;
537 childWidget
->GetWindowClipRegion(&clipRects
);
538 for (uint32_t i
= 0; i
< clipRects
.Length(); ++i
) {
539 nsRect rr
= (clipRects
[i
] + bounds
.TopLeft()).
540 ToAppUnits(AppUnitsPerDevPixel());
541 children
.Or(children
, rr
- aWidgetView
->ViewToWidgetOffset());
542 children
.SimplifyInward(20);
550 leftOver
.Sub(aDamagedRegion
, children
);
552 if (!leftOver
.IsEmpty()) {
554 for (nsRegionRectIterator
iter(leftOver
); (r
= iter
.Next());) {
555 nsIntRect bounds
= ViewToWidget(aWidgetView
, *r
);
556 widget
->Invalidate(bounds
);
562 ShouldIgnoreInvalidation(nsViewManager
* aVM
)
565 nsIPresShell
* shell
= aVM
->GetPresShell();
566 if (!shell
|| shell
->ShouldIgnoreInvalidation()) {
569 nsView
* view
= aVM
->GetRootView()->GetParent();
570 aVM
= view
? view
->GetViewManager() : nullptr;
576 nsViewManager::InvalidateView(nsView
*aView
, const nsRect
&aRect
)
578 // If painting is suppressed in the presshell or an ancestor drop all
579 // invalidates, it will invalidate everything when it unsuppresses.
580 if (ShouldIgnoreInvalidation(this)) {
584 InvalidateViewNoSuppression(aView
, aRect
);
588 nsViewManager::InvalidateViewNoSuppression(nsView
*aView
,
591 NS_PRECONDITION(nullptr != aView
, "null view");
593 NS_ASSERTION(aView
->GetViewManager() == this,
594 "InvalidateViewNoSuppression called on view we don't own");
596 nsRect
damagedRect(aRect
);
597 if (damagedRect
.IsEmpty()) {
601 nsView
* displayRoot
= GetDisplayRootFor(aView
);
602 nsViewManager
* displayRootVM
= displayRoot
->GetViewManager();
603 // Propagate the update to the displayRoot, since iframes, for example,
604 // can overlap each other and be translucent. So we have to possibly
605 // invalidate our rect in each of the widgets we have lying about.
606 damagedRect
.MoveBy(aView
->GetOffsetTo(displayRoot
));
607 int32_t rootAPD
= displayRootVM
->AppUnitsPerDevPixel();
608 int32_t APD
= AppUnitsPerDevPixel();
609 damagedRect
= damagedRect
.ConvertAppUnitsRoundOut(APD
, rootAPD
);
611 // accumulate this rectangle in the view's dirty region, so we can
613 AddDirtyRegion(displayRoot
, nsRegion(damagedRect
));
617 nsViewManager::InvalidateAllViews()
619 if (RootViewManager() != this) {
620 return RootViewManager()->InvalidateAllViews();
623 InvalidateViews(mRootView
);
626 void nsViewManager::InvalidateViews(nsView
*aView
)
628 // Invalidate this view.
629 InvalidateView(aView
);
631 // Invalidate all children as well.
632 nsView
* childView
= aView
->GetFirstChild();
633 while (nullptr != childView
) {
634 childView
->GetViewManager()->InvalidateViews(childView
);
635 childView
= childView
->GetNextSibling();
639 void nsViewManager::WillPaintWindow(nsIWidget
* aWidget
)
642 nsView
* view
= nsView::GetViewFor(aWidget
);
643 LayerManager
*manager
= aWidget
->GetLayerManager();
645 (view
->ForcedRepaint() || !manager
->NeedsWidgetInvalidation())) {
646 ProcessPendingUpdates();
647 // Re-get the view pointer here since the ProcessPendingUpdates might have
648 // destroyed it during CallWillPaintOnObservers.
649 view
= nsView::GetViewFor(aWidget
);
651 view
->SetForcedRepaint(false);
656 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
658 shell
->WillPaintWindow();
662 bool nsViewManager::PaintWindow(nsIWidget
* aWidget
, nsIntRegion aRegion
)
664 if (!aWidget
|| !mContext
)
667 NS_ASSERTION(IsPaintingAllowed(),
668 "shouldn't be receiving paint events while painting is disallowed!");
670 // Get the view pointer here since NS_WILL_PAINT might have
671 // destroyed it during CallWillPaintOnObservers (bug 378273).
672 nsView
* view
= nsView::GetViewFor(aWidget
);
673 if (view
&& !aRegion
.IsEmpty()) {
674 Refresh(view
, aRegion
);
680 void nsViewManager::DidPaintWindow()
682 nsCOMPtr
<nsIPresShell
> shell
= mPresShell
;
684 shell
->DidPaintWindow();
689 nsViewManager::DispatchEvent(nsGUIEvent
*aEvent
, nsView
* aView
, nsEventStatus
* aStatus
)
691 PROFILER_LABEL("event", "nsViewManager::DispatchEvent");
693 if ((NS_IS_MOUSE_EVENT(aEvent
) &&
694 // Ignore mouse events that we synthesize.
695 static_cast<nsMouseEvent
*>(aEvent
)->reason
== nsMouseEvent::eReal
&&
696 // Ignore mouse exit and enter (we'll get moves if the user
697 // is really moving the mouse) since we get them when we
698 // create and destroy widgets.
699 aEvent
->message
!= NS_MOUSE_EXIT
&&
700 aEvent
->message
!= NS_MOUSE_ENTER
) ||
701 NS_IS_KEY_EVENT(aEvent
) ||
702 NS_IS_IME_EVENT(aEvent
) ||
703 aEvent
->message
== NS_PLUGIN_INPUT_EVENT
) {
704 gLastUserEventTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
707 // Find the view whose coordinates system we're in.
708 nsView
* view
= aView
;
709 bool dispatchUsingCoordinates
= NS_IsEventUsingCoordinates(aEvent
);
710 if (dispatchUsingCoordinates
) {
711 // Will dispatch using coordinates. Pretty bogus but it's consistent
712 // with what presshell does.
713 view
= GetDisplayRootFor(view
);
716 // If the view has no frame, look for a view that does.
717 nsIFrame
* frame
= view
->GetFrame();
719 (dispatchUsingCoordinates
|| NS_IS_KEY_EVENT(aEvent
) ||
720 NS_IS_IME_RELATED_EVENT(aEvent
) ||
721 NS_IS_NON_RETARGETED_PLUGIN_EVENT(aEvent
) ||
722 aEvent
->message
== NS_PLUGIN_ACTIVATE
||
723 aEvent
->message
== NS_PLUGIN_FOCUS
||
724 aEvent
->message
== NS_PLUGIN_RESOLUTION_CHANGED
)) {
725 while (view
&& !view
->GetFrame()) {
726 view
= view
->GetParent();
730 frame
= view
->GetFrame();
734 if (nullptr != frame
) {
735 // Hold a refcount to the presshell. The continued existence of the
736 // presshell will delay deletion of this view hierarchy should the event
737 // want to cause its destruction in, say, some JavaScript event handler.
738 nsCOMPtr
<nsIPresShell
> shell
= view
->GetViewManager()->GetPresShell();
740 shell
->HandleEvent(frame
, aEvent
, false, aStatus
);
745 *aStatus
= nsEventStatus_eIgnore
;
748 // Recursively reparent widgets if necessary
750 void nsViewManager::ReparentChildWidgets(nsView
* aView
, nsIWidget
*aNewWidget
)
752 NS_PRECONDITION(aNewWidget
, "");
754 if (aView
->HasWidget()) {
755 // Check to see if the parent widget is the
756 // same as the new parent. If not then reparent
757 // the widget, otherwise there is nothing more
758 // to do for the view and its descendants
759 nsIWidget
* widget
= aView
->GetWidget();
760 nsIWidget
* parentWidget
= widget
->GetParent();
763 if (parentWidget
!= aNewWidget
) {
767 widget
->SetParent(aNewWidget
);
768 NS_ASSERTION(NS_SUCCEEDED(rv
), "SetParent failed!");
771 // Toplevel widget (popup, dialog, etc)
772 widget
->ReparentNativeWidget(aNewWidget
);
777 // Need to check each of the views children to see
778 // if they have a widget and reparent it.
780 for (nsView
*kid
= aView
->GetFirstChild(); kid
; kid
= kid
->GetNextSibling()) {
781 ReparentChildWidgets(kid
, aNewWidget
);
785 // Reparent a view and its descendant views widgets if necessary
787 void nsViewManager::ReparentWidgets(nsView
* aView
, nsView
*aParent
)
789 NS_PRECONDITION(aParent
, "Must have a parent");
790 NS_PRECONDITION(aView
, "Must have a view");
792 // Quickly determine whether the view has pre-existing children or a
793 // widget. In most cases the view will not have any pre-existing
794 // children when this is called. Only in the case
795 // where a view has been reparented by removing it from
796 // a reinserting it into a new location in the view hierarchy do we
797 // have to consider reparenting the existing widgets for the view and
799 if (aView
->HasWidget() || aView
->GetFirstChild()) {
800 nsIWidget
* parentWidget
= aParent
->GetNearestWidget(nullptr);
802 ReparentChildWidgets(aView
, parentWidget
);
805 NS_WARNING("Can not find a widget for the parent view");
810 nsViewManager::InsertChild(nsView
*aParent
, nsView
*aChild
, nsView
*aSibling
,
813 NS_PRECONDITION(nullptr != aParent
, "null ptr");
814 NS_PRECONDITION(nullptr != aChild
, "null ptr");
815 NS_ASSERTION(aSibling
== nullptr || aSibling
->GetParent() == aParent
,
816 "tried to insert view with invalid sibling");
817 NS_ASSERTION(!IsViewInserted(aChild
), "tried to insert an already-inserted view");
819 if ((nullptr != aParent
) && (nullptr != aChild
))
821 // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
822 // order, otherwise after 'kid' (i.e. before 'kid' in document order).
824 if (nullptr == aSibling
) {
826 // insert at end of document order, i.e., before first view
827 // this is the common case, by far
828 aParent
->InsertChild(aChild
, nullptr);
829 ReparentWidgets(aChild
, aParent
);
831 // insert at beginning of document order, i.e., after last view
832 nsView
*kid
= aParent
->GetFirstChild();
833 nsView
*prev
= nullptr;
836 kid
= kid
->GetNextSibling();
838 // prev is last view or null if there are no children
839 aParent
->InsertChild(aChild
, prev
);
840 ReparentWidgets(aChild
, aParent
);
843 nsView
*kid
= aParent
->GetFirstChild();
844 nsView
*prev
= nullptr;
845 while (kid
&& aSibling
!= kid
) {
846 //get the next sibling view
848 kid
= kid
->GetNextSibling();
850 NS_ASSERTION(kid
!= nullptr,
851 "couldn't find sibling in child list");
853 // insert after 'kid' in document order, i.e. before in view order
854 aParent
->InsertChild(aChild
, prev
);
855 ReparentWidgets(aChild
, aParent
);
857 // insert before 'kid' in document order, i.e. after in view order
858 aParent
->InsertChild(aChild
, kid
);
859 ReparentWidgets(aChild
, aParent
);
863 // if the parent view is marked as "floating", make the newly added view float as well.
864 if (aParent
->GetFloating())
865 aChild
->SetFloating(true);
870 nsViewManager::InsertChild(nsView
*aParent
, nsView
*aChild
, int32_t aZIndex
)
872 // no-one really calls this with anything other than aZIndex == 0 on a fresh view
873 // XXX this method should simply be eliminated and its callers redirected to the real method
874 SetViewZIndex(aChild
, false, aZIndex
);
875 InsertChild(aParent
, aChild
, nullptr, true);
879 nsViewManager::RemoveChild(nsView
*aChild
)
881 NS_ASSERTION(aChild
, "aChild must not be null");
883 nsView
* parent
= aChild
->GetParent();
885 if (nullptr != parent
) {
886 NS_ASSERTION(aChild
->GetViewManager() == this ||
887 parent
->GetViewManager() == this, "wrong view manager");
888 parent
->RemoveChild(aChild
);
893 nsViewManager::MoveViewTo(nsView
*aView
, nscoord aX
, nscoord aY
)
895 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
896 aView
->SetPosition(aX
, aY
);
900 nsViewManager::ResizeView(nsView
*aView
, const nsRect
&aRect
, bool aRepaintExposedAreaOnly
)
902 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
904 nsRect oldDimensions
= aView
->GetDimensions();
905 if (!oldDimensions
.IsEqualEdges(aRect
)) {
906 aView
->SetDimensions(aRect
, true);
909 // Note that if layout resizes the view and the view has a custom clip
910 // region set, then we expect layout to update the clip region too. Thus
911 // in the case where mClipRect has been optimized away to just be a null
912 // pointer, and this resize is implicitly changing the clip rect, it's OK
913 // because layout will change it back again if necessary.
917 nsViewManager::SetViewFloating(nsView
*aView
, bool aFloating
)
919 NS_ASSERTION(!(nullptr == aView
), "no view");
921 aView
->SetFloating(aFloating
);
925 nsViewManager::SetViewVisibility(nsView
*aView
, nsViewVisibility aVisible
)
927 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
929 if (aVisible
!= aView
->GetVisibility()) {
930 aView
->SetVisibility(aVisible
);
934 bool nsViewManager::IsViewInserted(nsView
*aView
)
936 if (mRootView
== aView
) {
938 } else if (aView
->GetParent() == nullptr) {
941 nsView
* view
= aView
->GetParent()->GetFirstChild();
942 while (view
!= nullptr) {
946 view
= view
->GetNextSibling();
953 nsViewManager::SetViewZIndex(nsView
*aView
, bool aAutoZIndex
, int32_t aZIndex
)
955 NS_ASSERTION((aView
!= nullptr), "no view");
957 // don't allow the root view's z-index to be changed. It should always be zero.
958 // This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
959 if (aView
== mRootView
) {
967 aView
->SetZIndex(aAutoZIndex
, aZIndex
);
971 nsViewManager::IncrementDisableRefreshCount()
974 return RootViewManager()->IncrementDisableRefreshCount();
977 ++mRefreshDisableCount
;
983 nsViewManager::DecrementDisableRefreshCount()
985 NS_ASSERTION(IsRootVM(), "Should only be called on root");
986 --mRefreshDisableCount
;
987 NS_ASSERTION(mRefreshDisableCount
>= 0, "Invalid refresh disable count!");
991 nsViewManager::GetRootWidget(nsIWidget
**aWidget
)
997 if (mRootView
->HasWidget()) {
998 *aWidget
= mRootView
->GetWidget();
1002 if (mRootView
->GetParent()) {
1003 mRootView
->GetParent()->GetViewManager()->GetRootWidget(aWidget
);
1009 nsIntRect
nsViewManager::ViewToWidget(nsView
*aView
, const nsRect
&aRect
) const
1011 NS_ASSERTION(aView
->GetViewManager() == this, "wrong view manager");
1013 // account for the view's origin not lining up with the widget's
1014 nsRect rect
= aRect
+ aView
->ViewToWidgetOffset();
1016 // finally, convert to device coordinates.
1017 return rect
.ToOutsidePixels(AppUnitsPerDevPixel());
1021 nsViewManager::IsPainting(bool& aIsPainting
)
1023 aIsPainting
= IsPainting();
1027 nsViewManager::ProcessPendingUpdates()
1030 RootViewManager()->ProcessPendingUpdates();
1034 mPresShell
->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
1036 // Flush things like reflows by calling WillPaint on observer presShells.
1038 CallWillPaintOnObservers();
1040 ProcessPendingUpdatesForView(mRootView
, true);
1044 nsViewManager::UpdateWidgetGeometry()
1047 RootViewManager()->UpdateWidgetGeometry();
1051 if (mHasPendingWidgetGeometryChanges
) {
1052 mHasPendingWidgetGeometryChanges
= false;
1053 ProcessPendingUpdatesForView(mRootView
, false);
1058 nsViewManager::CallWillPaintOnObservers()
1060 NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
1063 for (index
= 0; index
< mVMCount
; index
++) {
1064 nsViewManager
* vm
= (nsViewManager
*)gViewManagers
->ElementAt(index
);
1065 if (vm
->RootViewManager() == this) {
1067 if (vm
->mRootView
&& vm
->mRootView
->IsEffectivelyVisible()) {
1068 nsCOMPtr
<nsIPresShell
> shell
= vm
->GetPresShell();
1078 nsViewManager::GetLastUserEventTime(uint32_t& aTime
)
1080 aTime
= gLastUserEventTime
;
1084 nsViewManager::InvalidateHierarchy()
1088 NS_RELEASE(mRootViewManager
);
1090 nsView
*parent
= mRootView
->GetParent();
1092 mRootViewManager
= parent
->GetViewManager()->RootViewManager();
1093 NS_ADDREF(mRootViewManager
);
1094 NS_ASSERTION(mRootViewManager
!= this,
1095 "Root view had a parent, but it has the same view manager");
1097 mRootViewManager
= this;