Bug 610670 - Reuse a single puppet widget. r=bz,cjones a=blocking-fennec

This commit is contained in:
Alon Zakai 2011-02-09 12:13:18 -08:00
Родитель 73cf0eeb7b
Коммит 731ddee374
5 изменённых файлов: 112 добавлений и 58 удалений

Просмотреть файл

@ -414,6 +414,11 @@ private:
PRBool aStartAtTop);
#endif // NS_PRINTING
// Whether we should attach to the top level widget. This is true if we
// are sharing/recycling a single base widget and not creating multiple
// child widgets.
PRBool ShouldAttachToTopLevel();
protected:
// These return the current shell/prescontext etc.
nsIPresShell* GetPresShell();
@ -1392,6 +1397,32 @@ DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry)
// XXX re-enable image animations once that works correctly
PrepareToStartLoad();
// When loading a page from the bfcache with puppet widgets, we do the
// widget attachment here (it is otherwise done in MakeWindow, which is
// called for non-bfcache pages in the history, but not bfcache pages).
// Attachment is necessary, since we get detached when another page
// is browsed to. That is, if we are one page A, then when we go to
// page B, we detach. So page A's view has no widget. If we then go
// back to it, and it is in the bfcache, we will use that view, which
// doesn't have a widget. The attach call here will properly attach us.
if (nsIWidget::UsePuppetWidgets() && mPresContext &&
ShouldAttachToTopLevel()) {
// If the old view is already attached to our parent, detach
DetachFromTopLevelWidget();
nsIViewManager *vm = GetViewManager();
NS_ABORT_IF_FALSE(vm, "no view manager");
nsIView *v;
nsresult rv = vm->GetRootView(v);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "failed in getting the root view");
NS_ABORT_IF_FALSE(v, "no root view");
NS_ABORT_IF_FALSE(mParentWidget, "no mParentWidget to set");
v->AttachToTopLevelWidget(mParentWidget);
mAttachedToParent = PR_TRUE;
}
return NS_OK;
}
@ -2242,30 +2273,12 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize, nsIView* aContainerView)
if (GetIsPrintPreview())
return NS_OK;
// Prior to creating a new widget, check to see if our parent is a base
// chrome ui window. If so, drop the content into that widget instead of
// creating a new child widget. This eliminates the main content child
// widget we've had forever. Also allows for the recycling of the base
// widget of each window, vs. creating/discarding child widgets for each
// MakeWindow call. (Currently only implemented in windows widgets.)
#ifdef XP_WIN
nsCOMPtr<nsIDocShellTreeItem> containerItem = do_QueryReferent(mContainer);
if (mParentWidget && containerItem) {
PRInt32 docType;
nsWindowType winType;
containerItem->GetItemType(&docType);
mParentWidget->GetWindowType(winType);
if ((winType == eWindowType_toplevel ||
winType == eWindowType_dialog ||
winType == eWindowType_invisible) &&
docType == nsIDocShellTreeItem::typeChrome) {
PRBool shouldAttach = ShouldAttachToTopLevel();
if (shouldAttach) {
// If the old view is already attached to our parent, detach
DetachFromTopLevelWidget();
// Use the parent widget
mAttachedToParent = PR_TRUE;
}
}
#endif
nsresult rv;
mViewManager = do_CreateInstance(kViewManagerCID, &rv);
@ -2304,9 +2317,10 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize, nsIView* aContainerView)
initDataPtr = nsnull;
}
if (mAttachedToParent) {
if (shouldAttach) {
// Reuse the top level parent widget.
rv = view->AttachToTopLevelWidget(mParentWidget);
mAttachedToParent = PR_TRUE;
}
else if (!aContainerView && mParentWidget) {
rv = view->CreateWidgetForParent(mParentWidget, initDataPtr,
@ -4029,6 +4043,37 @@ DocumentViewerImpl::SetIsPrintingInDocShellTree(nsIDocShellTreeNode* aParentNode
}
#endif // NS_PRINTING
PRBool
DocumentViewerImpl::ShouldAttachToTopLevel()
{
if (!mParentWidget)
return PR_FALSE;
nsCOMPtr<nsIDocShellTreeItem> containerItem = do_QueryReferent(mContainer);
if (!containerItem)
return PR_FALSE;
// We always attach when using puppet widgets
if (nsIWidget::UsePuppetWidgets())
return PR_TRUE;
#ifdef XP_WIN
// On windows, in the parent process we also attach, but just to
// chrome items
PRInt32 docType;
nsWindowType winType;
containerItem->GetItemType(&docType);
mParentWidget->GetWindowType(winType);
if ((winType == eWindowType_toplevel ||
winType == eWindowType_dialog ||
winType == eWindowType_invisible) &&
docType == nsIDocShellTreeItem::typeChrome)
return PR_TRUE;
#endif
return PR_FALSE;
}
//------------------------------------------------------------
// XXX this always returns PR_FALSE for subdocuments
PRBool

Просмотреть файл

@ -854,7 +854,8 @@ nsresult nsIView::AttachToTopLevelWidget(nsIWidget* aWidget)
// Note, the previous device context will be released. Detaching
// will not restore the old one.
nsresult rv = aWidget->AttachViewToTopLevel(::AttachedHandleEvent, dx);
nsresult rv = aWidget->AttachViewToTopLevel(
nsIWidget::UsePuppetWidgets() ? ::HandleEvent : ::AttachedHandleEvent, dx);
if (NS_FAILED(rv))
return rv;

Просмотреть файл

@ -1330,7 +1330,6 @@ class nsIWidget : public nsISupports {
PRBool aIsHorizontal,
PRInt32 &aOverriddenDelta) = 0;
#ifdef MOZ_IPC
/**
* Return true if this process shouldn't use platform widgets, and
* so should use PuppetWidgets instead. If this returns true, the
@ -1339,8 +1338,15 @@ class nsIWidget : public nsISupports {
*/
static bool
UsePuppetWidgets()
{ return XRE_GetProcessType() == GeckoProcessType_Content; }
{
#ifdef MOZ_IPC
return XRE_GetProcessType() == GeckoProcessType_Content;
#else
return PR_FALSE;
#endif
}
#ifdef MOZ_IPC
/**
* Allocate and return a "puppet widget" that doesn't directly
* correlate to a platform widget; platform events and data must

Просмотреть файл

@ -276,8 +276,13 @@ PuppetWidget::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
nsCAutoString("PuppetWidget"), nsnull);
#endif
NS_ABORT_IF_FALSE(!mChild || mChild->mWindowType == eWindowType_popup,
"Unexpected event dispatch!");
aStatus = nsEventStatus_eIgnore;
if (mEventCallback) {
NS_ABORT_IF_FALSE(mViewCallback, "No view callback!");
if (event->message == NS_COMPOSITION_START) {
mIMEComposing = PR_TRUE;
}
@ -298,15 +303,11 @@ PuppetWidget::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
return NS_OK;
break;
}
aStatus = (*mEventCallback)(event);
aStatus = (*mViewCallback)(event);
if (event->message == NS_COMPOSITION_END) {
mIMEComposing = PR_FALSE;
}
} else if (mChild) {
event->widget = mChild;
mChild->DispatchEvent(event, aStatus);
}
return NS_OK;
}

Просмотреть файл

@ -301,8 +301,9 @@ nsBaseWidget::AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction,
{
NS_ASSERTION((mWindowType == eWindowType_toplevel ||
mWindowType == eWindowType_dialog ||
mWindowType == eWindowType_invisible),
"Can't attach to child?");
mWindowType == eWindowType_invisible ||
mWindowType == eWindowType_child),
"Can't attach to window of that type");
mViewCallback = aViewEventFunction;