Bug 1924240 - Devirtualize parent handling. r=mac-reviewers,win-reviewers,geckoview-reviewers,bradwerth,m_kato,rkraesig

Move mParent to nsIWidget.h along with kids and so on. Instead of
ReparentNativeWidget add a more general DidChangeParent method.

Make mParent weak to prevent cycles. These are broken on Destroy() but
it feels kinda silly, and we were inconsistent before I started this
effort so pretty sure it can be done.

Differential Revision: https://phabricator.services.mozilla.com/D225796
This commit is contained in:
Emilio Cobos Álvarez
2024-10-22 20:25:18 +00:00
parent 3c28d81d6b
commit 8955f5a673
18 changed files with 136 additions and 428 deletions

View File

@@ -662,21 +662,13 @@ void nsViewManager::DispatchEvent(WidgetGUIEvent* aEvent, nsView* aView,
void nsViewManager::ReparentChildWidgets(nsView* aView, nsIWidget* aNewWidget) {
MOZ_ASSERT(aNewWidget, "null widget");
if (aView->HasWidget()) {
if (nsIWidget* widget = aView->GetWidget()) {
// Check to see if the parent widget is the
// same as the new parent. If not then reparent
// the widget, otherwise there is nothing more
// to do for the view and its descendants
nsIWidget* widget = aView->GetWidget();
nsIWidget* parentWidget = widget->GetParent();
if (parentWidget) {
// Child widget
if (parentWidget != aNewWidget) {
widget->SetParent(aNewWidget);
}
} else {
// Toplevel widget (popup, dialog, etc)
widget->ReparentNativeWidget(aNewWidget);
if (widget->GetParent() != aNewWidget) {
widget->SetParent(aNewWidget);
}
return;
}

View File

@@ -96,26 +96,15 @@ PuppetWidget::~PuppetWidget() { Destroy(); }
void PuppetWidget::InfallibleCreate(nsIWidget* aParent,
const LayoutDeviceIntRect& aRect,
widget::InitData* aInitData) {
// FIXME(emilio): Why aParent = nullptr? Can we even get here with non-null
// aParent?
BaseCreate(/* aParent = */ nullptr, aInitData);
BaseCreate(aParent, aInitData);
mBounds = aRect;
mEnabled = true;
mVisible = true;
mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
IntSize(1, 1), SurfaceFormat::B8G8R8A8);
mNeedIMEStateInit = MightNeedIMEFocus(aInitData);
PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
if (parent) {
parent->SetChild(this);
mWindowRenderer = parent->GetWindowRenderer();
} else {
Resize(mBounds.X(), mBounds.Y(), mBounds.Width(), mBounds.Height(), false);
}
Resize(mBounds.X(), mBounds.Y(), mBounds.Width(), mBounds.Height(), false);
mMemoryPressureObserver = MemoryPressureObserver::Create(this);
}
@@ -148,7 +137,6 @@ void PuppetWidget::Destroy() {
mMemoryPressureObserver->Unregister();
mMemoryPressureObserver = nullptr;
}
mChild = nullptr;
if (mWindowRenderer) {
mWindowRenderer->Destroy();
}
@@ -163,10 +151,6 @@ void PuppetWidget::Show(bool aState) {
bool wasVisible = mVisible;
mVisible = aState;
if (mChild) {
mChild->mVisible = aState;
}
if (!wasVisible && mVisible) {
// The previously attached widget listener is handy if
// we're transitioning from page to page without dropping
@@ -187,11 +171,6 @@ void PuppetWidget::Resize(double aWidth, double aHeight, bool aRepaint) {
mBounds.SizeTo(
LayoutDeviceIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight)));
if (mChild) {
mChild->Resize(aWidth, aHeight, aRepaint);
return;
}
// XXX: roc says that |aRepaint| dictates whether or not to
// invalidate the expanded area
if (oldBounds.Size() < mBounds.Size() && aRepaint) {
@@ -225,11 +204,6 @@ void PuppetWidget::Invalidate(const LayoutDeviceIntRect& aRect) {
debug_DumpInvalidate(stderr, this, &aRect, "PuppetWidget", 0);
#endif
if (mChild) {
mChild->Invalidate(aRect);
return;
}
if (mBrowserChild && !aRect.IsEmpty() && !mWidgetPaintTask.IsPending()) {
mWidgetPaintTask = new WidgetPaintTask(this);
nsCOMPtr<nsIRunnable> event(mWidgetPaintTask.get());
@@ -262,9 +236,6 @@ nsresult PuppetWidget::DispatchEvent(WidgetGUIEvent* aEvent,
debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "PuppetWidget", 0);
#endif
MOZ_ASSERT(!mChild || mChild->mWindowType == WindowType::Popup,
"Unexpected event dispatch!");
MOZ_ASSERT(!aEvent->AsKeyboardEvent() ||
aEvent->mFlags.mIsSynthesizedForTests ||
aEvent->AsKeyboardEvent()->AreAllEditCommandsInitialized(),
@@ -937,14 +908,6 @@ void PuppetWidget::SetCursor(const Cursor& aCursor) {
mUpdateCursor = false;
}
void PuppetWidget::SetChild(PuppetWidget* aChild) {
MOZ_ASSERT(this != aChild, "can't parent a widget to itself");
MOZ_ASSERT(!aChild->mChild,
"fake widget 'hierarchy' only expected to have one level");
mChild = aChild;
}
NS_IMETHODIMP
PuppetWidget::WidgetPaintTask::Run() {
if (mWidget) {

View File

@@ -303,8 +303,6 @@ class PuppetWidget final : public nsBaseWidget,
private:
void Paint();
void SetChild(PuppetWidget* aChild);
nsresult RequestIMEToCommitComposition(bool aCancel);
nsresult NotifyIMEOfFocusChange(const IMENotification& aIMENotification);
nsresult NotifyIMEOfSelectionChange(const IMENotification& aIMENotification);
@@ -347,14 +345,8 @@ class PuppetWidget final : public nsBaseWidget,
// it's possible for BrowserChild to outlive the PuppetWidget, we clear
// this weak reference in Destroy()
BrowserChild* mBrowserChild;
// The "widget" to which we delegate events if we don't have an
// event handler.
RefPtr<PuppetWidget> mChild;
nsRevocableEventPtr<WidgetPaintTask> mWidgetPaintTask;
RefPtr<layers::MemoryPressureObserver> mMemoryPressureObserver;
// XXX/cjones: keeping this around until we teach LayerManager to do
// retained-content-only transactions
RefPtr<DrawTarget> mDrawTarget;
// IME
IMENotificationRequests mIMENotificationRequestsOfParent;
InputContext mInputContext;

View File

@@ -2169,7 +2169,7 @@ void nsWindow::LogWindow(nsWindow* win, int index, int indent) {
char spaces[] = " ";
spaces[indent < 20 ? indent : 20] = 0;
ALOG("%s [% 2d] 0x%p [parent 0x%p] [% 3d,% 3dx% 3d,% 3d] vis %d type %d",
spaces, index, win, win->mParent.get(), win->mBounds.x, win->mBounds.y,
spaces, index, win, win->mParent, win->mBounds.x, win->mBounds.y,
win->mBounds.width, win->mBounds.height, win->mIsVisible,
int(win->mWindowType));
int i = 0;
@@ -2226,7 +2226,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
aInitData->mWindowType != WindowType::Invisible);
BaseCreate(aParent, aInitData);
mParent = static_cast<nsWindow*>(aParent);
MOZ_ASSERT_IF(!IsTopLevel(), aParent);
if (IsTopLevel()) {
@@ -2251,13 +2250,7 @@ void nsWindow::Destroy() {
// Stuff below may release the last ref to this
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
while (RefPtr<nsWindow> kid = static_cast<nsWindow*>(mLastChild)) {
// why do we still have children?
ALOG("### Warning: Destroying window %p and reparenting child %p to null!",
this, kid.get());
RemoveChild(kid);
kid->mParent = nullptr;
}
RemoveAllChildren();
// Ensure the compositor has been shutdown before this nsWindow is potentially
// deleted
@@ -2265,9 +2258,9 @@ void nsWindow::Destroy() {
nsBaseWidget::Destroy();
if (IsTopLevel()) gTopLevelWindows.RemoveElement(this);
SetParent(nullptr);
if (IsTopLevel()) {
gTopLevelWindows.RemoveElement(this);
}
nsBaseWidget::OnDestroy();
@@ -2311,27 +2304,13 @@ void nsWindow::OnGeckoViewReady() {
acc->OnReady();
}
void nsWindow::SetParent(nsIWidget* aNewParent) {
if (mParent == aNewParent) {
return;
}
if (mParent) {
mParent->RemoveChild(this);
}
mParent = static_cast<nsWindow*>(aNewParent);
if (mParent) {
mParent->AddChild(this);
}
void nsWindow::DidChangeParent(nsIWidget*) {
// if we are now in the toplevel window's hierarchy, schedule a redraw
if (FindTopLevel() == nsWindow::TopWindow()) RedrawAll();
if (FindTopLevel() == nsWindow::TopWindow()) {
RedrawAll();
}
}
nsIWidget* nsWindow::GetParent() { return mParent; }
RefPtr<MozPromise<bool, bool, false>> nsWindow::OnLoadRequest(
nsIURI* aUri, int32_t aWindowType, int32_t aFlags,
nsIPrincipal* aTriggeringPrincipal, bool aHasUserGesture,
@@ -2523,9 +2502,10 @@ void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {}
nsWindow* nsWindow::FindTopLevel() {
nsWindow* toplevel = this;
while (toplevel) {
if (toplevel->IsTopLevel()) return toplevel;
toplevel = toplevel->mParent;
if (toplevel->IsTopLevel()) {
return toplevel;
}
toplevel = static_cast<nsWindow*>(toplevel->mParent);
}
ALOG(
@@ -2586,10 +2566,8 @@ LayoutDeviceIntRect nsWindow::GetScreenBounds() {
LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
LayoutDeviceIntPoint p(0, 0);
for (nsWindow* w = this; !!w; w = w->mParent) {
p.x += w->mBounds.x;
p.y += w->mBounds.y;
for (nsWindow* w = this; !!w; w = static_cast<nsWindow*>(w->mParent)) {
p += w->mBounds.TopLeft();
if (w->IsTopLevel()) {
break;
}
@@ -3080,8 +3058,7 @@ nsresult nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
const auto& npzc = npzcSup->GetJavaNPZC();
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
aPoint -= bounds.TopLeft();
DispatchToUiThread(
"nsWindow::SynthesizeNativeTouchPoint",
@@ -3106,8 +3083,7 @@ nsresult nsWindow::SynthesizeNativeMouseEvent(
const auto& npzc = npzcSup->GetJavaNPZC();
const auto& bounds = FindTopLevel()->mBounds;
aPoint.x -= bounds.x;
aPoint.y -= bounds.y;
aPoint -= bounds.TopLeft();
int32_t nativeMessage;
switch (aNativeMessage) {

View File

@@ -71,7 +71,6 @@ class nsWindow final : public nsBaseWidget {
bool aIsTopLevel);
private:
RefPtr<nsWindow> mParent;
nsCOMPtr<nsIUserIdleServiceInternal> mIdleService;
mozilla::ScreenIntCoord mDynamicToolbarMaxHeight{0};
mozilla::ScreenIntMargin mSafeAreaInsets;
@@ -159,8 +158,7 @@ class nsWindow final : public nsBaseWidget {
const LayoutDeviceIntRect& aRect,
InitData* aInitData) override;
void Destroy() override;
void SetParent(nsIWidget* aNewParent) override;
nsIWidget* GetParent(void) override;
void DidChangeParent(nsIWidget* aNewParent) override;
float GetDPI() override;
double GetDefaultScaleInternal() override;
void Show(bool aState) override;

View File

@@ -304,8 +304,6 @@ class nsChildView final : public nsBaseWidget {
void Show(bool aState) override;
bool IsVisible() const override;
void SetParent(nsIWidget* aNewParent) override;
nsIWidget* GetParent() override;
float GetDPI() override;
void Move(double aX, double aY) override;
@@ -463,8 +461,6 @@ class nsChildView final : public nsBaseWidget {
const bool aIsVertical,
const LayoutDeviceIntPoint& aPoint) override;
void ResetParent();
static bool DoHasPendingInputEvent();
static uint32_t GetCurrentInputEventCount();
static void UpdateCurrentInputEventCount();
@@ -473,7 +469,7 @@ class nsChildView final : public nsBaseWidget {
nsCocoaWindow* GetAppWindowWidget() const;
void ReparentNativeWidget(nsIWidget* aNewParent) override;
void DidChangeParent(nsIWidget*) override;
mozilla::widget::TextInputHandler* GetTextInputHandler() {
return mTextInputHandler;
@@ -562,7 +558,6 @@ class nsChildView final : public nsBaseWidget {
InputContext mInputContext;
NSView* mParentView;
nsCOMPtr<nsIWidget> mParentWidget;
#ifdef ACCESSIBILITY
// weak ref to this childview's associated mozAccessible for speed reasons

View File

@@ -228,22 +228,7 @@ nsChildView::nsChildView()
mIsDispatchPaint(false) {}
nsChildView::~nsChildView() {
// Notify the children that we're gone. childView->ResetParent() can change
// our list of children while it's being iterated, so the way we iterate the
// list must allow for this.
for (nsIWidget* kid = mLastChild; kid;) {
const WindowType kidType = kid->GetWindowType();
if (kidType == WindowType::Child) {
RefPtr<nsChildView> childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent();
} else {
RefPtr<nsCocoaWindow> childWindow = static_cast<nsCocoaWindow*>(kid);
kid = kid->GetPrevSibling();
RemoveChild(childWindow);
childWindow->mParent = nullptr;
}
}
RemoveAllChildren();
NS_WARNING_ASSERTION(
mOnDestroyCalled,
@@ -263,7 +248,7 @@ nsChildView::~nsChildView() {
// mGeckoChild are used throughout the ChildView class to tell if it's safe
// to use a ChildView object.
[mView widgetDestroyed]; // Safe if mView is nil.
mParentWidget = nil;
SetParent(nullptr);
TearDownView(); // Safe if called twice.
}
@@ -284,14 +269,8 @@ nsresult nsChildView::Create(nsIWidget* aParent,
BaseCreate(aParent, aInitData);
mParentWidget = nil;
mParentView = nil;
if (aParent) {
// This is the popup window case. aParent is the nsCocoaWindow for the
// popup window, and mParentView will be its content view.
mParentWidget = aParent;
mParentView = (NSView*)aParent->GetNativeData(NS_NATIVE_WIDGET);
}
mParentView =
mParent ? (NSView*)mParent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
// create our parallel NSView and hook it up to our parent. Recall
// that NS_NATIVE_WIDGET is the NSView.
@@ -305,10 +284,11 @@ nsresult nsChildView::Create(nsIWidget* aParent,
// If this view was created in a Gecko view hierarchy, the initial state
// is hidden. If the view is attached only to a native NSView but has
// no Gecko parent (as in embedding), the initial state is visible.
if (mParentWidget)
if (mParent) {
[mView setHidden:YES];
else
} else {
mVisible = true;
}
// Hook it up in the NSView hierarchy.
if (mParentView) {
@@ -317,8 +297,9 @@ nsresult nsChildView::Create(nsIWidget* aParent,
// if this is a ChildView, make sure that our per-window data
// is set up
if ([mView isKindOfClass:[ChildView class]])
if ([mView isKindOfClass:[ChildView class]]) {
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:[mView window]];
}
NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed");
mTextInputHandler = new TextInputHandler(this, mView);
@@ -394,7 +375,6 @@ void nsChildView::Destroy() {
nsBaseWidget::Destroy();
NotifyWindowDestroyed();
mParentWidget = nil;
TearDownView();
@@ -543,62 +523,27 @@ void nsChildView::Show(bool aState) {
}
// Change the parent of this widget
void nsChildView::SetParent(nsIWidget* aNewParent) {
void nsChildView::DidChangeParent(nsIWidget*) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (mOnDestroyCalled) return;
if (mOnDestroyCalled) {
return;
}
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
if (mParentWidget) {
mParentWidget->RemoveChild(this);
}
if (aNewParent) {
ReparentNativeWidget(aNewParent);
} else {
[mView removeFromSuperview];
mParentView = nil;
}
mParentWidget = aNewParent;
if (mParentWidget) {
mParentWidget->AddChild(this);
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
}
void nsChildView::ReparentNativeWidget(nsIWidget* aNewParent) {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
MOZ_ASSERT(aNewParent, "null widget");
if (mOnDestroyCalled) return;
NSView<mozView>* newParentView =
(NSView<mozView>*)aNewParent->GetNativeData(NS_NATIVE_WIDGET);
NS_ENSURE_TRUE_VOID(newParentView);
// we hold a ref to mView, so this is safe
[mView removeFromSuperview];
mParentView = newParentView;
[mParentView addSubview:mView];
mParentView = mParent
? (NSView<mozView>*)mParent->GetNativeData(NS_NATIVE_WIDGET)
: nullptr;
if (mParentView) {
[mParentView addSubview:mView];
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
}
void nsChildView::ResetParent() {
if (!mOnDestroyCalled) {
if (mParentWidget) mParentWidget->RemoveChild(this);
if (mView) [mView removeFromSuperview];
}
mParentWidget = nullptr;
}
nsIWidget* nsChildView::GetParent() { return mParentWidget; }
float nsChildView::GetDPI() {
float dpi = 96.0;
nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
@@ -653,7 +598,7 @@ LayoutDeviceIntRect nsChildView::GetBounds() {
LayoutDeviceIntRect nsChildView::GetClientBounds() {
LayoutDeviceIntRect rect = GetBounds();
if (!mParentWidget) {
if (!mParent) {
// For top level widgets we want the position on screen, not the position
// of this view inside the window.
rect.MoveTo(WidgetToScreenOffset());
@@ -1293,7 +1238,7 @@ nsresult nsChildView::DispatchEvent(WidgetGUIEvent* event,
// If the listener is NULL, check if the parent is a popup. If it is, then
// this child is the popup content view attached to a popup. Get the
// listener from the parent popup instead.
nsCOMPtr<nsIWidget> parentWidget = mParentWidget;
nsCOMPtr<nsIWidget> parentWidget = mParent;
if (!listener && parentWidget) {
if (parentWidget->GetWindowType() == WindowType::Popup) {
// Check just in case event->mWidget isn't this widget
@@ -1314,11 +1259,10 @@ nsresult nsChildView::DispatchEvent(WidgetGUIEvent* event,
nsIWidget* nsChildView::GetWidgetForListenerEvents() {
// If there is no listener, use the parent popup's listener if that exists.
if (!mWidgetListener && mParentWidget &&
mParentWidget->GetWindowType() == WindowType::Popup) {
return mParentWidget;
if (!mWidgetListener && mParent &&
mParent->GetWindowType() == WindowType::Popup) {
return mParent;
}
return this;
}

View File

@@ -323,9 +323,6 @@ class nsCocoaWindow final : public nsBaseWidget {
void SetPopupWindowLevel();
nsIWidget* GetParent() override { return mParent; }
void SetParent(nsIWidget*) override;
bool InFullScreenMode() const { return mInFullScreenMode; }
void PauseOrResumeCompositor(bool aPause) override;
@@ -381,7 +378,6 @@ class nsCocoaWindow final : public nsBaseWidget {
return nsIWidget::CreateTopLevelWindow();
}
nsCOMPtr<nsIWidget> mParent;
BaseWindow* mWindow; // our cocoa window [STRONG]
WindowDelegate*
mDelegate; // our delegate for processing window msgs [STRONG]

View File

@@ -120,8 +120,7 @@ static void RollUpPopups(nsIRollupListener::AllowAnimations aAllowAnimations =
}
nsCocoaWindow::nsCocoaWindow()
: mParent(nullptr),
mWindow(nil),
: mWindow(nil),
mDelegate(nil),
mPopupContentView(nil),
mFullscreenTransitionAnimation(nil),
@@ -188,25 +187,7 @@ void nsCocoaWindow::DestroyNativeWindow() {
nsCocoaWindow::~nsCocoaWindow() {
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
// Notify the children that we're gone. Popup windows (e.g. tooltips) can
// have nsChildView children. 'kid' is an nsChildView object if and only if
// its 'type' is 'WindowType::Child'.
// childView->ResetParent() can change our list of children while it's
// being iterated, so the way we iterate the list must allow for this.
for (nsIWidget* kid = mLastChild; kid;) {
const WindowType kidType = kid->GetWindowType();
if (kidType == WindowType::Child) {
RefPtr<nsChildView> childView = static_cast<nsChildView*>(kid);
kid = kid->GetPrevSibling();
childView->ResetParent();
} else {
RefPtr<nsCocoaWindow> childWindow = static_cast<nsCocoaWindow*>(kid);
kid = kid->GetPrevSibling();
RemoveChild(childWindow);
childWindow->mParent = nullptr;
}
}
RemoveAllChildren();
if (mWindow && mWindowMadeHere) {
CancelAllTransitions();
DestroyNativeWindow();
@@ -275,7 +256,6 @@ nsresult nsCocoaWindow::Create(nsIWidget* aParent, const DesktopIntRect& aRect,
Inherited::BaseCreate(aParent, aInitData);
mParent = aParent;
mAlwaysOnTop = aInitData->mAlwaysOnTop;
mIsAlert = aInitData->mIsAlert;
@@ -590,7 +570,6 @@ void nsCocoaWindow::Destroy() {
nsBaseWidget::OnDestroy();
nsBaseWidget::Destroy();
mParent = nullptr;
}
void* nsCocoaWindow::GetNativeData(uint32_t aDataType) {
@@ -686,7 +665,7 @@ void nsCocoaWindow::SetModal(bool aModal) {
// incompatible with the modal event loop in AppWindow::ShowModal() (each of
// these event loops is "exclusive", and can't run at the same time as other
// (similar) event loops).
for (auto* ancestorWidget = mParent.get(); ancestorWidget;
for (auto* ancestorWidget = mParent; ancestorWidget;
ancestorWidget = ancestorWidget->GetParent()) {
if (ancestorWidget->GetWindowType() == WindowType::Child) {
continue;
@@ -879,20 +858,6 @@ bool nsCocoaWindow::NeedsRecreateToReshow() {
NSScreen.screens.count > 1;
}
void nsCocoaWindow::SetParent(nsIWidget* aNewParent) {
// TODO(emilio): Do we need to reparent the native widget? We never did...
if (mParent) {
mParent->RemoveChild(this);
}
mParent = aNewParent;
if (mParent) {
mParent->AddChild(this);
}
}
WindowRenderer* nsCocoaWindow::GetWindowRenderer() {
if (mPopupContentView) {
return mPopupContentView->GetWindowRenderer();

View File

@@ -560,7 +560,8 @@ void nsWindow::OnDestroy(void) {
// Remove association between this object and its parent and siblings.
nsBaseWidget::Destroy();
mParent = nullptr;
RemoveAllChildren();
NotifyWindowDestroyed();
}
@@ -667,8 +668,6 @@ void nsWindow::Destroy() {
OnDestroy();
}
nsIWidget* nsWindow::GetParent() { return mParent; }
float nsWindow::GetDPI() {
float dpi = 96.0f;
nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
@@ -719,41 +718,6 @@ DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScaleByScreen() {
return nsBaseWidget::GetDesktopToDeviceScale();
}
// Reparent a child window to a new parent.
void nsWindow::SetParent(nsIWidget* aNewParent) {
LOG("nsWindow::SetParent() new parent %p", aNewParent);
if (!mIsChildWindow) {
NS_WARNING("Used by child widgets only");
return;
}
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
if (mParent) {
mParent->RemoveChild(this);
}
mParent = aNewParent;
// We're already deleted, quit.
if (!mGdkWindow || mIsDestroyed || !aNewParent) {
return;
}
aNewParent->AddChild(this);
auto* newParent = static_cast<nsWindow*>(aNewParent);
// New parent is deleted, quit.
if (newParent->mIsDestroyed) {
Destroy();
return;
}
GdkWindow* window = GetToplevelGdkWindow();
GdkWindow* parentWindow = newParent->GetToplevelGdkWindow();
LOG(" child GdkWindow %p set parent GdkWindow %p", window, parentWindow);
gdk_window_reparent(window, parentWindow, 0, 0);
SetHasMappedToplevel(newParent && newParent->mHasMappedToplevel);
}
bool nsWindow::WidgetTypeSupportsAcceleration() {
if (IsSmallPopup()) {
return false;
@@ -764,18 +728,26 @@ bool nsWindow::WidgetTypeSupportsAcceleration() {
return true;
}
void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
MOZ_ASSERT(aNewParent, "null widget");
MOZ_ASSERT(!mIsDestroyed, "");
MOZ_ASSERT(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "");
MOZ_ASSERT(
!mParent,
"nsWindow::ReparentNativeWidget() works on toplevel windows only.");
void nsWindow::DidChangeParent(nsIWidget* aOldParent) {
LOG("nsWindow::DidChangeParent new parent %p -> %p\n", aOldParent, mParent);
if (!mParent) {
return;
}
auto* newParent = static_cast<nsWindow*>(mParent);
if (mIsDestroyed || newParent->IsDestroyed()) {
return;
}
if (!IsTopLevelWindowType()) {
GdkWindow* window = GetToplevelGdkWindow();
GdkWindow* parentWindow = newParent->GetToplevelGdkWindow();
gdk_window_reparent(window, parentWindow, 0, 0);
SetHasMappedToplevel(newParent->mHasMappedToplevel);
return;
}
auto* newParent = static_cast<nsWindow*>(aNewParent);
GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget());
LOG("nsWindow::ReparentNativeWidget new parent %p\n", newParent);
GtkWindowSetTransientFor(GTK_WINDOW(mShell), newParentWidget);
}
@@ -5875,8 +5847,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
// initialize all the common bits of this class
BaseCreate(aParent, aInitData);
// and do our common creation
mParent = aParent;
// save our bounds
mBounds = aRect;
LOG(" mBounds: x:%d y:%d w:%d h:%d\n", mBounds.x, mBounds.y, mBounds.width,

View File

@@ -162,13 +162,11 @@ class nsWindow final : public nsBaseWidget {
const LayoutDeviceIntRect& aRect,
InitData* aInitData) override;
void Destroy() override;
nsIWidget* GetParent() override;
float GetDPI() override;
double GetDefaultScaleInternal() override;
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override;
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScaleByScreen()
override;
void SetParent(nsIWidget* aNewParent) override;
void SetModal(bool aModal) override;
bool IsVisible() const override;
bool IsMapped() const override;
@@ -334,7 +332,7 @@ class nsWindow final : public nsBaseWidget {
void SetTransparencyMode(TransparencyMode aMode) override;
TransparencyMode GetTransparencyMode() override;
void SetInputRegion(const InputRegion&) override;
void ReparentNativeWidget(nsIWidget* aNewParent) override;
void DidChangeParent(nsIWidget* aOldParent) override;
nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
NativeMouseMessage aNativeMessage,
@@ -492,7 +490,6 @@ class nsWindow final : public nsBaseWidget {
void RegisterTouchWindow() override;
nsCOMPtr<nsIWidget> mParent;
mozilla::Atomic<int, mozilla::Relaxed> mCeiledScaleFactor{1};
double mFractionalScaleFactor = 0.0;

View File

@@ -71,7 +71,6 @@ HeadlessWidget::HeadlessWidget()
mVisible(false),
mDestroyed(false),
mAlwaysOnTop(false),
mTopLevel(nullptr),
mCompositorWidget(nullptr),
mSizeMode(nsSizeMode_Normal),
mLastSizeMode(nsSizeMode_Normal),
@@ -120,21 +119,13 @@ void HeadlessWidget::Destroy() {
nsresult HeadlessWidget::Create(nsIWidget* aParent,
const LayoutDeviceIntRect& aRect,
widget::InitData* aInitData) {
// FIXME(emilio): Why aParent = nullptr? Should just pass in aParent, most
// likely?
BaseCreate(/* aParent = */ nullptr, aInitData);
BaseCreate(aParent, aInitData);
mBounds = aRect;
mRestoreBounds = aRect;
mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop;
if (aParent) {
mTopLevel = aParent->GetTopLevelWidget();
} else {
mTopLevel = this;
}
return NS_OK;
}
@@ -144,8 +135,6 @@ void HeadlessWidget::GetCompositorWidgetInitData(
mozilla::widget::HeadlessCompositorWidgetInitData(GetClientSize());
}
nsIWidget* HeadlessWidget::GetTopLevelWidget() { return mTopLevel; }
void HeadlessWidget::RaiseWindow() {
MOZ_ASSERT(
mWindowType == WindowType::TopLevel || mWindowType == WindowType::Dialog,
@@ -202,7 +191,9 @@ void HeadlessWidget::SetFocus(Raise aRaise,
// The toplevel only becomes active if it's currently visible; otherwise, it
// will be activated anyway when it's shown.
if (topLevel->IsVisible()) topLevel->RaiseWindow();
if (topLevel->IsVisible()) {
topLevel->RaiseWindow();
}
}
}
@@ -239,7 +230,7 @@ void HeadlessWidget::MoveInternal(int32_t aX, int32_t aY) {
}
LayoutDeviceIntPoint HeadlessWidget::WidgetToScreenOffset() {
return mTopLevel->GetBounds().TopLeft();
return GetTopLevelWidget()->GetBounds().TopLeft();
}
WindowRenderer* HeadlessWidget::GetWindowRenderer() {

View File

@@ -54,8 +54,6 @@ class HeadlessWidget : public nsBaseWidget {
widget::InitData* aInitData = nullptr) override;
using nsBaseWidget::Create; // for Create signature not overridden here
nsIWidget* GetTopLevelWidget() override;
void GetCompositorWidgetInitData(
mozilla::widget::CompositorWidgetInitData* aInitData) override;
@@ -144,7 +142,6 @@ class HeadlessWidget : public nsBaseWidget {
bool mVisible;
bool mDestroyed;
bool mAlwaysOnTop;
nsIWidget* mTopLevel;
HeadlessCompositorWidget* mCompositorWidget;
nsSizeMode mSizeMode;
// The size mode before entering fullscreen mode.

View File

@@ -420,8 +420,29 @@ void nsBaseWidget::BaseCreate(nsIWidget* aParent, widget::InitData* aInitData) {
mIsPIPWindow = aInitData->mPIPWindow;
}
if (aParent) {
aParent->AddChild(this);
mParent = aParent;
if (mParent) {
mParent->AddToChildList(this);
}
}
void nsIWidget::SetParent(nsIWidget* aNewParent) {
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
nsCOMPtr<nsIWidget> oldParent = mParent;
if (mParent) {
mParent->RemoveFromChildList(this);
}
mParent = aNewParent;
if (mParent) {
mParent->AddToChildList(this);
}
DidChangeParent(oldParent);
}
void nsIWidget::RemoveAllChildren() {
while (nsCOMPtr<nsIWidget> kid = mLastChild) {
kid->SetParent(nullptr);
MOZ_ASSERT(kid != mLastChild);
}
}
@@ -517,40 +538,20 @@ void nsBaseWidget::Destroy() {
// Just in case our parent is the only ref to us
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
// disconnect from the parent
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
if (mParent) {
mParent->RemoveFromChildList(this);
}
mParent = nullptr;
}
//-------------------------------------------------------------------------
//
// Get this nsBaseWidget parent
//
//-------------------------------------------------------------------------
nsIWidget* nsBaseWidget::GetParent(void) { return nullptr; }
//-------------------------------------------------------------------------
//
// Get this nsBaseWidget top level widget
//
//-------------------------------------------------------------------------
nsIWidget* nsBaseWidget::GetTopLevelWidget() {
nsIWidget *topLevelWidget = nullptr, *widget = this;
while (widget) {
topLevelWidget = widget;
widget = widget->GetParent();
nsIWidget* nsIWidget::GetTopLevelWidget() {
auto* cur = this;
while (nsIWidget* parent = cur->GetParent()) {
cur = parent;
}
return topLevelWidget;
return cur;
}
//-------------------------------------------------------------------------
//
// Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
//
//-------------------------------------------------------------------------
nsIWidget* nsBaseWidget::GetSheetWindowParent(void) { return nullptr; }
float nsBaseWidget::GetDPI() { return 96.0f; }
void nsBaseWidget::NotifyAPZOfDPIChange() {
@@ -597,7 +598,7 @@ RefPtr<mozilla::VsyncDispatcher> nsIWidget::GetVsyncDispatcher() {
// Add a child to the list of children
//
//-------------------------------------------------------------------------
void nsBaseWidget::AddChild(nsIWidget* aChild) {
void nsIWidget::AddToChildList(nsIWidget* aChild) {
MOZ_ASSERT(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
"aChild not properly removed from its old child list");
@@ -618,7 +619,7 @@ void nsBaseWidget::AddChild(nsIWidget* aChild) {
// Remove a child from the list of children
//
//-------------------------------------------------------------------------
void nsBaseWidget::RemoveChild(nsIWidget* aChild) {
void nsIWidget::RemoveFromChildList(nsIWidget* aChild) {
MOZ_ASSERT(aChild->GetParent() == this, "Not one of our kids!");
if (mLastChild == aChild) {

View File

@@ -168,13 +168,7 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
nsIWidgetListener* GetWidgetListener() const override;
void SetWidgetListener(nsIWidgetListener* alistener) override;
void Destroy() override;
void SetParent(nsIWidget* aNewParent) override {};
nsIWidget* GetParent() override;
nsIWidget* GetTopLevelWidget() override;
nsIWidget* GetSheetWindowParent(void) override;
float GetDPI() override;
void AddChild(nsIWidget* aChild) override;
void RemoveChild(nsIWidget* aChild) override;
void GetWorkspaceID(nsAString& workspaceID) override;
void MoveToWorkspace(const nsAString& workspaceID) override;
@@ -363,8 +357,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
PopupLevel GetPopupLevel() { return mPopupLevel; }
void ReparentNativeWidget(nsIWidget* aNewParent) override {}
const SizeConstraints GetSizeConstraints() override;
void SetSizeConstraints(const SizeConstraints& aConstraints) override;

View File

@@ -333,6 +333,7 @@ struct AutoObserverNotifier {
*/
class nsIWidget : public nsISupports {
protected:
friend class nsBaseWidget;
typedef mozilla::dom::BrowserChild BrowserChild;
public:
@@ -398,13 +399,7 @@ class nsIWidget : public nsISupports {
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWIDGET_IID)
nsIWidget()
: mLastChild(nullptr),
mPrevSibling(nullptr),
mOnDestroyCalled(false),
mWindowType(WindowType::Child) {
ClearNativeTouchSequence(nullptr);
}
nsIWidget() = default;
/**
* Create and initialize a widget.
@@ -529,7 +524,7 @@ class nsIWidget : public nsISupports {
*
* @param aNewParent new parent
*/
virtual void SetParent(nsIWidget* aNewParent) = 0;
void SetParent(nsIWidget* aNewParent);
/**
* Return the parent Widget of this Widget or nullptr if this is a
@@ -538,24 +533,17 @@ class nsIWidget : public nsISupports {
* @return the parent widget or nullptr if it does not have a parent
*
*/
virtual nsIWidget* GetParent(void) = 0;
nsIWidget* GetParent() const { return mParent; }
/** Gets called when mParent changes after creation. */
virtual void DidChangeParent(nsIWidget* aOldParent) {}
/**
* Return the top level Widget of this Widget
*
* @return the top level widget
*/
virtual nsIWidget* GetTopLevelWidget() = 0;
/**
* Return the top (non-sheet) parent of this Widget if it's a sheet,
* or nullptr if this isn't a sheet (or some other error occurred).
* Sheets are only supported on some platforms (currently only macOS).
*
* @return the top (non-sheet) parent widget or nullptr
*
*/
virtual nsIWidget* GetSheetWindowParent(void) = 0;
nsIWidget* GetTopLevelWidget();
/**
* Return the physical DPI of the screen containing the window ...
@@ -1209,15 +1197,15 @@ class nsIWidget : public nsISupports {
/**
* Internal methods
*/
//@{
virtual void AddChild(nsIWidget* aChild) = 0;
virtual void RemoveChild(nsIWidget* aChild) = 0;
virtual void* GetNativeData(uint32_t aDataType) = 0;
virtual void FreeNativeData(void* data, uint32_t aDataType) = 0; //~~~
//@}
protected:
void AddToChildList(nsIWidget* aChild);
void RemoveFromChildList(nsIWidget* aChild);
void RemoveAllChildren();
public:
/**
* Set the widget's title.
* Must be called after Create.
@@ -1850,13 +1838,6 @@ class nsIWidget : public nsISupports {
static already_AddRefed<nsIWidget> CreateHeadlessWidget();
/**
* Reparent this widget's native widget.
* @param aNewParent the native widget of aNewParent is the new native
* parent widget
*/
virtual void ReparentNativeWidget(nsIWidget* aNewParent) = 0;
/**
* Return true if widget has it's own GL context
*/
@@ -2090,12 +2071,14 @@ class nsIWidget : public nsISupports {
// lastchild pointers are weak, which is fine as long as they are
// maintained properly.
nsCOMPtr<nsIWidget> mFirstChild;
nsIWidget* MOZ_NON_OWNING_REF mLastChild;
nsIWidget* MOZ_NON_OWNING_REF mLastChild = nullptr;
nsCOMPtr<nsIWidget> mNextSibling;
nsIWidget* MOZ_NON_OWNING_REF mPrevSibling;
nsIWidget* MOZ_NON_OWNING_REF mPrevSibling = nullptr;
// Keeps us alive.
nsIWidget* MOZ_NON_OWNING_REF mParent = nullptr;
// When Destroy() is called, the sub class should set this true.
bool mOnDestroyCalled;
WindowType mWindowType;
bool mOnDestroyCalled = false;
WindowType mWindowType = WindowType::Child;
WidgetType mWidgetType = WidgetType::Native;
};

View File

@@ -880,7 +880,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
nsToolkit::GetToolkit();
BaseCreate(aParent, aInitData);
mParent = aParent;
HWND parent =
aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
@@ -1448,54 +1447,16 @@ void nsWindow::DissociateFromNativeWindow() {
mPrevWndProc.reset();
}
/**************************************************************
*
* SECTION: nsIWidget::SetParent, nsIWidget::GetParent
*
* Set or clear the parent widgets using window properties, and
* handles calculating native parent handles.
*
**************************************************************/
// Get and set parent widgets
void nsWindow::SetParent(nsIWidget* aNewParent) {
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
}
mParent = aNewParent;
if (aNewParent) {
ReparentNativeWidget(aNewParent);
aNewParent->AddChild(this);
void nsWindow::DidChangeParent(nsIWidget*) {
if (mWindowType == WindowType::Popup || !mWnd) {
return;
}
if (mWnd) {
// If we have no parent, SetParent should return the desktop.
VERIFY(::SetParent(mWnd, nullptr));
RecreateDirectManipulationIfNeeded();
}
HWND newParent =
mParent ? (HWND)mParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
::SetParent(mWnd, newParent);
RecreateDirectManipulationIfNeeded();
}
void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
MOZ_ASSERT(aNewParent, "null widget");
mParent = aNewParent;
if (mWindowType == WindowType::Popup) {
return;
}
HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
NS_ASSERTION(newParent, "Parent widget has a null native window handle");
if (newParent && mWnd) {
::SetParent(mWnd, newParent);
RecreateDirectManipulationIfNeeded();
}
}
nsIWidget* nsWindow::GetParent() { return mParent; }
static int32_t RoundDown(double aDouble) {
return aDouble > 0 ? static_cast<int32_t>(floor(aDouble))
: static_cast<int32_t>(ceil(aDouble));
@@ -6896,7 +6857,6 @@ void nsWindow::OnDestroy() {
// Disconnects us from our parent, will call our GetParent().
nsBaseWidget::Destroy();
mParent = nullptr;
// Release references to children, device context, toolkit, and app shell.
nsBaseWidget::OnDestroy();

View File

@@ -198,10 +198,9 @@ class nsWindow final : public nsBaseWidget {
const LayoutDeviceIntRect& aRect,
InitData* aInitData = nullptr) override;
void Destroy() override;
void SetParent(nsIWidget* aNewParent) override;
nsIWidget* GetParent(void) override;
float GetDPI() override;
double GetDefaultScaleInternal() override;
void DidChangeParent(nsIWidget* aOldParent) override;
int32_t LogToPhys(double aValue);
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override {
if (mozilla::widget::WinUtils::IsPerMonitorDPIAware()) {
@@ -385,8 +384,6 @@ class nsWindow final : public nsBaseWidget {
mTaskbarPreview = do_GetWeakReference(preview);
}
void ReparentNativeWidget(nsIWidget* aNewParent) override;
// Open file picker tracking
void PickerOpen();
void PickerClosed();
@@ -762,7 +759,6 @@ class nsWindow final : public nsBaseWidget {
InputContext mInputContext;
nsCOMPtr<nsIWidget> mParent;
nsIntSize mLastSize = nsIntSize(0, 0);
nsIntPoint mLastPoint;
HWND mWnd = nullptr;