Bug 781725: Refactor TabChild to allow pre-created instances, and then use a pre-created instance to pre-load and compile BrowserElementChild.js. r=smaug

--HG--
extra : rebase_source : f063c672d55da46541fdd1b6f6ff0cf510a6853f
This commit is contained in:
Chris Jones 2012-08-29 12:26:18 -03:00
parent 262988ed07
commit ec453b21c7
8 changed files with 222 additions and 95 deletions

View File

@ -822,6 +822,11 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
}
nsFrameJSScriptExecutorHolder* holder = sCachedScripts->Get(aURL);
if (!holder) {
TryCacheLoadAndCompileScript(aURL, EXECUTE_IF_CANT_CACHE);
holder = sCachedScripts->Get(aURL);
}
if (holder) {
nsContentUtils::ThreadJSContextStack()->Push(mCx);
{
@ -838,7 +843,12 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
nsContentUtils::ThreadJSContextStack()->Pop(&unused);
return;
}
}
void
nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
CacheFailedBehavior aBehavior)
{
nsCString url = NS_ConvertUTF16toUTF8(aURL);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
@ -907,8 +917,9 @@ nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
JS_AddNamedScriptRoot(mCx, &(holder->mScript),
"Cached message manager script");
sCachedScripts->Put(aURL, holder);
} else if (aBehavior == EXECUTE_IF_CANT_CACHE) {
(void) JS_ExecuteScript(mCx, global, script, nullptr);
}
(void) JS_ExecuteScript(mCx, global, script, nullptr);
}
}
}

View File

@ -224,6 +224,9 @@ protected:
// Call this when you want to destroy mCx.
void DestroyCx();
void LoadFrameScriptInternal(const nsAString& aURL);
enum CacheFailedBehavior { EXECUTE_IF_CANT_CACHE, DONT_EXECUTE };
void TryCacheLoadAndCompileScript(const nsAString& aURL,
CacheFailedBehavior aBehavior = DONT_EXECUTE);
bool InitTabChildGlobalInternal(nsISupports* aScope);
static void Traverse(nsFrameScriptExecutor *tmp,
nsCycleCollectionTraversalCallback &cb);

View File

@ -428,10 +428,10 @@ PBrowserChild*
ContentChild::AllocPBrowser(const uint32_t& aChromeFlags,
const bool& aIsBrowserElement, const AppId& aApp)
{
uint32_t appId = aApp.get_uint32_t();
nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
appId);
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
nsRefPtr<TabChild> child =
TabChild::Create(aChromeFlags, aIsBrowserElement, aApp.get_uint32_t());
// The ref here is released below.
return child.forget().get();
}
bool
@ -937,6 +937,8 @@ PreloadSlowThings()
{
// This fetches and creates all the built-in stylesheets.
nsLayoutStylesheetCache::UserContentSheet();
TabChild::PreloadSlowThings();
}
bool

View File

@ -100,6 +100,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/hal/sandbox \
-I$(topsrcdir)/dom/sms/src/ipc \
-I$(topsrcdir)/dom/devicestorage \
-I$(topsrcdir)/widget/xpwidgets \
$(NULL)
DEFINES += -DBIN_SUFFIX='"$(BIN_SUFFIX)"'

View File

