зеркало из https://github.com/mozilla/pjs.git
Bug 185236 part 5. Fire load and error events on stylesheet linking elements. r=peterv
This commit is contained in:
Родитель
e49d5e5860
Коммит
4d807853c0
|
@ -12,7 +12,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=364413
|
|||
<script type="text/javascript" src="/MochiKit/DOM.js"></script>
|
||||
<script type="text/javascript" src="/MochiKit/Style.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="SimpleTest/test.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=364413">Mozilla Bug 364413</a>
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsDocShellCID.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULPrototypeCache.h"
|
||||
|
@ -132,7 +133,8 @@ namespace css {
|
|||
*********************************************/
|
||||
|
||||
class SheetLoadData : public nsIRunnable,
|
||||
public nsIUnicharStreamLoaderObserver
|
||||
public nsIUnicharStreamLoaderObserver,
|
||||
public nsIThreadObserver
|
||||
{
|
||||
public:
|
||||
virtual ~SheetLoadData(void);
|
||||
|
@ -167,8 +169,11 @@ public:
|
|||
|
||||
already_AddRefed<nsIURI> GetReferrerURI();
|
||||
|
||||
void ScheduleLoadEventIfNeeded(nsresult aStatus);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSITHREADOBSERVER
|
||||
NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
|
||||
|
||||
// Hold a ref to the CSSLoader so we can call back to it to let it
|
||||
|
@ -259,6 +264,15 @@ public:
|
|||
// The charset to use if the transport and sheet don't indicate one.
|
||||
// May be empty. Must be empty if mOwningElement is non-null.
|
||||
nsCString mCharsetHint;
|
||||
|
||||
// The status our load ended up with; this determines whether we
|
||||
// should fire error events or load events. This gets initialized
|
||||
// by ScheduleLoadEventIfNeeded, and is only used after that has
|
||||
// been called.
|
||||
nsresult mStatus;
|
||||
|
||||
private:
|
||||
void FireLoadEvent(nsIThreadInternal* aThread);
|
||||
};
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
|
@ -310,7 +324,8 @@ static const char* const gStateStrings[] = {
|
|||
/********************************
|
||||
* SheetLoadData implementation *
|
||||
********************************/
|
||||
NS_IMPL_ISUPPORTS2(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable)
|
||||
NS_IMPL_ISUPPORTS3(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable,
|
||||
nsIThreadObserver)
|
||||
|
||||
SheetLoadData::SheetLoadData(Loader* aLoader,
|
||||
const nsSubstring& aTitle,
|
||||
|
@ -437,6 +452,78 @@ SheetLoadData::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SheetLoadData::OnDispatchedEvent(nsIThreadInternal* aThread)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SheetLoadData::OnProcessNextEvent(nsIThreadInternal* aThread,
|
||||
PRBool aMayWait,
|
||||
PRUint32 aRecursionDepth)
|
||||
{
|
||||
// We want to fire our load even before or after event processing,
|
||||
// whichever comes first.
|
||||
FireLoadEvent(aThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SheetLoadData::AfterProcessNextEvent(nsIThreadInternal* aThread,
|
||||
PRUint32 aRecursionDepth)
|
||||
{
|
||||
// We want to fire our load even before or after event processing,
|
||||
// whichever comes first.
|
||||
FireLoadEvent(aThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SheetLoadData::FireLoadEvent(nsIThreadInternal* aThread)
|
||||
{
|
||||
|
||||
// First remove ourselves as a thread observer. But we need to keep
|
||||
// ourselves alive while doing that!
|
||||
nsRefPtr<SheetLoadData> kungFuDeathGrip(this);
|
||||
aThread->RemoveObserver(this);
|
||||
|
||||
// Now fire the event
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(mOwningElement);
|
||||
NS_ASSERTION(node, "How did that happen???");
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(node->GetOwnerDoc(),
|
||||
node,
|
||||
NS_SUCCEEDED(mStatus) ?
|
||||
NS_LITERAL_STRING("load") :
|
||||
NS_LITERAL_STRING("error"),
|
||||
PR_FALSE, PR_FALSE);
|
||||
|
||||
// And unblock onload
|
||||
if (mLoader->mDocument) {
|
||||
mLoader->mDocument->UnblockOnload(PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SheetLoadData::ScheduleLoadEventIfNeeded(nsresult aStatus)
|
||||
{
|
||||
if (!mOwningElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
mStatus = aStatus;
|
||||
|
||||
nsCOMPtr<nsIThread> thread = do_GetMainThread();
|
||||
nsCOMPtr<nsIThreadInternal> internalThread = do_QueryInterface(thread);
|
||||
if (NS_SUCCEEDED(internalThread->AddObserver(this))) {
|
||||
// Make sure to block onload here
|
||||
if (mLoader->mDocument) {
|
||||
mLoader->mDocument->BlockOnload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Loader Implementation *
|
||||
*************************/
|
||||
|
@ -1661,6 +1748,7 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
|
|||
"should not get marked modified during parsing");
|
||||
if (!data->mSheetAlreadyComplete) {
|
||||
data->mSheet->SetComplete();
|
||||
data->ScheduleLoadEventIfNeeded(aStatus);
|
||||
}
|
||||
if (data->mMustNotify && (data->mObserver || !mObservers.IsEmpty())) {
|
||||
// Don't notify here so we don't trigger script. Remember the
|
||||
|
@ -1689,7 +1777,10 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
|
|||
data = data->mNext;
|
||||
}
|
||||
|
||||
// Now that it's marked complete, put the sheet in our cache
|
||||
// Now that it's marked complete, put the sheet in our cache.
|
||||
// If we ever start doing this for failure aStatus, we'll need to
|
||||
// adjust the PostLoadEvent code that thinks anything already
|
||||
// complete must have loaded succesfully.
|
||||
if (NS_SUCCEEDED(aStatus) && aLoadData->mURI) {
|
||||
#ifdef MOZ_XUL
|
||||
if (IsChromeURI(aLoadData->mURI)) {
|
||||
|
@ -2161,6 +2252,12 @@ Loader::PostLoadEvent(nsIURI* aURI,
|
|||
// We want to notify the observer for this data.
|
||||
evt->mMustNotify = PR_TRUE;
|
||||
evt->mSheetAlreadyComplete = PR_TRUE;
|
||||
|
||||
// If we get to this code, aSheet loaded correctly at some point, so
|
||||
// we can just use NS_OK for the status. Note that we do this here
|
||||
// and not from inside our SheetComplete so that we don't end up
|
||||
// running the load event async.
|
||||
evt->ScheduleLoadEventIfNeeded(NS_OK);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -226,6 +226,7 @@ _TEST_FILES = test_acid3_test46.html \
|
|||
visited_image_loading.sjs \
|
||||
visited_image_loading_frame.html \
|
||||
visited_image_loading_frame_empty.html \
|
||||
test_load_events_on_stylesheets.html \
|
||||
$(NULL)
|
||||
|
||||
_VISITED_REFTEST_FILES = \
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=185236
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 185236</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
var pendingEventCounter = 0;
|
||||
var messagePosted = false;
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
is(messagePosted, true, "Should have gotten onmessage event");
|
||||
is(pendingEventCounter, 0,
|
||||
"How did onload for the page fire before onload for all the stylesheets?");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
// Count the link we're about to parse
|
||||
pendingEventCounter = 1;
|
||||
</script>
|
||||
<link rel="stylesheet" href="data:text/css,*{}"
|
||||
onload="--pendingEventCounter;
|
||||
ok(true, 'Load event firing on basic stylesheet')"
|
||||
onerror="--pendingEventCounter;
|
||||
ok(false, 'Error event firing on basic stylesheet')">
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=185236">Mozilla Bug 185236</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
/** Test for Bug 185236 **/
|
||||
// Verify that there are no in-flight sheet loads right now; we should have
|
||||
// waited for them when we hit the script tag
|
||||
is(pendingEventCounter, 0, "There should be no pending events");
|
||||
|
||||
// Test sheet that will already be complete when we write it out
|
||||
++pendingEventCounter;
|
||||
|
||||
// Make sure that a postMessage we do right now fires after the onload handler
|
||||
// for the stylesheet. If we ever change the timing of sheet onload, we will
|
||||
// need to change that.
|
||||
window.onmessage = function() {
|
||||
messagePosted = true;
|
||||
// There are 4 pending events: two from the two direct example.com loads,
|
||||
// and 2 from the two data:text/css loads that import things
|
||||
is(pendingEventCounter, 4, "Load event for sheet should have fired");
|
||||
}
|
||||
window.postMessage("", "*");
|
||||
|
||||
document.write('<link rel="stylesheet" href="data:text/css,*{}"\
|
||||
onload="--pendingEventCounter;\
|
||||
ok(true, \'Load event firing on basic stylesheet\')"\
|
||||
onerror="--pendingEventCounter;\
|
||||
ok(false, \'Error event firing on basic stylesheet\')">');
|
||||
|
||||
// Make sure we have that second stylesheet
|
||||
is(document.styleSheets.length, 3, "Should have three stylesheets");
|
||||
|
||||
// Make sure that the second stylesheet is all loaded
|
||||
// If we ever switch away from sync loading of already-complete sheets, this
|
||||
// test will need adjusting
|
||||
is(document.styleSheets[2].cssRules.length, 1, "Should have one rule");
|
||||
|
||||
// Make sure the load event for that stylesheet has not fired yet
|
||||
is(pendingEventCounter, 1, "There should be one pending event");
|
||||
|
||||
++pendingEventCounter;
|
||||
document.write('<style\
|
||||
onload="--pendingEventCounter;\
|
||||
ok(true, \'Load event firing on inline stylesheet\')"\
|
||||
onerror="--pendingEventCounter;\
|
||||
ok(false, \'Error event firing on inline stylesheet\')"></style>');
|
||||
|
||||
// Make sure the load event for that second stylesheet has not fired yet
|
||||
is(pendingEventCounter, 2, "There should be two pending events");
|
||||
|
||||
++pendingEventCounter;
|
||||
document.write('<link rel="stylesheet" href="http://www.example.com"\
|
||||
onload="--pendingEventCounter;\
|
||||
ok(false, \'Load event firing on broken stylesheet\')"\
|
||||
onerror="--pendingEventCounter;\
|
||||
ok(true, \'Error event firing on broken stylesheet\')">');
|
||||
|
||||
++pendingEventCounter;
|
||||
var link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "http://www.example.com";
|
||||
link.onload = function() { --pendingEventCounter;
|
||||
ok(false, 'Load event firing on broken stylesheet');
|
||||
};
|
||||
link.onerror = function() { --pendingEventCounter;
|
||||
ok(true, 'Error event firing on broken stylesheet');
|
||||
}
|
||||
document.body.appendChild(link);
|
||||
|
||||
++pendingEventCounter;
|
||||
link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "data:text/css,*{}";
|
||||
link.onload = function() { --pendingEventCounter;
|
||||
ok(true, 'Load event firing on external stylesheet');
|
||||
};
|
||||
link.onerror = function() { --pendingEventCounter;
|
||||
ok(false, 'Error event firing on external stylesheet');
|
||||
}
|
||||
document.body.appendChild(link);
|
||||
|
||||
// Make sure we have that last stylesheet
|
||||
is(document.styleSheets.length, 7, "Should have seven stylesheets here");
|
||||
|
||||
// Make sure that the sixth stylesheet is all loaded
|
||||
// If we ever switch away from sync loading of already-complete sheets, this
|
||||
// test will need adjusting
|
||||
is(document.styleSheets[6].cssRules.length, 1, "Should have one rule");
|
||||
|
||||
++pendingEventCounter;
|
||||
link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "data:text/css,@import url('data:text/css,*{}')";
|
||||
link.onload = function() { --pendingEventCounter;
|
||||
ok(true, 'Load event firing on external stylesheet');
|
||||
};
|
||||
link.onerror = function() { --pendingEventCounter;
|
||||
ok(false, 'Error event firing on external stylesheet');
|
||||
}
|
||||
document.body.appendChild(link);
|
||||
|
||||
++pendingEventCounter;
|
||||
link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = "data:text/css,@import url('http://www.example.com')";
|
||||
link.onload = function() { --pendingEventCounter;
|
||||
ok(false, 'Load event firing on broken stylesheet');
|
||||
};
|
||||
link.onerror = function() { --pendingEventCounter;
|
||||
ok(true, 'Error event firing on broken stylesheet');
|
||||
}
|
||||
document.body.appendChild(link);
|
||||
|
||||
// Make sure the load events for all those stylesheets have not fired yet
|
||||
is(pendingEventCounter, 7, "There should be one pending event");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче