Bug 523224 - nsFrameLoader::TryNewProcess crashes if reflow hasn't happened yet and created a view for our remote tab. Fix this by separating the process of creating the IFrameEmbedding and hooking up the view. IFrameEmbedding creation is analogous to creating a docshell, and we can hook up the view/widget hierarchy later.

* * *
imported patch fennelectrolysis-workihng
This commit is contained in:
Benjamin Smedberg 2009-10-28 16:41:46 -04:00
parent cfa536b0fc
commit be1e4c0ce6
13 changed files with 190 additions and 140 deletions

View File

@ -80,6 +80,7 @@
#include "nsISHistory.h"
#include "nsISHistoryInternal.h"
#include "nsIDOMNSHTMLDocument.h"
#include "nsLayoutUtils.h"
#include "nsIURI.h"
#include "nsIURL.h"
@ -588,36 +589,37 @@ nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
return false;
#ifdef MOZ_IPC
if (!mRemoteFrame)
if (mRemoteFrame) {
return ShowRemoteFrame(frame, view);
}
#endif
{
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0, 10, 10);
// This is kinda whacky, this "Create()" call doesn't really
// create anything, one starts to wonder why this was named
// "Create"...
baseWindow->Create();
baseWindow->SetVisibility(PR_TRUE);
// Trigger editor re-initialization if midas is turned on in the
// sub-document. This shouldn't be necessary, but given the way our
// editor works, it is. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=284245
nsCOMPtr<nsIPresShell> presShell;
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIDOMNSHTMLDocument> doc =
do_QueryInterface(presShell->GetDocument());
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0, 10, 10);
// This is kinda whacky, this "Create()" call doesn't really
// create anything, one starts to wonder why this was named
// "Create"...
baseWindow->Create();
baseWindow->SetVisibility(PR_TRUE);
if (doc) {
nsAutoString designMode;
doc->GetDesignMode(designMode);
// Trigger editor re-initialization if midas is turned on in the
// sub-document. This shouldn't be necessary, but given the way our
// editor works, it is. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=284245
nsCOMPtr<nsIPresShell> presShell;
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIDOMNSHTMLDocument> doc =
do_QueryInterface(presShell->GetDocument());
if (designMode.EqualsLiteral("on")) {
doc->SetDesignMode(NS_LITERAL_STRING("off"));
doc->SetDesignMode(NS_LITERAL_STRING("on"));
}
if (doc) {
nsAutoString designMode;
doc->GetDesignMode(designMode);
if (designMode.EqualsLiteral("on")) {
doc->SetDesignMode(NS_LITERAL_STRING("off"));
doc->SetDesignMode(NS_LITERAL_STRING("on"));
}
}
}
@ -625,6 +627,65 @@ nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
return true;
}
#ifdef MOZ_IPC
bool
nsFrameLoader::ShowRemoteFrame(nsIFrameFrame* frame, nsIView* view)
{
NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
TryNewProcess();
if (!mChildProcess) {
NS_ERROR("Couldn't create child process.");
return false;
}
nsIWidget* w = view->GetWidget();
if (!w) {
NS_ERROR("Our view doesn't have a widget. Totally stuffed!");
return false;
}
nsIntSize size = GetSubDocumentSize(frame->GetFrame());
#ifdef XP_WIN
HWND parentwin =
static_cast<HWND>(w->GetNativeData(NS_NATIVE_WINDOW));
mChildProcess->SendcreateWidget(parentwin);
#elif defined(MOZ_WIDGET_GTK2)
GdkWindow* parent_win =
static_cast<GdkWindow*>(w->GetNativeData(NS_NATIVE_WINDOW));
gpointer user_data = nsnull;
gdk_window_get_user_data(parent_win, &user_data);
MozContainer* parentMozContainer = MOZ_CONTAINER(user_data);
GtkContainer* container = GTK_CONTAINER(parentMozContainer);
// create the socket for the child and add it to our view's widget
mRemoteSocket = gtk_socket_new();
gtk_widget_set_parent_window(mRemoteSocket, parent_win);
gtk_container_add(container, mRemoteSocket);
gtk_widget_realize(mRemoteSocket);
// set the child window's size and position
GtkAllocation alloc = { 0, 0, size.width, size.height };
gtk_widget_size_allocate(mRemoteSocket, &alloc);
gtk_widget_show(mRemoteSocket);
GdkNativeWindow id = gtk_socket_get_id(GTK_SOCKET(mRemoteSocket));
mChildProcess->SendcreateWidget(id);
#else
#error TODO for this platform
#endif
mChildProcess->Move(0, 0, size.width, size.height);
return true;
}
#endif
void
nsFrameLoader::Hide()
{
@ -941,7 +1002,7 @@ nsFrameLoader::Destroy()
}
}
}
// Let our window know that we are gone
nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
if (win_private) {
@ -1266,6 +1327,14 @@ nsFrameLoader::UpdatePositionAndSize(nsIFrame *aIFrame)
if (mRemoteFrame) {
if (mChildProcess) {
nsIntSize size = GetSubDocumentSize(aIFrame);
#ifdef MOZ_WIDGET_GTK2
if (mRemoteSocket) {
GtkAllocation alloc = {0, 0, size.width, size.height };
gtk_widget_size_allocate(mRemoteSocket, &alloc);
}
#endif
mChildProcess->Move(0, 0, size.width, size.height);
}
return NS_OK;
@ -1306,40 +1375,41 @@ nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame)
nsIntSize
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
{
nsSize docSizeAppUnits;
nsPresContext* presContext = aIFrame->PresContext();
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
do_QueryInterface(aIFrame->GetContent());
if (frameElem) {
docSizeAppUnits = aIFrame->GetSize();
} else {
docSizeAppUnits = aIFrame->GetContentRect().Size();
nsAutoDisableGetUsedXAssertions disableAssert;
nsSize docSizeAppUnits;
nsPresContext* presContext = aIFrame->PresContext();
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
do_QueryInterface(aIFrame->GetContent());
if (frameElem) {
docSizeAppUnits = aIFrame->GetSize();
} else {
docSizeAppUnits = aIFrame->GetContentRect().Size();
}
return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
}
#ifdef MOZ_IPC
PRBool
bool
nsFrameLoader::TryNewProcess()
{
NS_ASSERTION(!mChildProcess, "TryNewProcess called with a process already?");
nsIDocument* doc = mOwnerContent->GetDocument();
if (!doc) {
return PR_FALSE;
return false;
}
if (doc->GetDisplayDocument()) {
// Don't allow subframe loads in external reference documents
return PR_FALSE;
return false;
}
nsCOMPtr<nsIWebNavigation> parentAsWebNav =
do_GetInterface(doc->GetScriptGlobalObject());
if (!parentAsWebNav) {
return PR_FALSE;
return false;
}
nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
@ -1348,11 +1418,11 @@ nsFrameLoader::TryNewProcess()
parentAsItem->GetItemType(&parentType);
if (parentType != nsIDocShellTreeItem::typeChrome) {
return PR_FALSE;
return false;
}
if (!mOwnerContent->IsXUL()) {
return PR_FALSE;
return false;
}
nsAutoString value;
@ -1361,79 +1431,11 @@ nsFrameLoader::TryNewProcess()
if (!value.LowerCaseEqualsLiteral("content") &&
!StringBeginsWith(value, NS_LITERAL_STRING("content-"),
nsCaseInsensitiveStringComparator())) {
return PR_FALSE;
return false;
}
// FIXME shouldn't need to launch a new process every time get here
// XXXnasty hack get our (parent) widget
doc->FlushPendingNotifications(Flush_Layout);
nsIFrame* ourFrame =
doc->GetPrimaryShell()->GetPrimaryFrameFor(mOwnerContent);
nsIView* ancestorView = ourFrame->GetView();
nsIView* firstChild = ancestorView->GetFirstChild();
if (!firstChild) {
NS_ERROR("no first child");
return PR_FALSE;
}
nsIWidget* w = firstChild->GetWidget();
if (!w) {
NS_ERROR("we're stuffed!");
return PR_FALSE;
}
// FIXME check that this widget has the size and position we expect for
// this iframe?
nsPresContext* presContext = ourFrame->PresContext();
#ifdef XP_WIN
HWND parentwin =
static_cast<HWND>(w->GetNativeData(NS_NATIVE_WINDOW));
mChildProcess = ContentProcessParent::GetSingleton()->CreateTab(parentwin);
mChildProcess->Move(0, 0,
presContext->AppUnitsToDevPixels(ourFrame->GetSize().width),
presContext->AppUnitsToDevPixels(ourFrame->GetSize().height));
#elif defined(MOZ_WIDGET_GTK2)
GdkWindow* parent_win =
static_cast<GdkWindow*>(w->GetNativeData(NS_NATIVE_WINDOW));
gpointer user_data = nsnull;
gdk_window_get_user_data(parent_win, &user_data);
MozContainer* parentMozContainer = MOZ_CONTAINER(user_data);
GtkContainer* container = GTK_CONTAINER(parentMozContainer);
// create the widget for the child and add it to the parent's window
GtkWidget* socket = gtk_socket_new();
gtk_widget_set_parent_window(socket, parent_win);
gtk_container_add(container, socket);
gtk_widget_realize(socket);
// set the child window's size and position
GtkAllocation alloc;
alloc.x = 0; // setting position doesn't look necessary
alloc.y = 0;
alloc.width = presContext->AppUnitsToDevPixels(ourFrame->GetSize().width);
alloc.height = presContext->AppUnitsToDevPixels(ourFrame->GetSize().height);
gtk_widget_size_allocate(socket, &alloc);
gtk_widget_show(socket);
GdkNativeWindow id = gtk_socket_get_id((GtkSocket*)socket);
mChildProcess = ContentProcessParent::GetSingleton()->CreateTab(id);
mChildProcess->Move(0, 0, alloc.width, alloc.height);
#else
#error TODO for this platform
#endif
return PR_TRUE;
mChildProcess = ContentProcessParent::GetSingleton()->CreateTab();
return true;
}
#endif

View File

@ -54,6 +54,7 @@
class nsIContent;
class nsIURI;
class nsIFrameFrame;
class nsIView;
#ifdef MOZ_IPC
namespace mozilla {
@ -62,6 +63,10 @@ namespace mozilla {
class PIFrameEmbeddingParent;
}
}
#ifdef MOZ_WIDGET_GTK2
typedef struct _GtkWidget GtkWidget;
#endif
#endif
class nsFrameLoader : public nsIFrameLoader
@ -77,6 +82,9 @@ protected:
#ifdef MOZ_IPC
, mRemoteFrame(false)
, mChildProcess(nsnull)
#ifdef MOZ_WIDGET_GTK2
, mRemoteSocket(nsnull)
#endif
#endif
{}
@ -145,7 +153,11 @@ private:
#ifdef MOZ_IPC
// True means new process started; nothing else to do
PRBool TryNewProcess();
bool TryNewProcess();
// Do the hookup necessary to actually show a remote frame once the view and
// widget are available.
bool ShowRemoteFrame(nsIFrameFrame* frame, nsIView* view);
#endif
nsCOMPtr<nsIDocShell> mDocShell;
@ -161,6 +173,10 @@ private:
bool mRemoteFrame;
// XXX leaking
mozilla::dom::TabParent* mChildProcess;
#ifdef MOZ_WIDGET_GTK2
GtkWidget* mRemoteSocket;
#endif
#endif
};

View File

@ -3344,8 +3344,14 @@ nsCanvasRenderingContext2D::AsyncDrawXULElement(nsIDOMXULElement* aElem, float a
#ifdef MOZ_IPC
mozilla::dom::PIFrameEmbeddingParent *child = frameloader->GetChildProcess();
if (!child)
return NS_ERROR_FAILURE;
if (!child) {
nsCOMPtr<nsIDOMWindow> window =
do_GetInterface(frameloader->GetExistingDocShell());
if (!window)
return NS_ERROR_FAILURE;
return DrawWindow(window, aX, aY, aW, aH, aBGColor, flags);
}
// protect against too-large surfaces that will cause allocation
// or overflow issues

View File

@ -78,9 +78,9 @@ ContentProcessChild::Init(MessageLoop* aIOLoop,
}
PIFrameEmbeddingChild*
ContentProcessChild::AllocPIFrameEmbedding(const MagicWindowHandle& hwnd)
ContentProcessChild::AllocPIFrameEmbedding()
{
PIFrameEmbeddingChild* iframe = new TabChild(hwnd);
PIFrameEmbeddingChild* iframe = new TabChild();
if (iframe && mIFrames.AppendElement(iframe)) {
return iframe;
}

View File

@ -62,8 +62,7 @@ public:
return sSingleton;
}
virtual PIFrameEmbeddingChild* AllocPIFrameEmbedding(
const MagicWindowHandle& hwnd);
virtual PIFrameEmbeddingChild* AllocPIFrameEmbedding();
virtual bool DeallocPIFrameEmbedding(PIFrameEmbeddingChild*);
virtual PTestShellChild* AllocPTestShell();

View File

@ -84,9 +84,9 @@ ContentProcessParent::GetSingleton()
}
TabParent*
ContentProcessParent::CreateTab(const MagicWindowHandle& hwnd)
ContentProcessParent::CreateTab()
{
return static_cast<TabParent*>(SendPIFrameEmbeddingConstructor(hwnd));
return static_cast<TabParent*>(SendPIFrameEmbeddingConstructor());
}
TestShellParent*
@ -143,8 +143,7 @@ ContentProcessParent::OnWaitableEventSignaled(base::WaitableEvent *event)
}
PIFrameEmbeddingParent*
ContentProcessParent::AllocPIFrameEmbedding(
const MagicWindowHandle& parentWidget)
ContentProcessParent::AllocPIFrameEmbedding()
{
return new TabParent();
}