@ -12,6 +12,7 @@
#include "Blob.h"
#include "ContentChild.h"
#include "IndexedDBChild.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/IntentionalCrash.h"
#include "mozilla/docshell/OfflineCacheUpdateChild.h"
#include "mozilla/dom/PContentChild.h"
@ -20,6 +21,7 @@
#include "mozilla/layers/CompositorChild.h"
#include "mozilla/layers/PLayersChild.h"
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/unused.h"
#include "nsComponentManagerUtils.h"
#include "nsComponentManagerUtils.h"
@ -62,9 +64,13 @@
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "PCOMContentPermissionRequestChild.h"
#include "PuppetWidget.h"
#include "StructuredCloneUtils.h"
#include "xpcpublic.h"
#define BROWSER_ELEMENT_CHILD_SCRIPT \
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::ipc;
@ -93,6 +99,48 @@ public:
const InfallibleTArray<nsString>& aStringParams);
};
StaticRefPtr<TabChild> sPreallocatedTab;
/*static*/ void
TabChild::PreloadSlowThings()
{
MOZ_ASSERT(!sPreallocatedTab);
nsRefPtr<TabChild> tab(new TabChild(0, false,
nsIScriptSecurityManager::NO_APP_ID));
if (!NS_SUCCEEDED(tab->Init()) ||
!tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
return;
}
tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT);
sPreallocatedTab = tab;
ClearOnShutdown(&sPreallocatedTab);
}
/*static*/ already_AddRefed<TabChild>
TabChild::Create(uint32_t aChromeFlags,
bool aIsBrowserElement, uint32_t aAppId)
{
if (sPreallocatedTab &&
sPreallocatedTab->mChromeFlags == aChromeFlags &&
(aIsBrowserElement ||
aAppId != nsIScriptSecurityManager::NO_APP_ID)) {
nsRefPtr<TabChild> child = sPreallocatedTab.get();
sPreallocatedTab = nullptr;
MOZ_ASSERT(!child->mTriedBrowserInit);
child->SetAppBrowserConfig(aIsBrowserElement, aAppId);
return child.forget();
}
nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags, aIsBrowserElement,
aAppId);
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
}
TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
uint32_t aAppId)
@ -101,10 +149,11 @@ TabChild::TabChild(uint32_t aChromeFlags, bool aIsBrowserElement,
, mChromeFlags(aChromeFlags)
, mOuterRect(0, 0, 0, 0)
, mLastBackgroundColor(NS_RGB(255, 255, 255))
, mAppId(aAppId)
, mDidFakeShow(false)
, mIsBrowserElement(aIsBrowserElement)
, mNotified(false)
, mAppId(aAppId)
, mTriedBrowserInit(false)
{
printf("creating %d!\n", NS_IsMainThread());
}
@ -150,22 +199,62 @@ TabChild::Init()
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(mWebNav));
docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mWebNav);
if (!baseWindow) {
NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
return false;
}
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
mWidget = nsIWidget::CreatePuppetWidget(this);
if (!mWidget) {
NS_ERROR("couldn't create fake widget");
return false;
}
mWidget->Create(
nullptr, 0, // no parents
nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
nullptr, // HandleWidgetEvent
nullptr // nsDeviceContext
);
if (observerService) {
observerService->AddObserver(this,
"cancel-default-pan-zoom",
false);
observerService->AddObserver(this,
"browser-zoom-to-rect",
false);
baseWindow->InitWindow(0, mWidget, 0, 0, 0, 0);
baseWindow->Create();
SetAppBrowserConfig(mIsBrowserElement, mAppId);
// IPC uses a WebBrowser object for which DNS prefetching is turned off
// by default. But here we really want it, so enable it explicitly
nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup =
do_QueryInterface(baseWindow);
if (webBrowserSetup) {
webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
true);
} else {
NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping "
"DNS prefetching enable step.");
}
return NS_OK;
}
void
TabChild::SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId)
{
mIsBrowserElement = aIsBrowserElement;
mAppId = aAppId;
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
MOZ_ASSERT(docShell);
if (docShell) {
docShell->SetAppId(mAppId);
if (mIsBrowserElement) {
docShell->SetIsBrowserElement();
}
}
}
NS_INTERFACE_MAP_BEGIN(TabChild)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
@ -569,6 +658,8 @@ TabChild::ActorDestroy(ActorDestroyReason why)
TabChild::~TabChild()
{
DestroyWindow();
nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(mWebNav);
if (webBrowser) {
webBrowser->SetContainerWindow(nullptr);
@ -611,6 +702,7 @@ TabChild::DoFakeShow()
bool
TabChild::RecvShow(const nsIntSize& size)
{
if (mDidFakeShow) {
return true;
}
@ -623,7 +715,7 @@ TabChild::RecvShow(const nsIntSize& size)
return false;
}
if (!InitWidget(size)) {
if (!InitRenderingState()) {
// We can fail to initialize our widget if the <browser
// remote> has already been destroyed, and we couldn't hook
// into the parent-process's layer system. That's not a fatal
@ -631,33 +723,8 @@ TabChild::RecvShow(const nsIntSize& size)
return true;
}
baseWindow->InitWindow(0, mWidget,
0, 0, size.width, size.height);
baseWindow->Create();
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mWebNav);
MOZ_ASSERT(docShell);
if (docShell) {
docShell->SetAppId(mAppId);
if (mIsBrowserElement) {
docShell->SetIsBrowserElement();
}
}
baseWindow->SetVisibility(true);
// IPC uses a WebBrowser object for which DNS prefetching is turned off
// by default. But here we really want it, so enable it explicitly
nsCOMPtr<nsIWebBrowserSetup> webBrowserSetup = do_QueryInterface(baseWindow);
if (webBrowserSetup) {
webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH,
true);
} else {
NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping "
"DNS prefetching enable step.");
}
return InitTabChildGlobal();
}
@ -1160,58 +1227,47 @@ TabChild::DeallocPRenderFrame(PRenderFrameChild* aFrame)
}
bool
TabChild::InitTabChildGlobal()
TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
{
if (mCx && mTabChildGlobal)
return true;
if (!mCx && !mTabChildGlobal) {
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
NS_ENSURE_TRUE(window, false);
nsCOMPtr<nsIDOMEventTarget> chromeHandler =
do_QueryInterface(window->GetChromeEventHandler());
NS_ENSURE_TRUE(chromeHandler, false);
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
NS_ENSURE_TRUE(window, false);
nsCOMPtr<nsIDOMEventTarget> chromeHandler =
do_QueryInterface(window->GetChromeEventHandler());
NS_ENSURE_TRUE(chromeHandler, false);
nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
NS_ENSURE_TRUE(scope, false);
nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
NS_ENSURE_TRUE(scope, false);
mTabChildGlobal = scope;
mTabChildGlobal = scope;
nsISupports* scopeSupports =
NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIDOMEventTarget*, scope);
NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false);
NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports), false);
scope->Init();
scope->Init();
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
NS_ENSURE_TRUE(root, false);
root->SetParentTarget(scope);
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
NS_ENSURE_TRUE(root, false);
root->SetParentTarget(scope);
}
// Initialize the child side of the browser element machinery, if appropriate.
if (mIsBrowserElement || mAppId != nsIScriptSecurityManager::NO_APP_ID) {
RecvLoadRemoteScript(
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"));
if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
mTriedBrowserInit = true;
// Initialize the child side of the browser element machinery,
// if appropriate.
if (mIsBrowserElement || mAppId != nsIScriptSecurityManager::NO_APP_ID) {
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT);
}
}
return true;
}
bool
TabChild::InitWidget(const nsIntSize& size)
TabChild::InitRenderingState()
{
NS_ABORT_IF_FALSE(!mWidget && !mRemoteFrame, "CreateWidget twice?");
mWidget = nsIWidget::CreatePuppetWidget(this);
if (!mWidget) {
NS_ERROR("couldn't create fake widget");
return false;
}
mWidget->Create(
nullptr, 0, // no parents
nsIntRect(nsIntPoint(0, 0), size),
nullptr, // HandleWidgetEvent
nullptr // nsDeviceContext
);
static_cast<PuppetWidget*>(mWidget.get())->InitIMEState();
LayersBackend be;
uint64_t id;
@ -1252,6 +1308,19 @@ TabChild::InitWidget(const nsIntSize& size)
lf->SetMaxTextureSize(maxTextureSize);
mRemoteFrame = remoteFrame;
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (observerService) {
observerService->AddObserver(this,
"cancel-default-pan-zoom",
false);
observerService->AddObserver(this,
"browser-zoom-to-rect",
false);
}
return true;
}
@ -1264,6 +1333,17 @@ TabChild::SetBackgroundColor(const nscolor& aColor)
}
}
void
TabChild::GetDPI(float* aDPI)
{
*aDPI = -1.0;
if (!mRemoteFrame) {
return;
}
SendGetDPI(aDPI);
}
void
TabChild::NotifyPainted()
{

View File

@ -149,16 +149,18 @@ class TabChild : public PBrowserChild,
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
/**
* Create a new TabChild object.
*
* |aIsBrowserElement| indicates whether the tab is inside an <iframe mozbrowser>.
* |aAppId| is the app id of the app containing this tab. If the tab isn't
* contained in an app, aAppId will be nsIScriptSecurityManager::NO_APP_ID.
/**
* This is expected to be called off the critical path to content
* startup. This is an opportunity to load things that are slow
* on the critical path.
*/
TabChild(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
static void PreloadSlowThings();
/** Return a TabChild with the given attributes. */
static already_AddRefed<TabChild>
Create(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
virtual ~TabChild();
nsresult Init();
uint32_t GetAppId() { return mAppId; }
@ -259,6 +261,9 @@ public:
nsIPrincipal* GetPrincipal() { return mPrincipal; }
/** Return the DPI of the widget this TabChild draws to. */
void GetDPI(float* aDPI);
void SetBackgroundColor(const nscolor& aColor);
void NotifyPainted();
@ -281,12 +286,26 @@ protected:
virtual bool DeallocPIndexedDB(PIndexedDBChild* aActor);
private:
/**
* Create a new TabChild object.
*
* |aIsBrowserElement| indicates whether the tab is inside an <iframe mozbrowser>.
* |aAppId| is the app id of the app containing this tab. If the tab isn't
* contained in an app, aAppId will be nsIScriptSecurityManager::NO_APP_ID.
*/
TabChild(uint32_t aChromeFlags, bool aIsBrowserElement, uint32_t aAppId);
nsresult Init();
void SetAppBrowserConfig(bool aIsBrowserElement, uint32_t aAppId);
bool UseDirectCompositor();
void ActorDestroy(ActorDestroyReason why);
bool InitTabChildGlobal();
bool InitWidget(const nsIntSize& size);
enum FrameScriptLoading { DONT_LOAD_SCRIPTS, DEFAULT_LOAD_SCRIPTS };
bool InitTabChildGlobal(FrameScriptLoading aScriptLoading = DEFAULT_LOAD_SCRIPTS);
bool InitRenderingState();
void DestroyWindow();
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
@ -316,10 +335,11 @@ private:
nsIntRect mOuterRect;
nscolor mLastBackgroundColor;
ScrollingBehavior mScrolling;
uint32_t mAppId;
bool mDidFakeShow;
bool mIsBrowserElement;
bool mNotified;
uint32_t mAppId;
bool mTriedBrowserInit;
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};

View File

@ -99,11 +99,7 @@ PuppetWidget::Create(nsIWidget *aParent,
gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32));
mIMEComposing = false;
if (MightNeedIMEFocus(aInitData)) {
uint32_t chromeSeqno;
mTabChild->SendNotifyIMEFocus(false, &mIMEPreference, &chromeSeqno);
mIMELastBlurSeqno = mIMELastReceivedSeqno = chromeSeqno;
}
mNeedIMEStateInit = MightNeedIMEFocus(aInitData);
PuppetWidget* parent = static_cast<PuppetWidget*>(aParent);
if (parent) {
@ -117,6 +113,17 @@ PuppetWidget::Create(nsIWidget *aParent,
return NS_OK;
}
void
PuppetWidget::InitIMEState()
{
if (mNeedIMEStateInit) {
uint32_t chromeSeqno;
mTabChild->SendNotifyIMEFocus(false, &mIMEPreference, &chromeSeqno);
mIMELastBlurSeqno = mIMELastReceivedSeqno = chromeSeqno;
mNeedIMEStateInit = false;
}
}
already_AddRefed<nsIWidget>
PuppetWidget::CreateChild(const nsIntRect &aRect,
nsDeviceContext *aContext,
@ -537,7 +544,7 @@ PuppetWidget::GetDPI()
{
if (mDPI < 0) {
NS_ABORT_IF_FALSE(mTabChild, "Need TabChild to get the DPI from!");
mTabChild->SendGetDPI(&mDPI);
mTabChild->GetDPI(&mDPI);
}
return mDPI;

View File

@ -52,6 +52,8 @@ public:
nsDeviceContext* aContext,
nsWidgetInitData* aInitData = nullptr);
void InitIMEState();
virtual already_AddRefed<nsIWidget>
CreateChild(const nsIntRect &aRect,
nsDeviceContext *aContext,
@ -206,6 +208,7 @@ private:
// Note that if seqno overflows (~50 days at 1 ms increment rate),
// events will be discarded until new focus/blur occurs
uint32_t mIMELastBlurSeqno;
bool mNeedIMEStateInit;
// The DPI of the screen corresponding to this widget
float mDPI;