mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 401155: Make it safe to create a wrapper for an object at any time by making sure wrapping doesn't write script. Also set up a service that tries to keep track of when it's safe to execute script. r=bz sr=jst
This commit is contained in:
parent
5afad8f2fa
commit
c078e73997
@ -90,6 +90,7 @@ class nsIWordBreaker;
|
||||
class nsIJSRuntimeService;
|
||||
class nsIEventListenerManager;
|
||||
class nsIScriptContext;
|
||||
class nsIRunnable;
|
||||
template<class E> class nsCOMArray;
|
||||
class nsIPref;
|
||||
class nsVoidArray;
|
||||
@ -1177,6 +1178,45 @@ public:
|
||||
*/
|
||||
static PRBool OfflineAppAllowed(nsIURI *aURI);
|
||||
|
||||
/**
|
||||
* Increases the count of blockers preventing scripts from running.
|
||||
* NOTE: You might want to use nsAutoScriptBlocker rather than calling
|
||||
* this directly
|
||||
*/
|
||||
static void AddScriptBlocker();
|
||||
|
||||
/**
|
||||
* Decreases the count of blockers preventing scripts from running.
|
||||
* NOTE: You might want to use nsAutoScriptBlocker rather than calling
|
||||
* this directly
|
||||
*
|
||||
* WARNING! Calling this function could synchronously execute scripts.
|
||||
*/
|
||||
static void RemoveScriptBlocker();
|
||||
|
||||
/**
|
||||
* Add a runnable that is to be executed as soon as it's safe to execute
|
||||
* scripts.
|
||||
* NOTE: If it's currently safe to execute scripts, aRunnable will be run
|
||||
* synchronously before the function returns.
|
||||
*
|
||||
* @param aRunnable The nsIRunnable to run as soon as it's safe to execute
|
||||
* scripts. Passing null is allowed and results in nothing
|
||||
* happening. It is also allowed to pass an object that
|
||||
* has not yet been AddRefed.
|
||||
*/
|
||||
static PRBool AddScriptRunner(nsIRunnable* aRunnable);
|
||||
|
||||
/**
|
||||
* Returns true if it's safe to execute content script and false otherwise.
|
||||
*
|
||||
* The only known case where this lies is mutation events. They run, and can
|
||||
* run anything else, when this function returns false, but this is ok.
|
||||
*/
|
||||
static PRBool IsSafeToRunScript() {
|
||||
return sScriptBlockerCount == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static PRBool InitializeEventTable();
|
||||
@ -1249,6 +1289,9 @@ private:
|
||||
#endif
|
||||
|
||||
static PRBool sInitialized;
|
||||
static PRUint32 sScriptBlockerCount;
|
||||
static nsCOMArray<nsIRunnable>* sBlockedScriptRunners;
|
||||
static PRUint32 sRunnersCountAtFirstBlocker;
|
||||
};
|
||||
|
||||
#define NS_HOLD_JS_OBJECTS(obj, clazz) \
|
||||
@ -1267,6 +1310,7 @@ public:
|
||||
|
||||
// Returns PR_FALSE if something erroneous happened.
|
||||
PRBool Push(nsISupports *aCurrentTarget);
|
||||
PRBool Push(JSContext *cx);
|
||||
void Pop();
|
||||
|
||||
private:
|
||||
@ -1317,6 +1361,16 @@ private:
|
||||
nsresult mResult;
|
||||
};
|
||||
|
||||
class nsAutoScriptBlocker {
|
||||
public:
|
||||
nsAutoScriptBlocker() {
|
||||
nsContentUtils::AddScriptBlocker();
|
||||
}
|
||||
~nsAutoScriptBlocker() {
|
||||
nsContentUtils::RemoveScriptBlocker();
|
||||
}
|
||||
};
|
||||
|
||||
#define NS_AUTO_GCROOT_PASTE2(tok,line) tok##line
|
||||
#define NS_AUTO_GCROOT_PASTE(tok,line) \
|
||||
NS_AUTO_GCROOT_PASTE2(tok,line)
|
||||
|
@ -596,6 +596,8 @@ public:
|
||||
// To make this easy and painless, use the mozAutoDocUpdate helper class.
|
||||
virtual void BeginUpdate(nsUpdateType aUpdateType) = 0;
|
||||
virtual void EndUpdate(nsUpdateType aUpdateType) = 0;
|
||||
virtual PRUint32 GetUpdateNestingLevel() = 0;
|
||||
virtual PRBool AllUpdatesAreContent() = 0;
|
||||
virtual void BeginLoad() = 0;
|
||||
virtual void EndLoad() = 0;
|
||||
// notify that one or two content nodes changed state
|
||||
|
@ -43,7 +43,7 @@ interface nsIPluginInstance;
|
||||
/**
|
||||
* This interface represents a content node that loads objects.
|
||||
*/
|
||||
[scriptable, uuid(42f9358e-300f-4a44-afd7-7830b750e955)]
|
||||
[scriptable, uuid(90ab443e-3e99-405e-88c9-9c42adaa3217)]
|
||||
interface nsIObjectLoadingContent : nsISupports
|
||||
{
|
||||
const unsigned long TYPE_LOADING = 0;
|
||||
@ -71,6 +71,13 @@ interface nsIObjectLoadingContent : nsISupports
|
||||
*/
|
||||
unsigned long getContentTypeForMIMEType(in AUTF8String aMimeType);
|
||||
|
||||
/**
|
||||
* Returns the plugin instance if it has already been instantiated. This
|
||||
* will never instantiate the plugin and so is safe to call even when
|
||||
* content script must not execute.
|
||||
*/
|
||||
[noscript] readonly attribute nsIPluginInstance pluginInstance;
|
||||
|
||||
|
||||
/**
|
||||
* Makes sure that a frame for this object exists, and that the plugin is
|
||||
|
@ -149,6 +149,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsIBidiKeyboard.h"
|
||||
@ -195,6 +197,9 @@ PRUint32 nsContentUtils::sJSGCThingRootCount;
|
||||
#ifdef IBMBIDI
|
||||
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nsnull;
|
||||
#endif
|
||||
PRUint32 nsContentUtils::sScriptBlockerCount = 0;
|
||||
nsCOMArray<nsIRunnable>* nsContentUtils::sBlockedScriptRunners = nsnull;
|
||||
PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
|
||||
|
||||
nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService;
|
||||
JSRuntime *nsAutoGCRoot::sJSScriptRuntime;
|
||||
@ -323,6 +328,9 @@ nsContentUtils::Init()
|
||||
}
|
||||
}
|
||||
|
||||
sBlockedScriptRunners = new nsCOMArray<nsIRunnable>;
|
||||
NS_ENSURE_TRUE(sBlockedScriptRunners, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
sInitialized = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
@ -821,6 +829,12 @@ nsContentUtils::Shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(!sBlockedScriptRunners ||
|
||||
sBlockedScriptRunners->Count() == 0,
|
||||
"How'd this happen?");
|
||||
delete sBlockedScriptRunners;
|
||||
sBlockedScriptRunners = nsnull;
|
||||
|
||||
nsAutoGCRoot::Shutdown();
|
||||
}
|
||||
|
||||
@ -2588,17 +2602,41 @@ nsCxPusher::Push(nsISupports *aCurrentTarget)
|
||||
|
||||
JSContext *cx = nsnull;
|
||||
|
||||
if (sgo) {
|
||||
mScx = sgo->GetContext();
|
||||
nsCOMPtr<nsIScriptContext> scx;
|
||||
|
||||
if (mScx) {
|
||||
cx = (JSContext *)mScx->GetNativeContext();
|
||||
if (sgo) {
|
||||
scx = sgo->GetContext();
|
||||
|
||||
if (scx) {
|
||||
cx = (JSContext *)scx->GetNativeContext();
|
||||
}
|
||||
// Bad, no JSContext from script global object!
|
||||
NS_ENSURE_TRUE(cx, PR_FALSE);
|
||||
}
|
||||
|
||||
// If there's no native context in the script context it must be
|
||||
// in the process or being torn down. We don't want to notify the
|
||||
// script context about scripts having been evaluated in such a
|
||||
// case, calling with a null cx is fine in that case.
|
||||
return Push(cx);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCxPusher::Push(JSContext *cx)
|
||||
{
|
||||
if (mScx) {
|
||||
NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (cx) {
|
||||
mScx = GetScriptContextFromJSContext(cx);
|
||||
if (!mScx) {
|
||||
// Should probably return PR_FALSE. See bug 416916.
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (!mStack) {
|
||||
mStack = do_GetService(kJSStackContractID);
|
||||
}
|
||||
@ -2612,13 +2650,6 @@ nsCxPusher::Push(nsISupports *aCurrentTarget)
|
||||
|
||||
mStack->Push(cx);
|
||||
}
|
||||
} else {
|
||||
// If there's no native context in the script context it must be
|
||||
// in the process or being torn down. We don't want to notify the
|
||||
// script context about scripts having been evaluated in such a
|
||||
// case, so null out mScx.
|
||||
|
||||
mScx = nsnull;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3960,6 +3991,65 @@ nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMEvent* aDOMEvent,
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::AddScriptBlocker()
|
||||
{
|
||||
if (!sScriptBlockerCount) {
|
||||
NS_ASSERTION(sRunnersCountAtFirstBlocker == 0,
|
||||
"Should not already have a count");
|
||||
sRunnersCountAtFirstBlocker = sBlockedScriptRunners->Count();
|
||||
}
|
||||
++sScriptBlockerCount;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::RemoveScriptBlocker()
|
||||
{
|
||||
--sScriptBlockerCount;
|
||||
if (sScriptBlockerCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
PRUint32 firstBlocker = sRunnersCountAtFirstBlocker;
|
||||
PRUint32 lastBlocker = sBlockedScriptRunners->Count();
|
||||
sRunnersCountAtFirstBlocker = 0;
|
||||
NS_ASSERTION(firstBlocker <= lastBlocker,
|
||||
"bad sRunnersCountAtFirstBlocker");
|
||||
|
||||
while (firstBlocker < lastBlocker) {
|
||||
nsCOMPtr<nsIRunnable> runnable = (*sBlockedScriptRunners)[firstBlocker];
|
||||
sBlockedScriptRunners->RemoveObjectAt(firstBlocker);
|
||||
--lastBlocker;
|
||||
|
||||
runnable->Run();
|
||||
NS_ASSERTION(lastBlocker == sBlockedScriptRunners->Count() &&
|
||||
sRunnersCountAtFirstBlocker == 0,
|
||||
"Bad count");
|
||||
NS_ASSERTION(!sScriptBlockerCount, "This is really bad");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
PRBool
|
||||
nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable)
|
||||
{
|
||||
if (!aRunnable) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (sScriptBlockerCount) {
|
||||
return sBlockedScriptRunners->AppendObject(aRunnable);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> run = aRunnable;
|
||||
run->Run();
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
|
||||
|
@ -2701,17 +2701,23 @@ nsDocument::BeginUpdate(nsUpdateType aUpdateType)
|
||||
}
|
||||
|
||||
++mUpdateNestLevel;
|
||||
if (mScriptLoader) {
|
||||
mScriptLoader->AddExecuteBlocker();
|
||||
if (aUpdateType == UPDATE_CONTENT_MODEL) {
|
||||
++mContentUpdateNestLevel;
|
||||
}
|
||||
NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType));
|
||||
|
||||
nsContentUtils::AddScriptBlocker();
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::EndUpdate(nsUpdateType aUpdateType)
|
||||
{
|
||||
nsContentUtils::RemoveScriptBlocker();
|
||||
NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType));
|
||||
|
||||
if (aUpdateType == UPDATE_CONTENT_MODEL) {
|
||||
--mContentUpdateNestLevel;
|
||||
}
|
||||
--mUpdateNestLevel;
|
||||
if (mUpdateNestLevel == 0) {
|
||||
// This set of updates may have created XBL bindings. Let the
|
||||
@ -2719,10 +2725,6 @@ nsDocument::EndUpdate(nsUpdateType aUpdateType)
|
||||
mBindingManager->EndOutermostUpdate();
|
||||
}
|
||||
|
||||
if (mScriptLoader) {
|
||||
mScriptLoader->RemoveExecuteBlocker();
|
||||
}
|
||||
|
||||
if (mUpdateNestLevel == 0) {
|
||||
PRUint32 length = mFinalizableFrameLoaders.Length();
|
||||
if (length > 0) {
|
||||
@ -2735,6 +2737,18 @@ nsDocument::EndUpdate(nsUpdateType aUpdateType)
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsDocument::GetUpdateNestingLevel()
|
||||
{
|
||||
return mUpdateNestLevel;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDocument::AllUpdatesAreContent()
|
||||
{
|
||||
return mContentUpdateNestLevel == mUpdateNestLevel;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::BeginLoad()
|
||||
{
|
||||
@ -5816,6 +5830,8 @@ nsDocument::MutationEventDispatched(nsINode* aTarget)
|
||||
|
||||
PRInt32 realTargetCount = realTargets.Count();
|
||||
for (PRInt32 k = 0; k < realTargetCount; ++k) {
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(this);
|
||||
|
||||
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_SUBTREEMODIFIED);
|
||||
nsEventDispatcher::Dispatch(realTargets[k], nsnull, &mutation);
|
||||
}
|
||||
|
@ -474,6 +474,8 @@ public:
|
||||
// observers.
|
||||
virtual void BeginUpdate(nsUpdateType aUpdateType);
|
||||
virtual void EndUpdate(nsUpdateType aUpdateType);
|
||||
virtual PRUint32 GetUpdateNestingLevel();
|
||||
virtual PRBool AllUpdatesAreContent();
|
||||
virtual void BeginLoad();
|
||||
virtual void EndLoad();
|
||||
virtual void ContentStatesChanged(nsIContent* aContent1,
|
||||
@ -799,6 +801,8 @@ protected:
|
||||
|
||||
// Our update nesting level
|
||||
PRUint32 mUpdateNestLevel;
|
||||
// Our UPDATE_CONTENT_MODEL update nesting level
|
||||
PRUint32 mContentUpdateNestLevel;
|
||||
|
||||
private:
|
||||
friend class nsUnblockOnloadEvent;
|
||||
|
@ -492,6 +492,8 @@ nsGenericDOMDataNode::SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
|
||||
mutation.mNewAttrValue = do_GetAtom(val);
|
||||
}
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(document);
|
||||
|
||||
mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
|
||||
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
|
||||
}
|
||||
|
@ -2758,6 +2758,9 @@ nsGenericElement::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
|
||||
NS_EVENT_BITS_MUTATION_NODEINSERTED, container)) {
|
||||
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
|
||||
mutation.mRelatedNode = do_QueryInterface(container);
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(aDocument);
|
||||
|
||||
mozAutoSubtreeModified subtree(container->GetOwnerDoc(), container);
|
||||
nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
|
||||
}
|
||||
@ -2825,6 +2828,9 @@ nsGenericElement::doRemoveChildAt(PRUint32 aIndex, PRBool aNotify,
|
||||
NS_EVENT_BITS_MUTATION_NODEREMOVED, container)) {
|
||||
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED);
|
||||
mutation.mRelatedNode = do_QueryInterface(container);
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(aDocument);
|
||||
|
||||
subtree.UpdateTarget(container->GetOwnerDoc(), container);
|
||||
nsEventDispatcher::Dispatch(aKid, nsnull, &mutation);
|
||||
}
|
||||
@ -3792,6 +3798,9 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
|
||||
mutation.mPrevAttrValue = do_GetAtom(aOldValue);
|
||||
}
|
||||
mutation.mAttrChange = modType;
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(document);
|
||||
|
||||
mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
|
||||
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
|
||||
}
|
||||
@ -4039,6 +4048,8 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
mutation.mPrevAttrValue = do_GetAtom(value);
|
||||
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(document);
|
||||
|
||||
mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
|
||||
nsEventDispatcher::Dispatch(this, nsnull, &mutation);
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "nsDOMAttributeMap.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
class nsIDOMAttr;
|
||||
class nsIDOMEventListener;
|
||||
@ -1066,4 +1067,33 @@ private:
|
||||
nsRefPtr<nsGenericElement> mContent;
|
||||
};
|
||||
|
||||
class mozAutoDocUpdateContentUnnest
|
||||
{
|
||||
public:
|
||||
mozAutoDocUpdateContentUnnest(nsIDocument* aDocument)
|
||||
{
|
||||
if (aDocument) {
|
||||
NS_ASSERTION(aDocument->AllUpdatesAreContent(),
|
||||
"There are non-content updates in progress");
|
||||
mNestingLevel = aDocument->GetUpdateNestingLevel();
|
||||
for (PRUint32 i = 0; i < mNestingLevel; ++i) {
|
||||
nsContentUtils::RemoveScriptBlocker();
|
||||
}
|
||||
}
|
||||
else {
|
||||
mNestingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~mozAutoDocUpdateContentUnnest()
|
||||
{
|
||||
for (PRUint32 i = 0; i < mNestingLevel; ++i) {
|
||||
nsContentUtils::AddScriptBlocker();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32 mNestingLevel;
|
||||
};
|
||||
|
||||
#endif /* nsGenericElement_h___ */
|
||||
|
@ -127,10 +127,11 @@ nsAsyncInstantiateEvent::Run()
|
||||
mContent->mPendingInstantiateEvent = nsnull;
|
||||
|
||||
// Make sure that we still have the right frame (NOTE: we don't need to check
|
||||
// the type here - GetFrame() only returns object frames, and that means we're
|
||||
// a plugin)
|
||||
// the type here - GetExistingFrame() only returns object frames, and that
|
||||
// means we're a plugin)
|
||||
// Also make sure that we still refer to the same data.
|
||||
nsIObjectFrame* frame = mContent->GetFrame(PR_FALSE);
|
||||
nsIObjectFrame* frame = mContent->
|
||||
GetExistingFrame(nsObjectLoadingContent::eFlushContent);
|
||||
if (frame == mFrame &&
|
||||
mContent->mURI == mURI &&
|
||||
mContent->mContentType.Equals(mContentType)) {
|
||||
@ -519,7 +520,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte
|
||||
notifier.Notify();
|
||||
}
|
||||
nsIObjectFrame* frame;
|
||||
frame = GetFrame(PR_TRUE);
|
||||
frame = GetExistingFrame(eFlushLayout);
|
||||
if (!frame) {
|
||||
// Do nothing in this case: This is probably due to a display:none
|
||||
// frame. If we ever get a frame, HasNewFrame will do the right thing.
|
||||
@ -585,7 +586,7 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest, nsISupports *aConte
|
||||
#endif
|
||||
Fallback(PR_FALSE);
|
||||
} else if (mType == eType_Plugin) {
|
||||
nsIObjectFrame* frame = GetFrame(PR_FALSE);
|
||||
nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
|
||||
if (frame) {
|
||||
// We have to notify the wrapper here instead of right after
|
||||
// Instantiate because the plugin only gets instantiated by
|
||||
@ -674,7 +675,7 @@ nsObjectLoadingContent::EnsureInstantiation(nsIPluginInstance** aInstance)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIObjectFrame* frame = GetFrame(PR_FALSE);
|
||||
nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
|
||||
if (frame) {
|
||||
// If we have a frame, we may have pending instantiate events; revoke
|
||||
// them.
|
||||
@ -711,7 +712,7 @@ nsObjectLoadingContent::EnsureInstantiation(nsIPluginInstance** aInstance)
|
||||
|
||||
mInstantiating = PR_FALSE;
|
||||
|
||||
frame = GetFrame(PR_FALSE);
|
||||
frame = GetExistingFrame(eFlushContent);
|
||||
if (!frame) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -774,6 +775,19 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::GetPluginInstance(nsIPluginInstance** aInstance)
|
||||
{
|
||||
*aInstance = nsnull;
|
||||
|
||||
nsIObjectFrame* objFrame = GetExistingFrame(eDontFlush);
|
||||
if (!objFrame) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return objFrame->GetPluginInstance(*aInstance);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
|
||||
PRUint32* aType)
|
||||
@ -1547,13 +1561,12 @@ nsObjectLoadingContent::GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI)
|
||||
}
|
||||
|
||||
nsIObjectFrame*
|
||||
nsObjectLoadingContent::GetFrame(PRBool aFlushLayout)
|
||||
nsObjectLoadingContent::GetExistingFrame(FlushType aFlushType)
|
||||
{
|
||||
nsCOMPtr<nsIContent> thisContent =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
NS_ASSERTION(thisContent, "must be a content");
|
||||
|
||||
PRBool flushed = PR_FALSE;
|
||||
nsIFrame* frame;
|
||||
do {
|
||||
nsIDocument* doc = thisContent->GetCurrentDoc();
|
||||
@ -1571,17 +1584,17 @@ nsObjectLoadingContent::GetFrame(PRBool aFlushLayout)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (flushed) {
|
||||
if (aFlushType == eDontFlush) {
|
||||
break;
|
||||
}
|
||||
|
||||
// OK, let's flush out and try again. Note that we want to reget
|
||||
// the document, etc, since flushing might run script.
|
||||
mozFlushType flushType =
|
||||
aFlushLayout ? Flush_Layout : Flush_ContentAndNotify;
|
||||
aFlushType == eFlushLayout ? Flush_Layout : Flush_ContentAndNotify;
|
||||
doc->FlushPendingNotifications(flushType);
|
||||
|
||||
flushed = PR_TRUE;
|
||||
aFlushType = eDontFlush;
|
||||
} while (1);
|
||||
|
||||
nsIObjectFrame* objFrame;
|
||||
@ -1610,7 +1623,7 @@ nsresult
|
||||
nsObjectLoadingContent::TryInstantiate(const nsACString& aMIMEType,
|
||||
nsIURI* aURI)
|
||||
{
|
||||
nsIObjectFrame* frame = GetFrame(PR_FALSE);
|
||||
nsIObjectFrame* frame = GetExistingFrame(eFlushContent);
|
||||
if (!frame) {
|
||||
LOG(("OBJLC [%p]: No frame yet\n", this));
|
||||
return NS_OK; // Not a failure to have no frame
|
||||
|
@ -271,14 +271,27 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
*/
|
||||
void GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the frame that's associated with this content node in
|
||||
* presentation 0. If aFlushLayout is true, this function will
|
||||
* flush layout before trying to get the frame. This is needed
|
||||
* in some cases by plug-ins to ensure that NPP_SetWindow() gets
|
||||
* called (from nsObjectFrame::DidReflow).
|
||||
* presentation 0. Always returns null if the node doesn't currently
|
||||
* have a frame.
|
||||
*
|
||||
* @param aFlush When eFlushContent will flush content notifications
|
||||
* before returning a non-null value.
|
||||
* When eFlushLayout will flush layout and content
|
||||
* notifications before returning a non-null value.
|
||||
* When eDontFlush will never flush.
|
||||
*
|
||||
* eFlushLayout is needed in some cases by plug-ins to ensure
|
||||
* that NPP_SetWindow() gets called (from nsObjectFrame::DidReflow).
|
||||
*/
|
||||
nsIObjectFrame* GetFrame(PRBool aFlushLayout);
|
||||
enum FlushType {
|
||||
eFlushContent,
|
||||
eFlushLayout,
|
||||
eDontFlush
|
||||
};
|
||||
nsIObjectFrame* GetExistingFrame(FlushType aFlushType);
|
||||
|
||||
/**
|
||||
* Handle being blocked by a content policy. aStatus is the nsresult
|
||||
@ -408,7 +421,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
// Whether we fell back because of an unsupported type
|
||||
PRBool mTypeUnsupported:1;
|
||||
|
||||
friend struct nsAsyncInstantiateEvent;
|
||||
friend class nsAsyncInstantiateEvent;
|
||||
};
|
||||
|
||||
|
||||
|
@ -159,8 +159,7 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest)
|
||||
nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
|
||||
: mDocument(aDocument),
|
||||
mBlockerCount(0),
|
||||
mEnabled(PR_TRUE),
|
||||
mHadPendingScripts(PR_FALSE)
|
||||
mEnabled(PR_TRUE)
|
||||
{
|
||||
}
|
||||
|
||||
@ -491,7 +490,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
|
||||
// If we've got existing pending requests, add ourselves
|
||||
// to this list.
|
||||
if (mPendingRequests.Count() == 0 && ReadyToExecuteScripts()) {
|
||||
if (mPendingRequests.Count() == 0 && ReadyToExecuteScripts() &&
|
||||
nsContentUtils::IsSafeToRunScript()) {
|
||||
return ProcessRequest(request);
|
||||
}
|
||||
}
|
||||
@ -500,6 +500,14 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
NS_ENSURE_TRUE(mPendingRequests.AppendObject(request),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// If there weren't any pending requests before, and this one is
|
||||
// ready to execute, do that as soon as it's safe.
|
||||
if (mPendingRequests.Count() == 1 && !request->mLoading &&
|
||||
ReadyToExecuteScripts()) {
|
||||
nsContentUtils::AddScriptRunner(new nsRunnableMethod<nsScriptLoader>(this,
|
||||
&nsScriptLoader::ProcessPendingRequests));
|
||||
}
|
||||
|
||||
// Added as pending request, now we can send blocking back
|
||||
return NS_ERROR_HTMLPARSER_BLOCK;
|
||||
}
|
||||
@ -507,7 +515,7 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
nsresult
|
||||
nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
|
||||
{
|
||||
NS_ASSERTION(ReadyToExecuteScripts(),
|
||||
NS_ASSERTION(ReadyToExecuteScripts() && nsContentUtils::IsSafeToRunScript(),
|
||||
"Caller forgot to check ReadyToExecuteScripts()");
|
||||
|
||||
NS_ENSURE_ARG(aRequest);
|
||||
|
@ -147,31 +147,15 @@ public:
|
||||
/**
|
||||
* Add/remove blocker. Blockers will stop scripts from executing, but not
|
||||
* from loading.
|
||||
* NOTE! Calling RemoveExecuteBlocker could potentially execute pending
|
||||
* scripts synchronously. In other words, it should not be done at 'unsafe'
|
||||
* times
|
||||
*/
|
||||
void AddExecuteBlocker()
|
||||
{
|
||||
if (!mBlockerCount++) {
|
||||
mHadPendingScripts = mPendingRequests.Count() != 0;
|
||||
}
|
||||
++mBlockerCount;
|
||||
}
|
||||
void RemoveExecuteBlocker()
|
||||
{
|
||||
if (!--mBlockerCount) {
|
||||
// If there were pending scripts then the newly added scripts will
|
||||
// execute once whatever event triggers the pending scripts fires.
|
||||
// However, due to synchronous loads and pushed event queues it's
|
||||
// possible that the requests that were there have already been processed
|
||||
// if so we need to process any new requests asynchronously.
|
||||
// Ideally that should be fixed such that it can't happen.
|
||||
if (mHadPendingScripts) {
|
||||
ProcessPendingRequestsAsync();
|
||||
}
|
||||
else {
|
||||
ProcessPendingRequests();
|
||||
}
|
||||
ProcessPendingRequestsAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +230,6 @@ protected:
|
||||
nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
|
||||
PRUint32 mBlockerCount;
|
||||
PRPackedBool mEnabled;
|
||||
PRPackedBool mHadPendingScripts;
|
||||
};
|
||||
|
||||
#endif //__nsScriptLoader_h__
|
||||
|
@ -972,28 +972,13 @@ nsBindingManager::ProcessAttachedQueue(PRUint32 aSkipSize)
|
||||
mProcessingAttachedStack = PR_TRUE;
|
||||
|
||||
PRUint32 currentIndex = aSkipSize;
|
||||
// Excute constructors. Do this from high index to low
|
||||
while (mAttachedStack.Length() > aSkipSize) {
|
||||
// First install all implementations. Do this from low index to high
|
||||
// since that way we'll automatically get any new bindings added in the
|
||||
// process.
|
||||
for (; currentIndex < mAttachedStack.Length(); ++currentIndex) {
|
||||
nsRefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(currentIndex);
|
||||
if (binding) {
|
||||
nsresult rv = binding->EnsureScriptAPI();
|
||||
if (NS_FAILED(rv)) {
|
||||
mAttachedStack[currentIndex] = nsnull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then excute constructors. Do this from high index to low
|
||||
while (currentIndex > aSkipSize && currentIndex == mAttachedStack.Length()) {
|
||||
--currentIndex;
|
||||
nsRefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(currentIndex);
|
||||
mAttachedStack.RemoveElementAt(currentIndex);
|
||||
if (binding) {
|
||||
binding->ExecuteAttachedHandler();
|
||||
}
|
||||
PRUint32 lastItem = mAttachedStack.Length() - 1;
|
||||
nsRefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem);
|
||||
mAttachedStack.RemoveElementAt(lastItem);
|
||||
if (binding) {
|
||||
binding->ExecuteAttachedHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1537,16 +1522,6 @@ nsBindingManager::EndOutermostUpdate()
|
||||
ProcessAttachedQueue(mAttachedStackSizeOnOutermost);
|
||||
mAttachedStackSizeOnOutermost = 0;
|
||||
}
|
||||
else {
|
||||
PRUint32 i = mAttachedStackSizeOnOutermost;
|
||||
for (; i < mAttachedStack.Length(); ++i) {
|
||||
nsRefPtr<nsXBLBinding> binding = mAttachedStack[i];
|
||||
nsresult rv = binding->EnsureScriptAPI();
|
||||
if (NS_FAILED(rv)) {
|
||||
mAttachedStack[i] = nsnull;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -272,8 +272,7 @@ nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
|
||||
: mPrototypeBinding(aBinding),
|
||||
mInsertionPointTable(nsnull),
|
||||
mIsStyleBinding(PR_TRUE),
|
||||
mMarkedForDeath(PR_FALSE),
|
||||
mInstalledAPI(PR_FALSE)
|
||||
mMarkedForDeath(PR_FALSE)
|
||||
{
|
||||
NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
|
||||
// Grab a ref to the document info so the prototype binding won't die
|
||||
@ -786,22 +785,6 @@ nsXBLBinding::GenerateAnonymousContent()
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLBinding::EnsureScriptAPI()
|
||||
{
|
||||
if (mInstalledAPI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Set mInstalledAPI right away since we'll recurse into here from
|
||||
// nsElementSH::PostCreate when InstallImplementation is called.
|
||||
mInstalledAPI = PR_TRUE;
|
||||
|
||||
InstallEventHandlers();
|
||||
|
||||
return InstallImplementation();
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLBinding::InstallEventHandlers()
|
||||
{
|
||||
|
@ -120,7 +120,8 @@ public:
|
||||
|
||||
void GenerateAnonymousContent();
|
||||
void InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement);
|
||||
nsresult EnsureScriptAPI();
|
||||
void InstallEventHandlers();
|
||||
nsresult InstallImplementation();
|
||||
|
||||
void ExecuteAttachedHandler();
|
||||
void ExecuteDetachedHandler();
|
||||
@ -167,11 +168,6 @@ public:
|
||||
|
||||
// MEMBER VARIABLES
|
||||
protected:
|
||||
// These two functions recursively install the event handlers
|
||||
// and implementation on this binding and its base class bindings.
|
||||
// External callers should call EnsureScriptAPI instead.
|
||||
void InstallEventHandlers();
|
||||
nsresult InstallImplementation();
|
||||
|
||||
nsAutoRefCnt mRefCnt;
|
||||
nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
|
||||
@ -185,7 +181,6 @@ protected:
|
||||
|
||||
PRPackedBool mIsStyleBinding;
|
||||
PRPackedBool mMarkedForDeath;
|
||||
PRPackedBool mInstalledAPI;
|
||||
};
|
||||
|
||||
#endif // nsXBLBinding_h_
|
||||
|
@ -563,6 +563,13 @@ nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
|
||||
// Tell the binding to build the anonymous content.
|
||||
newBinding->GenerateAnonymousContent();
|
||||
|
||||
// Tell the binding to install event handlers
|
||||
newBinding->InstallEventHandlers();
|
||||
|
||||
// Set up our properties
|
||||
rv = newBinding->InstallImplementation();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Figure out if we have any scoped sheets. If so, we do a second resolve.
|
||||
*aResolveStyle = newBinding->HasStyleSheets();
|
||||
|
||||
|
@ -1393,6 +1393,8 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify)
|
||||
mutation.mPrevAttrValue = do_GetAtom(oldValue);
|
||||
mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
|
||||
|
||||
mozAutoDocUpdateContentUnnest updateUnnest(doc);
|
||||
|
||||
mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
|
||||
nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
||||
nsnull, &mutation);
|
||||
|
@ -59,6 +59,8 @@
|
||||
#include "prprf.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
// JavaScript includes
|
||||
#include "jsapi.h"
|
||||
@ -7139,20 +7141,17 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
// We must ensure that the XBL Binding is installed before we hand
|
||||
// back this object.
|
||||
|
||||
nsRefPtr<nsXBLBinding> binding;
|
||||
if (content->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) &&
|
||||
(binding = doc->BindingManager()->GetBinding(content))) {
|
||||
// There's already a binding for this element, make sure that
|
||||
// the script API has been installed.
|
||||
// Note that this could end up recusing into code that calls
|
||||
// WrapNative. So don't do anything important beyond this point
|
||||
// as that will not be done to the wrapper returned from that
|
||||
// WrapNative call.
|
||||
// In theory we could also call ExecuteAttachedHandler here if
|
||||
// we also removed the binding from the PAQ queue, but that seems
|
||||
// like a scary change that would mosly just add more inconsistencies.
|
||||
doc->BindingManager()->GetBinding(content)) {
|
||||
// There's already a binding for this element so nothing left to
|
||||
// be done here.
|
||||
|
||||
return binding->EnsureScriptAPI();
|
||||
// In theory we could call ExecuteAttachedHandler here when it's safe to
|
||||
// run script if we also removed the binding from the PAQ queue, but that
|
||||
// seems like a scary change that would mosly just add more
|
||||
// inconsistencies.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// See if we have a frame.
|
||||
@ -7176,6 +7175,7 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
|
||||
// Make sure the style context goes away _before_ we execute the binding
|
||||
// constructor, since the constructor can destroy the relevant presshell.
|
||||
nsRefPtr<nsXBLBinding> binding;
|
||||
{
|
||||
// Scope for the nsRefPtr
|
||||
nsRefPtr<nsStyleContext> sc = pctx->StyleSet()->ResolveStyleFor(content,
|
||||
@ -7200,17 +7200,13 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
}
|
||||
|
||||
if (binding) {
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool safeToRunScript = PR_FALSE;
|
||||
pctx->PresShell()->IsSafeToFlush(safeToRunScript);
|
||||
NS_ASSERTION(safeToRunScript, "Wrapping when it's not safe to flush");
|
||||
#endif
|
||||
|
||||
rv = binding->EnsureScriptAPI();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
binding->ExecuteAttachedHandler();
|
||||
if (nsContentUtils::IsSafeToRunScript()) {
|
||||
binding->ExecuteAttachedHandler();
|
||||
}
|
||||
else {
|
||||
nsContentUtils::AddScriptRunner(new nsRunnableMethod<nsXBLBinding>(
|
||||
binding, &nsXBLBinding::ExecuteAttachedHandler));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -8801,17 +8797,24 @@ nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsHTMLPluginObjElementSH::GetPluginInstance(nsIXPConnectWrappedNative *wrapper,
|
||||
nsIPluginInstance **_result)
|
||||
nsHTMLPluginObjElementSH::GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *wrapper,
|
||||
nsIPluginInstance **_result)
|
||||
{
|
||||
*_result = nsnull;
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryWrappedNative(wrapper));
|
||||
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Make sure that there is a plugin
|
||||
nsCOMPtr<nsIObjectLoadingContent> objlc(do_QueryInterface(content));
|
||||
NS_ASSERTION(objlc, "Object nodes must implement nsIObjectLoadingContent");
|
||||
|
||||
// If it's not safe to run script we'll only return the instance if it
|
||||
// exists.
|
||||
if (!nsContentUtils::IsSafeToRunScript()) {
|
||||
return objlc->GetPluginInstance(_result);
|
||||
}
|
||||
|
||||
// Make sure that there is a plugin
|
||||
return objlc->EnsureInstantiation(_result);
|
||||
}
|
||||
|
||||
@ -8837,22 +8840,51 @@ IsObjInProtoChain(JSContext *cx, JSObject *obj, JSObject *proto)
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Note that not only XPConnect calls this PostCreate() method when
|
||||
// it creates wrappers, nsObjectFrame also calls this method when a
|
||||
// plugin is loaded if the embed/object element is already wrapped to
|
||||
// get the scriptable plugin inserted into the embed/object's proto
|
||||
// chain.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx, JSObject *obj)
|
||||
class nsPluginProtoChainInstallRunner : public nsIRunnable
|
||||
{
|
||||
nsresult rv = nsElementSH::PostCreate(wrapper, cx, obj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsPluginProtoChainInstallRunner(nsIXPConnectWrappedNative* wrapper,
|
||||
nsIScriptContext* scriptContext)
|
||||
: mWrapper(wrapper),
|
||||
mContext(scriptContext)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
JSObject* obj = nsnull;
|
||||
mWrapper->GetJSObject(&obj);
|
||||
NS_ASSERTION(obj, "Should never be null");
|
||||
nsHTMLPluginObjElementSH::SetupProtoChain(
|
||||
mWrapper, (JSContext*)mContext->GetNativeContext(), obj);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> mWrapper;
|
||||
nsCOMPtr<nsIScriptContext> mContext;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsPluginProtoChainInstallRunner, nsIRunnable)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsHTMLPluginObjElementSH::SetupProtoChain(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx,
|
||||
JSObject *obj)
|
||||
{
|
||||
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
|
||||
"Shouldn't have gotten in here");
|
||||
|
||||
nsCxPusher cxPusher;
|
||||
if (!cxPusher.Push(cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPluginInstance> pi;
|
||||
rv = GetPluginInstance(wrapper, getter_AddRefs(pi));
|
||||
nsresult rv = GetPluginInstanceIfSafe(wrapper, getter_AddRefs(pi));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!pi) {
|
||||
@ -8876,7 +8908,7 @@ nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
||||
if (IsObjInProtoChain(cx, obj, pi_obj)) {
|
||||
// We must have re-entered ::PostCreate() from nsObjectFrame()
|
||||
// (through the EnsureInstantiation() call in
|
||||
// GetPluginInstance()), this means that we've already done what
|
||||
// GetPluginInstanceIfSafe()), this means that we've already done what
|
||||
// we're about to do in this function so we can just return here.
|
||||
|
||||
return NS_OK;
|
||||
@ -8966,6 +8998,26 @@ nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx, JSObject *obj)
|
||||
{
|
||||
nsresult rv = nsElementSH::PostCreate(wrapper, cx, obj);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (nsContentUtils::IsSafeToRunScript()) {
|
||||
return SetupProtoChain(wrapper, cx, obj);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext =
|
||||
GetScriptContextFromJSContext(cx);
|
||||
NS_ENSURE_TRUE(scriptContext, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new nsPluginProtoChainInstallRunner(wrapper, scriptContext));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
|
||||
@ -9067,7 +9119,7 @@ nsHTMLPluginObjElementSH::Call(nsIXPConnectWrappedNative *wrapper,
|
||||
jsval *argv, jsval *vp, PRBool *_retval)
|
||||
{
|
||||
nsCOMPtr<nsIPluginInstance> pi;
|
||||
nsresult rv = GetPluginInstance(wrapper, getter_AddRefs(pi));
|
||||
nsresult rv = GetPluginInstanceIfSafe(wrapper, getter_AddRefs(pi));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!pi) {
|
||||
@ -9284,7 +9336,7 @@ nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
|
||||
// plugin instances.
|
||||
|
||||
nsCOMPtr<nsIPluginInstance> pi;
|
||||
nsresult rv = GetPluginInstance(wrapper, getter_AddRefs(pi));
|
||||
nsresult rv = GetPluginInstanceIfSafe(wrapper, getter_AddRefs(pi));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPluginInstanceInternal> plugin_internal =
|
||||
|
@ -977,8 +977,8 @@ protected:
|
||||
{
|
||||
}
|
||||
|
||||
nsresult GetPluginInstance(nsIXPConnectWrappedNative *aWrapper,
|
||||
nsIPluginInstance **aResult);
|
||||
static nsresult GetPluginInstanceIfSafe(nsIXPConnectWrappedNative *aWrapper,
|
||||
nsIPluginInstance **aResult);
|
||||
|
||||
static nsresult GetPluginJSObject(JSContext *cx, JSObject *obj,
|
||||
nsIPluginInstance *plugin_inst,
|
||||
@ -1004,6 +1004,10 @@ public:
|
||||
JSObject *obj, PRUint32 argc, jsval *argv, jsval *vp,
|
||||
PRBool *_retval);
|
||||
|
||||
|
||||
static nsresult SetupProtoChain(nsIXPConnectWrappedNative *wrapper,
|
||||
JSContext *cx, JSObject *obj);
|
||||
|
||||
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
|
||||
{
|
||||
return new nsHTMLPluginObjElementSH(aData);
|
||||
|
@ -1048,6 +1048,8 @@ DocumentViewerImpl::PermitUnload(PRBool *aPermitUnload)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), "This is unsafe");
|
||||
|
||||
// Now, fire an BeforeUnload event to the document and see if it's ok
|
||||
// to unload...
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
@ -760,6 +760,7 @@ struct nsCallbackEventRequest
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class nsPresShellEventCB;
|
||||
class nsAutoCauseReflowNotifier;
|
||||
|
||||
class PresShell : public nsIPresShell, public nsIViewObserver,
|
||||
public nsStubDocumentObserver,
|
||||
@ -1009,8 +1010,14 @@ protected:
|
||||
|
||||
void UnsuppressAndInvalidate();
|
||||
|
||||
void WillCauseReflow() { ++mChangeNestCount; }
|
||||
|
||||
void WillCauseReflow() {
|
||||
nsContentUtils::AddScriptBlocker();
|
||||
++mChangeNestCount;
|
||||
}
|
||||
nsresult DidCauseReflow();
|
||||
friend class nsAutoCauseReflowNotifier;
|
||||
|
||||
void WillDoReflow();
|
||||
void DidDoReflow();
|
||||
nsresult ProcessReflowCommands(PRBool aInterruptible);
|
||||
@ -1209,6 +1216,29 @@ private:
|
||||
nsPluginEnumCallback aCallback);
|
||||
};
|
||||
|
||||
class nsAutoCauseReflowNotifier
|
||||
{
|
||||
public:
|
||||
nsAutoCauseReflowNotifier(PresShell* aShell)
|
||||
: mShell(aShell)
|
||||
{
|
||||
mShell->WillCauseReflow();
|
||||
}
|
||||
~nsAutoCauseReflowNotifier()
|
||||
{
|
||||
// This check should not be needed. Currently the only place that seem
|
||||
// to need it is the code that deals with bug 337586.
|
||||
if (!mShell->mHaveShutDown) {
|
||||
mShell->DidCauseReflow();
|
||||
}
|
||||
else {
|
||||
nsContentUtils::RemoveScriptBlocker();
|
||||
}
|
||||
}
|
||||
|
||||
PresShell* mShell;
|
||||
};
|
||||
|
||||
class nsPresShellEventCB : public nsDispatchingCallback
|
||||
{
|
||||
public:
|
||||
@ -2383,31 +2413,35 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
MOZ_TIMER_RESET(mFrameCreationWatch);
|
||||
MOZ_TIMER_START(mFrameCreationWatch);
|
||||
|
||||
WillCauseReflow();
|
||||
mFrameConstructor->BeginUpdate();
|
||||
{
|
||||
nsAutoCauseReflowNotifier reflowNotifier(this);
|
||||
mFrameConstructor->BeginUpdate();
|
||||
|
||||
if (!rootFrame) {
|
||||
// Have style sheet processor construct a frame for the
|
||||
// precursors to the root content object's frame
|
||||
mFrameConstructor->ConstructRootFrame(root, &rootFrame);
|
||||
FrameManager()->SetRootFrame(rootFrame);
|
||||
if (!rootFrame) {
|
||||
// Have style sheet processor construct a frame for the
|
||||
// precursors to the root content object's frame
|
||||
mFrameConstructor->ConstructRootFrame(root, &rootFrame);
|
||||
FrameManager()->SetRootFrame(rootFrame);
|
||||
}
|
||||
|
||||
// Have the style sheet processor construct frame for the root
|
||||
// content object down
|
||||
mFrameConstructor->ContentInserted(nsnull, root, 0, nsnull);
|
||||
VERIFY_STYLE_TREE;
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
|
||||
(void*)this));
|
||||
MOZ_TIMER_STOP(mFrameCreationWatch);
|
||||
|
||||
// Something in mFrameConstructor->ContentInserted may have caused
|
||||
// Destroy() to get called, bug 337586.
|
||||
NS_ENSURE_STATE(!mHaveShutDown);
|
||||
|
||||
mFrameConstructor->EndUpdate();
|
||||
}
|
||||
|
||||
// Have the style sheet processor construct frame for the root
|
||||
// content object down
|
||||
mFrameConstructor->ContentInserted(nsnull, root, 0, nsnull);
|
||||
VERIFY_STYLE_TREE;
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::InitialReflow(), this=%p\n",
|
||||
(void*)this));
|
||||
MOZ_TIMER_STOP(mFrameCreationWatch);
|
||||
|
||||
// Something in mFrameConstructor->ContentInserted may have caused
|
||||
// Destroy() to get called, bug 337586.
|
||||
// DidCauseReflow may have killed us too
|
||||
NS_ENSURE_STATE(!mHaveShutDown);
|
||||
|
||||
mFrameConstructor->EndUpdate();
|
||||
DidCauseReflow();
|
||||
|
||||
// Run the XBL binding constructors for any new frames we've constructed
|
||||
mDocument->BindingManager()->ProcessAttachedQueue();
|
||||
|
||||
@ -2525,10 +2559,10 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
|
||||
// XXX Do a full invalidate at the beginning so that invalidates along
|
||||
// the way don't have region accumulation issues?
|
||||
|
||||
WillCauseReflow();
|
||||
WillDoReflow();
|
||||
|
||||
{
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
WillDoReflow();
|
||||
|
||||
// Kick off a top-down reflow
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
mIsReflowing = PR_TRUE;
|
||||
@ -2538,7 +2572,6 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight)
|
||||
mIsReflowing = PR_FALSE;
|
||||
}
|
||||
|
||||
DidCauseReflow();
|
||||
DidDoReflow();
|
||||
}
|
||||
|
||||
@ -3086,6 +3119,7 @@ PresShell::RestoreRootScrollPosition()
|
||||
// we're scrolling to our restored position. Entering reflow for the
|
||||
// scrollable frame will cause it to reenter ScrollToRestoredPosition(), and
|
||||
// it'll get all confused.
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
++mChangeNestCount;
|
||||
|
||||
if (historyState) {
|
||||
@ -3376,6 +3410,8 @@ PresShell::RecreateFramesFor(nsIContent* aContent)
|
||||
// start messing with the frame model; otherwise we can get content doubling.
|
||||
mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
nsStyleChangeList changeList;
|
||||
changeList.AppendChange(nsnull, aContent, nsChangeHint_ReconstructFrame);
|
||||
|
||||
@ -4467,12 +4503,16 @@ PresShell::HandlePostedReflowCallbacks()
|
||||
NS_IMETHODIMP
|
||||
PresShell::IsSafeToFlush(PRBool& aIsSafeToFlush)
|
||||
{
|
||||
aIsSafeToFlush = PR_TRUE;
|
||||
// XXX technically we don't need to check anything but
|
||||
// nsContentUtils::IsSafeToRunScript here since that should be false
|
||||
// if any of the other flags are set.
|
||||
|
||||
// Not safe if we are reflowing or in the middle of frame construction
|
||||
aIsSafeToFlush = nsContentUtils::IsSafeToRunScript() &&
|
||||
!mIsReflowing &&
|
||||
!mChangeNestCount;
|
||||
|
||||
if (mIsReflowing || mChangeNestCount) {
|
||||
// Not safe if we are reflowing or in the middle of frame construction
|
||||
aIsSafeToFlush = PR_FALSE;
|
||||
} else {
|
||||
if (aIsSafeToFlush) {
|
||||
// Not safe if we are painting
|
||||
nsIViewManager* viewManager = GetViewManager();
|
||||
if (viewManager) {
|
||||
@ -4483,6 +4523,10 @@ PresShell::IsSafeToFlush(PRBool& aIsSafeToFlush)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION(aIsSafeToFlush == nsContentUtils::IsSafeToRunScript(),
|
||||
"Someone forgot to block scripts");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -4586,7 +4630,8 @@ PresShell::CharacterDataChanged(nsIDocument *aDocument,
|
||||
NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged");
|
||||
NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
|
||||
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
|
||||
if (mCaret) {
|
||||
// Invalidate the caret's current location before we call into the frame
|
||||
// constructor. It is important to do this now, and not wait until the
|
||||
@ -4615,7 +4660,6 @@ PresShell::CharacterDataChanged(nsIDocument *aDocument,
|
||||
|
||||
mFrameConstructor->CharacterDataChanged(aContent, aInfo->mAppend);
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
}
|
||||
|
||||
void
|
||||
@ -4628,10 +4672,9 @@ PresShell::ContentStatesChanged(nsIDocument* aDocument,
|
||||
NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument");
|
||||
|
||||
if (mDidInitialReflow) {
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
mFrameConstructor->ContentStatesChanged(aContent1, aContent2, aStateMask);
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4651,11 +4694,10 @@ PresShell::AttributeChanged(nsIDocument* aDocument,
|
||||
// initial reflow to begin observing the document. That would
|
||||
// squelch any other inappropriate notifications as well.
|
||||
if (mDidInitialReflow) {
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
mFrameConstructor->AttributeChanged(aContent, aNameSpaceID,
|
||||
aAttribute, aModType, aStateMask);
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4672,7 +4714,7 @@ PresShell::ContentAppended(nsIDocument *aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
MOZ_TIMER_DEBUGLOG(("Start: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
|
||||
MOZ_TIMER_START(mFrameCreationWatch);
|
||||
|
||||
@ -4686,7 +4728,6 @@ PresShell::ContentAppended(nsIDocument *aDocument,
|
||||
|
||||
MOZ_TIMER_DEBUGLOG(("Stop: Frame Creation: PresShell::ContentAppended(), this=%p\n", this));
|
||||
MOZ_TIMER_STOP(mFrameCreationWatch);
|
||||
DidCauseReflow();
|
||||
}
|
||||
|
||||
void
|
||||
@ -4702,7 +4743,7 @@ PresShell::ContentInserted(nsIDocument* aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
|
||||
// Call this here so it only happens for real content mutations and
|
||||
// not cases when the frame constructor calls its own methods to force
|
||||
@ -4713,7 +4754,6 @@ PresShell::ContentInserted(nsIDocument* aDocument,
|
||||
mFrameConstructor->ContentInserted(aContainer, aChild,
|
||||
aIndexInContainer, nsnull);
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
}
|
||||
|
||||
void
|
||||
@ -4734,7 +4774,7 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
|
||||
// it can clean up any state related to the content.
|
||||
mPresContext->EventStateManager()->ContentRemoved(aChild);
|
||||
|
||||
WillCauseReflow();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
|
||||
// Call this here so it only happens for real content mutations and
|
||||
// not cases when the frame constructor calls its own methods to force
|
||||
@ -4747,18 +4787,14 @@ PresShell::ContentRemoved(nsIDocument *aDocument,
|
||||
aIndexInContainer, &didReconstruct);
|
||||
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresShell::ReconstructFrames(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
WillCauseReflow();
|
||||
rv = mFrameConstructor->ReconstructDocElementHierarchy();
|
||||
nsAutoCauseReflowNotifier crNotifier(this);
|
||||
nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy();
|
||||
VERIFY_STYLE_TREE;
|
||||
DidCauseReflow();
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -5527,7 +5563,11 @@ PresShell::HandleEvent(nsIView *aView,
|
||||
{
|
||||
NS_ASSERTION(aView, "null view");
|
||||
|
||||
if (mIsDestroying || mIsReflowing || mChangeNestCount) {
|
||||
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
|
||||
"How did we get here if it's not safe to run scripts?");
|
||||
|
||||
if (mIsDestroying || mIsReflowing || mChangeNestCount ||
|
||||
!nsContentUtils::IsSafeToRunScript()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -6169,6 +6209,8 @@ PresShell::DidCauseReflow()
|
||||
PostReflowEvent();
|
||||
}
|
||||
|
||||
nsContentUtils::RemoveScriptBlocker();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -6346,6 +6388,7 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
|
||||
|
||||
// Scope for the reflow entry point
|
||||
{
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow);
|
||||
mIsReflowing = PR_TRUE;
|
||||
|
||||
@ -6375,7 +6418,10 @@ PresShell::ProcessReflowCommands(PRBool aInterruptible)
|
||||
mIsReflowing = PR_FALSE;
|
||||
}
|
||||
|
||||
DidDoReflow();
|
||||
// Exiting the scriptblocker might have killed us
|
||||
if (!mIsDestroying) {
|
||||
DidDoReflow();
|
||||
}
|
||||
|
||||
// DidDoReflow might have killed us
|
||||
if (!mIsDestroying) {
|
||||
@ -6512,9 +6558,12 @@ PresShell::Observe(nsISupports* aSubject,
|
||||
ReframeImageBoxes, &changeList);
|
||||
// Mark ourselves as not safe to flush while we're doing frame
|
||||
// construction.
|
||||
++mChangeNestCount;
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
--mChangeNestCount;
|
||||
{
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
++mChangeNestCount;
|
||||
mFrameConstructor->ProcessRestyledFrames(changeList);
|
||||
--mChangeNestCount;
|
||||
}
|
||||
|
||||
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
#ifdef ACCESSIBILITY
|
||||
|
@ -187,6 +187,7 @@ LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/../../content/xul/content/src \
|
||||
-I$(srcdir)/../../content/base/src \
|
||||
-I$(srcdir)/../../content/html/content/src \
|
||||
-I$(srcdir)/../../dom/src/base \
|
||||
$(MOZ_CAIRO_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
|
@ -108,6 +108,7 @@
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
// headers for plugin scriptability
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
@ -1856,22 +1857,8 @@ nsObjectFrame::NotifyContentObjectWrapper()
|
||||
getter_AddRefs(wrapper));
|
||||
|
||||
if (!wrapper) {
|
||||
// Nothing to do here if there's no wrapper for mContent
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIClassInfo> ci(do_QueryInterface(mContent));
|
||||
if (!ci)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsISupports> s;
|
||||
ci->GetHelperForLanguage(nsIProgrammingLanguage::JAVASCRIPT,
|
||||
getter_AddRefs(s));
|
||||
|
||||
nsCOMPtr<nsIXPCScriptable> helper(do_QueryInterface(s));
|
||||
|
||||
if (!helper) {
|
||||
// There's nothing we can do if there's no helper
|
||||
// Nothing to do here if there's no wrapper for mContent. The proto
|
||||
// chain will be fixed appropriately when the wrapper is created.
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1880,13 +1867,7 @@ nsObjectFrame::NotifyContentObjectWrapper()
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
nsCxPusher cxPusher;
|
||||
if (cxPusher.Push(mContent)) {
|
||||
// Abuse the scriptable helper to trigger prototype setup for the
|
||||
// wrapper for mContent so that this plugin becomes part of the DOM
|
||||
// object.
|
||||
helper->PostCreate(wrapper, cx, obj);
|
||||
}
|
||||
nsHTMLPluginObjElementSH::SetupProtoChain(wrapper, cx, obj);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -57,6 +57,9 @@ REQUIRES = xpcom \
|
||||
pref \
|
||||
thebes \
|
||||
cairo \
|
||||
content \
|
||||
js \
|
||||
layout \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LIBS = gkgfx
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "nsHashtable.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
|
||||
@ -452,47 +453,51 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext,
|
||||
RootViewManager()->mRecursiveRefreshPending = PR_TRUE;
|
||||
return;
|
||||
}
|
||||
SetPainting(PR_TRUE);
|
||||
|
||||
nsCOMPtr<nsIRenderingContext> localcx;
|
||||
NS_ASSERTION(aView->GetWidget(),
|
||||
"Must have a widget to calculate coordinates correctly");
|
||||
if (nsnull == aContext)
|
||||
{
|
||||
localcx = CreateRenderingContext(*aView);
|
||||
{
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
SetPainting(PR_TRUE);
|
||||
|
||||
//couldn't get rendering context. this is ok at init time atleast
|
||||
if (nsnull == localcx) {
|
||||
SetPainting(PR_FALSE);
|
||||
return;
|
||||
nsCOMPtr<nsIRenderingContext> localcx;
|
||||
NS_ASSERTION(aView->GetWidget(),
|
||||
"Must have a widget to calculate coordinates correctly");
|
||||
if (nsnull == aContext)
|
||||
{
|
||||
localcx = CreateRenderingContext(*aView);
|
||||
|
||||
//couldn't get rendering context. this is ok at init time atleast
|
||||
if (nsnull == localcx) {
|
||||
SetPainting(PR_FALSE);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// plain assignment grabs another reference.
|
||||
localcx = aContext;
|
||||
}
|
||||
} else {
|
||||
// plain assignment grabs another reference.
|
||||
localcx = aContext;
|
||||
}
|
||||
|
||||
PRInt32 p2a = mContext->AppUnitsPerDevPixel();
|
||||
PRInt32 p2a = mContext->AppUnitsPerDevPixel();
|
||||
|
||||
nsRefPtr<gfxContext> ctx = localcx->ThebesContext();
|
||||
nsRefPtr<gfxContext> ctx = localcx->ThebesContext();
|
||||
|
||||
ctx->Save();
|
||||
ctx->Save();
|
||||
|
||||
nsPoint vtowoffset = aView->ViewToWidgetOffset();
|
||||
ctx->Translate(gfxPoint(gfxFloat(vtowoffset.x) / p2a,
|
||||
gfxFloat(vtowoffset.y) / p2a));
|
||||
nsPoint vtowoffset = aView->ViewToWidgetOffset();
|
||||
ctx->Translate(gfxPoint(gfxFloat(vtowoffset.x) / p2a,
|
||||
gfxFloat(vtowoffset.y) / p2a));
|
||||
|
||||
ctx->Translate(gfxPoint(-gfxFloat(viewRect.x) / p2a,
|
||||
-gfxFloat(viewRect.y) / p2a));
|
||||
ctx->Translate(gfxPoint(-gfxFloat(viewRect.x) / p2a,
|
||||
-gfxFloat(viewRect.y) / p2a));
|
||||
|
||||
nsRegion opaqueRegion;
|
||||
AddCoveringWidgetsToOpaqueRegion(opaqueRegion, mContext, aView);
|
||||
damageRegion.Sub(damageRegion, opaqueRegion);
|
||||
nsRegion opaqueRegion;
|
||||
AddCoveringWidgetsToOpaqueRegion(opaqueRegion, mContext, aView);
|
||||
damageRegion.Sub(damageRegion, opaqueRegion);
|
||||
|
||||
RenderViews(aView, *localcx, damageRegion);
|
||||
RenderViews(aView, *localcx, damageRegion);
|
||||
|
||||
ctx->Restore();
|
||||
ctx->Restore();
|
||||
|
||||
SetPainting(PR_FALSE);
|
||||
SetPainting(PR_FALSE);
|
||||
}
|
||||
|
||||
if (RootViewManager()->mRecursiveRefreshPending) {
|
||||
// Unset this flag first, since if aUpdateFlags includes NS_VMREFRESH_IMMEDIATE
|
||||
|
Loading…
Reference in New Issue
Block a user