View File

@ -77,7 +77,7 @@ public:
virtual void OnWaitableEventSignaled(base::WaitableEvent *event);
TabParent* CreateTab(const MagicWindowHandle& hwnd);
TabParent* CreateTab();
mozilla::ipc::TestShellParent* CreateTestShell();
private:
@ -91,8 +91,7 @@ private:
ContentProcessParent();
virtual ~ContentProcessParent();
virtual PIFrameEmbeddingParent* AllocPIFrameEmbedding(
const MagicWindowHandle& parentWidget);
virtual PIFrameEmbeddingParent* AllocPIFrameEmbedding();
virtual bool DeallocPIFrameEmbedding(PIFrameEmbeddingParent* frame);
virtual PTestShellParent* AllocPTestShell();

View File

@ -42,8 +42,6 @@ include protocol "PNecko.ipdl";
include "mozilla/TabTypes.h";
using MagicWindowHandle;
namespace mozilla {
namespace dom {
@ -54,7 +52,7 @@ sync protocol PContentProcess
manages PNecko;
child:
PIFrameEmbedding(MagicWindowHandle parentWidget);
PIFrameEmbedding();
~PIFrameEmbedding();
PTestShell();

View File

@ -42,6 +42,7 @@ include protocol "PDocumentRenderer.ipdl";
using PRUint32;
using PRInt32;
using MagicWindowHandle;
namespace mozilla {
namespace dom {
@ -52,6 +53,9 @@ async protocol PIFrameEmbedding
manages PDocumentRenderer;
child:
createWidget(MagicWindowHandle parentWidget);
destroyWidget();
loadURL(nsCString uri);
move(PRUint32 x,

View File

@ -55,7 +55,7 @@
using namespace mozilla::dom;
TabChild::TabChild(const MagicWindowHandle& parentWidget)
TabChild::TabChild()
{
printf("creating %d!\n", NS_IsMainThread());
@ -63,10 +63,24 @@ TabChild::TabChild(const MagicWindowHandle& parentWidget)
gtk_init(NULL, NULL);
#endif
nsCOMPtr<nsIWebBrowser> webBrowser(do_CreateInstance(NS_WEBBROWSER_CONTRACTID));
mWebNav = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
if (!mWebNav) {
NS_ERROR("Couldn't create a nsWebBrowser?");
return;
}
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(webBrowser);
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
}
bool
TabChild::RecvcreateWidget(const MagicWindowHandle& parentWidget)
{
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
if (!baseWindow) {
NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
return true;
}
#ifdef MOZ_WIDGET_GTK2
GtkWidget* win = gtk_plug_new((GdkNativeWindow)parentWidget);
@ -78,15 +92,20 @@ TabChild::TabChild(const MagicWindowHandle& parentWidget)
#endif
baseWindow->InitWindow(win, 0, 0, 0, 0, 0);
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(baseWindow));
docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
baseWindow->Create();
baseWindow->SetVisibility(PR_TRUE);
mWebNav = do_QueryInterface(webBrowser);
return true;
}
bool
TabChild::RecvdestroyWidget()
{
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
if (baseWindow)
baseWindow->Destroy();
return true;
}
TabChild::~TabChild()
@ -102,7 +121,10 @@ TabChild::RecvloadURL(const nsCString& uri)
nsresult rv = mWebNav->LoadURI(NS_ConvertUTF8toUTF16(uri).get(),
nsIWebNavigation::LOAD_FLAGS_NONE,
NULL, NULL, NULL);
return NS_FAILED(rv) ? false : true;
if (NS_FAILED(rv)) {
NS_WARNING("mWebNav->LoadURI failed. Eating exception, what else can I do?");
}
return true;
}
bool

View File

@ -49,9 +49,11 @@ namespace dom {
class TabChild : public PIFrameEmbeddingChild
{
public:
TabChild(const MagicWindowHandle& parentWidget);
TabChild();
virtual ~TabChild();
virtual bool RecvcreateWidget(const MagicWindowHandle& parentWidget);
virtual bool RecvdestroyWidget();
virtual bool RecvloadURL(const nsCString& uri);
virtual bool Recvmove(const PRUint32& x,
const PRUint32& y,

View File

@ -181,6 +181,7 @@ public:
NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
virtual void EndSwapDocShells(nsIFrame* aOther);
virtual nsIFrame* GetFrame() { return this; }
// nsIReflowCallback
virtual PRBool ReflowFinished();

View File

@ -65,6 +65,8 @@ public:
* The frameloader informs us what kind of widget to create during Show()
*/
virtual nsIView* CreateViewAndWidget(nsContentType aContentType) = 0;
virtual nsIFrame* GetFrame() = 0;
};
#endif