--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -158,41 +158,49 @@ nsAsyncInstantiateEvent::Run()
}
/**
* A task for firing PluginNotFound and PluginBlocklisted DOM Events.
*/
class nsPluginErrorEvent : public nsRunnable {
public:
nsCOMPtr<nsIContent> mContent;
- PRBool mBlocklisted;
+ PluginSupportState mState;
- nsPluginErrorEvent(nsIContent* aContent, PRBool aBlocklisted)
+ nsPluginErrorEvent(nsIContent* aContent, PluginSupportState aState)
: mContent(aContent),
- mBlocklisted(aBlocklisted)
+ mState(aState)
{}
~nsPluginErrorEvent() {}
NS_IMETHOD Run();
};
NS_IMETHODIMP
nsPluginErrorEvent::Run()
{
LOG(("OBJLC []: Firing plugin not found event for content %p\n",
mContent.get()));
- if (mBlocklisted)
- nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
- NS_LITERAL_STRING("PluginBlocklisted"),
- PR_TRUE, PR_TRUE);
- else
- nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
- NS_LITERAL_STRING("PluginNotFound"),
- PR_TRUE, PR_TRUE);
+ nsString type;
+ switch (mState) {
+ case ePluginUnsupported:
+ type = NS_LITERAL_STRING("PluginNotFound");
+ break;
+ case ePluginDisabled:
+ type = NS_LITERAL_STRING("PluginDisabled");
+ break;
+ case ePluginBlocklisted:
+ type = NS_LITERAL_STRING("PluginBlocklisted");
+ break;
+ default:
+ return NS_OK;
+ }
+ nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
+ type, PR_TRUE, PR_TRUE);
return NS_OK;
}
class AutoNotifier {
public:
AutoNotifier(nsObjectLoadingContent* aContent, PRBool aNotify) :
mContent(aContent), mNotify(aNotify) {
@@ -227,38 +235,39 @@ class AutoNotifier {
/**
* A class that will automatically fall back if a |rv| variable has a failure
* code when this class is destroyed. It does not notify.
*/
class AutoFallback {
public:
AutoFallback(nsObjectLoadingContent* aContent, const nsresult* rv)
- : mContent(aContent), mResult(rv), mTypeUnsupported(PR_FALSE) {}
+ : mContent(aContent), mResult(rv), mPluginState(ePluginOtherState) {}
~AutoFallback() {
if (NS_FAILED(*mResult)) {
LOG(("OBJLC [%p]: rv=%08x, falling back\n", mContent, *mResult));
mContent->Fallback(PR_FALSE);
- if (mTypeUnsupported) {
- mContent->mTypeUnsupported = PR_TRUE;
+ if (mPluginState != ePluginOtherState) {
+ mContent->mPluginState = mPluginState;
}
}
}
/**
- * This function can be called to indicate that, after falling back,
- * mTypeUnsupported should be set to true.
+ * This should be set to something other than ePluginOtherState to indicate
+ * a specific failure that should be passed on.
*/
- void TypeUnsupported() {
- mTypeUnsupported = PR_TRUE;
- }
+ void SetPluginState(PluginSupportState aState) {
+ NS_ASSERTION(aState != ePluginOtherState, "Should not be setting ePluginOtherState");
+ mPluginState = aState;
+ }
private:
nsObjectLoadingContent* mContent;
const nsresult* mResult;
- PRBool mTypeUnsupported;
+ PluginSupportState mPluginState;
};
/**
* A class that automatically sets mInstantiating to false when it goes
* out of scope.
*/
class AutoSetInstantiatingToFalse {
public:
@@ -335,17 +344,17 @@ IsPluginEnabledByExtension(nsIURI* uri,
nsObjectLoadingContent::nsObjectLoadingContent()
: mPendingInstantiateEvent(nsnull)
, mChannel(nsnull)
, mType(eType_Loading)
, mInstantiating(PR_FALSE)
, mUserDisabled(PR_FALSE)
, mSuppressed(PR_FALSE)
- , mTypeUnsupported(PR_FALSE)
+ , mPluginState(ePluginOtherState)
{
}
nsObjectLoadingContent::~nsObjectLoadingContent()
{
DestroyImageLoadingContent();
if (mFrameLoader) {
mFrameLoader->Destroy();
@@ -568,30 +577,26 @@ nsObjectLoadingContent::OnStartRequest(n
}
break;
case eType_Loading:
NS_NOTREACHED("Should not have a loading type here!");
case eType_Null:
LOG(("OBJLC [%p]: Unsupported type, falling back\n", this));
// Need to fallback here (instead of using the case below), so that we can
- // set mTypeUnsupported without it being overwritten. This is also why we
+ // set mPluginState without it being overwritten. This is also why we
// return early.
Fallback(PR_FALSE);
PluginSupportState pluginState = GetPluginSupportState(thisContent,
mContentType);
// Do nothing, but fire the plugin not found event if needed
- if (pluginState == ePluginUnsupported ||
- pluginState == ePluginBlocklisted) {
- FirePluginError(thisContent, pluginState == ePluginBlocklisted);
- }
- if (pluginState != ePluginDisabled &&
- pluginState != ePluginBlocklisted) {
- mTypeUnsupported = PR_TRUE;
+ if (pluginState != ePluginOtherState) {
+ FirePluginError(thisContent, pluginState);
+ mPluginState = pluginState;
}
return NS_BINDING_ABORTED;
}
if (mFinalListener) {
mType = newType;
rv = mFinalListener->OnStartRequest(aRequest, aContext);
if (NS_FAILED(rv)) {
@@ -887,18 +892,26 @@ nsObjectLoadingContent::ObjectState() co
case eType_Null:
if (mSuppressed)
return NS_EVENT_STATE_SUPPRESSED;
if (mUserDisabled)
return NS_EVENT_STATE_USERDISABLED;
// Otherwise, broken
PRInt32 state = NS_EVENT_STATE_BROKEN;
- if (mTypeUnsupported) {
- state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
+ switch (mPluginState) {
+ case ePluginDisabled:
+ state |= NS_EVENT_STATE_HANDLER_DISABLED;
+ break;
+ case ePluginBlocklisted:
+ state |= NS_EVENT_STATE_HANDLER_BLOCKED;
+ break;
+ case ePluginUnsupported:
+ state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
+ break;
}
return state;
};
NS_NOTREACHED("unknown type?");
// this return statement only exists to avoid a compile warning
return 0;
}
@@ -956,26 +969,21 @@ IsAboutBlank(nsIURI* aURI)
return str.EqualsLiteral("about:blank");
}
void
nsObjectLoadingContent::UpdateFallbackState(nsIContent* aContent,
AutoFallback& fallback,
const nsCString& aTypeHint)
{
- PluginSupportState pluginState = GetPluginDisabledState(aTypeHint);
- if (pluginState == ePluginUnsupported) {
- // For unknown plugins notify the UI and allow the unknown plugin binding
- // to attach.
- FirePluginError(aContent, PR_FALSE);
- fallback.TypeUnsupported();
- }
- else if (pluginState == ePluginBlocklisted) {
- // For blocklisted plugins just send a notification to the UI.
- FirePluginError(aContent, PR_TRUE);
+ // Notify the UI and update the fallback state
+ PluginSupportState state = GetPluginSupportState(aContent, aTypeHint);
+ if (state != ePluginOtherState) {
+ fallback.SetPluginState(state);
+ FirePluginError(aContent, state);
}
}
nsresult
nsObjectLoadingContent::LoadObject(nsIURI* aURI,
PRBool aNotify,
const nsCString& aTypeHint,
PRBool aForceLoad)
@@ -1443,17 +1451,18 @@ nsObjectLoadingContent::UnloadContent()
{
// Don't notify in CancelImageRequests. We do it ourselves.
CancelImageRequests(PR_FALSE);
if (mFrameLoader) {
mFrameLoader->Destroy();
mFrameLoader = nsnull;
}
mType = eType_Null;
- mUserDisabled = mSuppressed = mTypeUnsupported = PR_FALSE;
+ mUserDisabled = mSuppressed = PR_FALSE;
+ mPluginState = ePluginOtherState;
}
void
nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
PRInt32 aOldState,
PRBool aSync)
{
LOG(("OBJLC [%p]: Notifying about state change: (%u, %x) -> (%u, %x) (sync=%i)\n",
@@ -1493,22 +1502,22 @@ nsObjectLoadingContent::NotifyStateChang
while ((shell = iter.GetNextShell())) {
shell->RecreateFramesFor(thisContent);
}
}
}
/* static */ void
nsObjectLoadingContent::FirePluginError(nsIContent* thisContent,
- PRBool blocklisted)
+ PluginSupportState state)
{
LOG(("OBJLC []: Dispatching nsPluginErrorEvent for content %p\n",
thisContent));
- nsCOMPtr<nsIRunnable> ev = new nsPluginErrorEvent(thisContent, blocklisted);
+ nsCOMPtr<nsIRunnable> ev = new nsPluginErrorEvent(thisContent, state);
nsresult rv = NS_DispatchToCurrentThread(ev);
if (NS_FAILED(rv)) {
NS_WARNING("failed to dispatch nsPluginErrorEvent");
}
}
nsObjectLoadingContent::ObjectType
nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
@@ -1761,17 +1770,17 @@ nsObjectLoadingContent::ShouldShowDefaul
{
if (nsContentUtils::GetBoolPref("plugin.default_plugin_disabled", PR_FALSE)) {
return PR_FALSE;
}
return GetPluginSupportState(aContent, aContentType) == ePluginUnsupported;
}
-/* static */ nsObjectLoadingContent::PluginSupportState
+/* static */ PluginSupportState
nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
const nsCString& aContentType)
{
if (!aContent->IsNodeOfType(nsINode::eHTML)) {
return ePluginOtherState;
}
if (aContent->Tag() == nsGkAtoms::embed ||
@@ -1798,17 +1807,17 @@ nsObjectLoadingContent::GetPluginSupport
nsStyleUtil::IsSignificantChild(child, PR_TRUE, PR_FALSE);
}
}
return hasAlternateContent ? ePluginOtherState :
GetPluginDisabledState(aContentType);
}
-/* static */ nsObjectLoadingContent::PluginSupportState
+/* static */ PluginSupportState
nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
{
nsCOMPtr<nsIPluginHost> host(do_GetService("@mozilla.org/plugin/host;1"));
if (!host) {
return ePluginUnsupported;
}
nsresult rv = host->IsPluginEnabledForType(aContentType.get());
if (rv == NS_ERROR_PLUGIN_DISABLED)
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -54,16 +54,25 @@
#include "nsIRunnable.h"
#include "nsIChannelClassifier.h"
class nsAsyncInstantiateEvent;
class AutoNotifier;
class AutoFallback;
class AutoSetInstantiatingToFalse;
+enum PluginSupportState {
+ ePluginUnsupported, // The plugin is not supported (not installed, say)
+ ePluginDisabled, // The plugin has been explicitly disabled by the
+ // user.
+ ePluginBlocklisted, // The plugin is blocklisted and disabled
+ ePluginOtherState // Something else (e.g. not a plugin at all as far
+ // as we can tell).
+};
+
/**
* INVARIANTS OF THIS CLASS
* - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
* to be valid until onStopRequest is called on mFinalListener, not
* necessarily until the channel calls onStopRequest on us)
* - mChannel corresponds to the channel that gets passed to the
* nsIRequestObserver/nsIStreamListener methods
* - mChannel can be cancelled and ODA calls will stop
@@ -247,17 +256,17 @@ class nsObjectLoadingContent : public ns
*/
void NotifyStateChanged(ObjectType aOldType, PRInt32 aOldState,
PRBool aSync);
/**
* Fires the "Plugin not found" event. This function doesn't do any checks
* whether it should be fired, the caller should do that.
*/
- static void FirePluginError(nsIContent* thisContent, PRBool blocklisted);
+ static void FirePluginError(nsIContent* thisContent, PluginSupportState state);
ObjectType GetTypeOfContent(const nsCString& aMIMEType);
/**
* For a classid, returns the MIME type that can be used to instantiate
* a plugin for this ID.
*
* @return NS_ERROR_NOT_AVAILABLE Unsupported class ID.
@@ -327,25 +336,16 @@ class nsObjectLoadingContent : public ns
/**
* Whether to treat this content as a plugin, even though we can't handle
* the type. This function impl should match the checks in the plugin host.
* aContentType is the MIME type we ended up with.
*/
static PRBool ShouldShowDefaultPlugin(nsIContent* aContent,
const nsCString& aContentType);
- enum PluginSupportState {
- ePluginUnsupported, // The plugin is not supported (not installed, say)
- ePluginDisabled, // The plugin has been explicitly disabled by the
- // user.
- ePluginBlocklisted, // The plugin is blocklisted and disabled
- ePluginOtherState // Something else (e.g. not a plugin at all as far
- // as we can tell).
- };
-
/**
* Get the plugin support state for the given content node and MIME type.
* This is used for purposes of determining whether to fire PluginNotFound
* events etc. aContentType is the MIME type we ended up with.
*
* This should only be called if the type of this content is eType_Null.
*/
static PluginSupportState
@@ -413,16 +413,16 @@ class nsObjectLoadingContent : public ns
/**
* Whether we are about to call instantiate on our frame. If we aren't,
* SetFrame needs to asynchronously call Instantiate.
*/
PRBool mInstantiating : 1;
// Blocking status from content policy
PRBool mUserDisabled : 1;
PRBool mSuppressed : 1;
- // Whether we fell back because of an unsupported type
- PRBool mTypeUnsupported:1;
+ // A specific state that caused us to fallback
+ PluginSupportState mPluginState;
friend class nsAsyncInstantiateEvent;
};
#endif
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -198,16 +198,19 @@ include $(topsrcdir)/config/rules.mk
test_bug444030.xhtml \
test_NodeIterator_basics_filters.xhtml \
test_NodeIterator_mutations_1.xhtml \
test_NodeIterator_mutations_2.html \
test_bug28293.html \
file_bug28293.sjs \
test_title.html \
test_bug453521.html \
+ test_bug391728.html \
+ file_bug391728.html \
+ file_bug391728_2.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
check::
@$(EXIT_ON_ERROR) \
for f in $(subst .cpp,,$(CPP_UNIT_TESTS)); do \
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug391728.html
@@ -0,0 +1,100 @@
+<html>
+<head>
+<style type="text/css">
+embed,object {
+ border: 1px solid black;
+}
+
+embed:-moz-handler-disabled,
+object:-moz-handler-disabled {
+ border-style: dotted !important;
+}
+
+embed:-moz-handler-blocked,
+object:-moz-handler-blocked {
+ border-style: dashed !important;
+}
+
+embed:-moz-type-unsupported,
+object:-moz-type-unsupported {
+ border-style: none !important;
+}
+</style>
+<script type="text/javascript">
+function unknown_plugin_detected(event) {
+ window.parent.unknown_plugin_detected(event);
+}
+
+function blocked_plugin_detected(event) {
+ window.parent.blocked_plugin_detected(event);
+}
+
+function disabled_plugin_detected(event) {
+ window.parent.disabled_plugin_detected(event);
+}
+
+document.addEventListener("PluginNotFound", unknown_plugin_detected, true);
+document.addEventListener("PluginDisabled", disabled_plugin_detected, true);
+document.addEventListener("PluginBlocklisted", blocked_plugin_detected, true);
+</script>
+</head>
+<body>
+<!-- Embeds always fire events and have the pseudo class attached -->
+<div><embed id="plugin1" style="width: 100px; height: 100px" type="application/x-test"></div>
+<div><embed id="plugin2" style="width: 100px; height: 100px" src="data:application/x-test,test"></div>
+
+<!-- So do objects with no content and no pluginurl -->
+<div><object id="plugin3" style="width: 100px; height: 100px" type="application/x-test"></object></div>
+<div><object id="plugin4" style="width: 100px; height: 100px" data="data:application/x-test,test"></object></div>
+
+<!-- The mimetype of the actual data is supposed to be used in preference -->
+<div><embed id="plugin5" style="width: 100px; height: 100px" type="application/x-unknown" src="data:application/x-test,test"></div>
+<div><object id="plugin6" style="width: 100px; height: 100px" type="application/x-unknown" data="data:application/x-test,test"></object></div>
+
+<!-- Params are not considered content -->
+<div><object id="plugin7" style="width: 100px; height: 100px" type="application/x-test">
+ <param name="foo" value="bar">
+</object></div>
+<div><object id="plugin8" style="width: 100px; height: 100px" data="data:application/x-test,test">
+ <param name="foo" value="bar">
+</object></div>
+
+<!-- Nor is whitespace -->
+<div><object id="plugin9" style="width: 100px; height: 100px" type="application/x-test">
+
+
+</object></div>
+<div><object id="plugin10" style="width: 100px; height: 100px" data="data:application/x-test,test">
+
+
+</object></div>
+
+<!-- Pluginurl forces the psuedo class and error event regardless of content -->
+<div><object id="plugin11" style="width: 100px; height: 100px" type="application/x-test">
+ <param name="pluginurl" value="http://foo">
+ <p>Fallback content</p>
+</object></div>
+<div><object id="plugin12" style="width: 100px; height: 100px" data="data:application/x-test,test">
+ <param name="pluginurl" value="http://foo">
+ <p>Fallback content</p>
+</object></div>
+
+<!-- No errors or psuedo classes for objects with fallback content -->
+<div><object id="fallback1" style="width: 100px; height: 100px" type="application/x-test">
+ <p>Fallback content</p>
+</object></div>
+<div><object id="fallback2" style="width: 100px; height: 100px" data="data:application/x-test,test">
+ <p>Fallback content</p>
+</object></div>
+
+<!-- Even other plugins are considered content so no errors dispatched from these
+ objects, but the inner embeds do get processed -->
+<div><object id="fallback3" style="width: 100px; height: 100px" type="application/x-test">
+ <embed id="plugin13" style="width: 100px; height: 100px" type="application/x-test">
+</object></div>
+<div><object id="fallback4" style="width: 100px; height: 100px" data="data:application/x-test,test">
+ <embed id="plugin14" style="width: 100px; height: 100px" type="application/x-test">
+</object></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug391728_2.html
@@ -0,0 +1,99 @@
+<html>
+<head>
+<style type="text/css">
+embed,object {
+ border: 1px solid black;
+}
+
+embed:-moz-handler-disabled,
+object:-moz-handler-disabled {
+ border-style: dotted !important;
+}
+
+embed:-moz-handler-blocked,
+object:-moz-handler-blocked {
+ border-style: dashed !important;
+}
+
+embed:-moz-type-unsupported,
+object:-moz-type-unsupported {
+ border-style: none !important;
+}
+</style>
+<script type="text/javascript">
+function unknown_plugin_detected(event) {
+ window.parent.unknown_plugin_detected(event);
+}
+
+function blocked_plugin_detected(event) {
+ window.parent.blocked_plugin_detected(event);
+}
+
+function disabled_plugin_detected(event) {
+ window.parent.disabled_plugin_detected(event);
+}
+
+document.addEventListener("PluginNotFound", unknown_plugin_detected, true);
+document.addEventListener("PluginDisabled", disabled_plugin_detected, true);
+document.addEventListener("PluginBlocklisted", blocked_plugin_detected, true);
+</script>
+</head>
+<body>
+<!-- Embeds always fire events and have the pseudo class attached -->
+<div><embed id="plugin1" style="width: 100px; height: 100px" type="application/x-unknown"></div>
+<div><embed id="plugin2" style="width: 100px; height: 100px" src="data:application/x-unknown,test"></div>
+
+<!-- So do objects with no content and no pluginurl -->
+<div><object id="plugin3" style="width: 100px; height: 100px" type="application/x-unknown"></object></div>
+<div><object id="plugin4" style="width: 100px; height: 100px" data="data:application/x-unknown,test"></object></div>
+
+<!-- The mimetype of the actual data is supposed to be used in preference -->
+<div><embed id="plugin5" style="width: 100px; height: 100px" type="application/x-test" src="data:application/x-unknown,test"></div>
+<div><object id="plugin6" style="width: 100px; height: 100px" type="application/x-test" data="data:application/x-unknown,test"></object></div>
+
+<!-- Params are not considered content -->
+<div><object id="plugin7" style="width: 100px; height: 100px" type="application/x-unknown">
+ <param name="foo" value="bar">
+</object></div>
+<div><object id="plugin8" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
+ <param name="foo" value="bar">
+</object></div>
+
+<!-- Nor is whitespace -->
+<div><object id="plugin9" style="width: 100px; height: 100px" type="application/x-unknown">
+
+
+</object></div>
+<div><object id="plugin10" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
+
+
+</object></div>
+
+<!-- Pluginurl forces the psuedo class and error event regardless of content -->
+<div><object id="plugin11" style="width: 100px; height: 100px" type="application/x-unknown">
+ <param name="pluginurl" value="http://foo">
+ <p>Fallback content</p>
+</object></div>
+<div><object id="plugin12" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
+ <param name="pluginurl" value="http://foo">
+ <p>Fallback content</p>
+</object></div>
+
+<!-- No errors or psuedo classes for objects with fallback content -->
+<div><object id="fallback1" style="width: 100px; height: 100px" type="application/x-unknown">
+ <p>Fallback content</p>
+</object></div>
+<div><object id="fallback2" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
+ <p>Fallback content</p>
+</object></div>
+
+<!-- Even other plugins are considered content so no errors dispatched from these
+ objects, but the inner embeds do get processed -->
+<div><object id="fallback3" style="width: 100px; height: 100px" type="application/x-unknown">
+ <embed id="plugin13" style="width: 100px; height: 100px" type="application/x-unknown">
+</object></div>
+<div><object id="fallback4" style="width: 100px; height: 100px" data="data:application/x-unknown,test">
+ <embed id="plugin14" style="width: 100px; height: 100px" type="application/x-unknown">
+</object></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug391728.html
@@ -0,0 +1,176 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=391728
+-->
+<head>
+ <title>Test for Bug 391728</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <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=391728">Mozilla Bug 391728</a>
+<p id="display"></p>
+<div id="content">
+ <iframe id="testframe" width="150" height="250" src="about:blank"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 391728 **/
+// Plugins that should dispatch error events and have the pseudo classes set
+const PLUGIN_COUNT = 14;
+// Plugins that should neither dispatch error events or have the pseudo classes set
+const FALLBACK_COUNT = 4;
+
+var gNextTest = null;
+var gUnknown = [];
+var gBlocked = [];
+var gDisabled = [];
+
+function get_test_plugin() {
+ var ph = Components.classes["@mozilla.org/plugin/host;1"]
+ .getService(Components.interfaces.nsIPluginHost);
+ var tags = ph.getPluginTags({});
+
+ // Find the test plugin
+ for (var i = 0; i < tags.length; i++) {
+ if (tags[i].name == "Test Plug-in")
+ return tags[i];
+ }
+}
+
+function disabled_plugin_detected(event) {
+ gDisabled.push(event.target.id);
+}
+
+function blocked_plugin_detected(event) {
+ gBlocked.push(event.target.id);
+}
+
+function unknown_plugin_detected(event) {
+ gUnknown.push(event.target.id);
+}
+
+function init_test() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ // Make sure the blocklist is off for the duration of this test
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+ prefs.setBoolPref("extensions.blocklist.enabled", false);
+
+ var plugin = get_test_plugin();
+ ok(plugin, "Test plugin was not found");
+
+ is(plugin.description, "Plug-in for testing purposes.", "Test plugin had an incorrect description");
+ is(plugin.version, "1.0.0.0", "Test plugin had an incorrect version");
+ ok(!plugin.disabled, "Test plugin should not be disabled");
+ ok(!plugin.blocklisted, "Test plugin should not be blocklisted");
+
+ var frame = document.getElementById("testframe");
+ frame.addEventListener("load", frame_loaded, true);
+ load_frame(test_normal, "file_bug391728");
+}
+
+function finish_test() {
+ var plugin = get_test_plugin();
+ plugin.disabled = false;
+ plugin.blocklisted = false;
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+ .getService(Components.interfaces.nsIPrefBranch);
+ prefs.clearUserPref("extensions.blocklist.enabled");
+ SimpleTest.finish();
+}
+
+function load_frame(nextTest, file) {
+ gNextTest = nextTest;
+ gDisabled = [];
+ gUnknown = [];
+ gBlocked = [];
+ var frame = document.getElementById("testframe");
+ frame.src = file + ".html?" + Math.random();
+}
+
+function frame_loaded() {
+ // We must delay to wait for the plugin sources to be loaded :(
+ setTimeout(gNextTest, 500);
+}
+
+function test_style(expected) {
+ var frame = document.getElementById("testframe");
+ for (var i = 1; i <= PLUGIN_COUNT; i++) {
+ var tag = frame.contentDocument.getElementById("plugin" + i);
+ ok(tag, "Plugin " + i + " did not exist");
+ var style = frame.contentWindow.getComputedStyle(tag, null);
+ is(style.borderTopStyle, expected, "Plugin " + i + " had an incorrect border style");
+ }
+ for (i = 1; i <= FALLBACK_COUNT; i++) {
+ var tag = frame.contentDocument.getElementById("fallback" + i);
+ ok(tag, "Fallback plugin " + i + " did not exist");
+ var style = frame.contentWindow.getComputedStyle(tag, null);
+ is(style.borderTopStyle, "solid", "Fallback plugin " + i + " had an incorrect border style");
+ }
+}
+
+function test_list(list) {
+ for (var i = 1; i <= PLUGIN_COUNT; i++) {
+ ok(list.indexOf("plugin" + i) >= 0, "Plugin " + i + " did not send the event");
+ }
+ for (i = 1; i <= FALLBACK_COUNT; i++) {
+ ok(list.indexOf("fallback" + i) < 0, "Fallback plugin " + i + " should not have sent the event");
+ }
+}
+
+function test_normal() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ is(gUnknown.length, 0, "Should not have been any unknown plugins");
+ is(gDisabled.length, 0, "Should not have been any disabled plugins");
+ is(gBlocked.length, 0, "Should not have been any blocked plugins");
+ test_style("solid");
+ var plugin = get_test_plugin();
+ plugin.disabled = true;
+ load_frame(test_disabled, "file_bug391728");
+}
+
+function test_disabled() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ is(gUnknown.length, 0, "Should not have been any unknown plugins");
+ is(gDisabled.length, PLUGIN_COUNT, "Should have been disabled plugins");
+ test_list(gDisabled);
+ is(gBlocked.length, 0, "Should not have been any blocked plugins");
+ test_style("dotted");
+ var plugin = get_test_plugin();
+ ok(plugin.disabled, "Plugin lost its disabled status");
+ plugin.disabled = false;
+ plugin.blocklisted = true;
+ load_frame(test_blocked, "file_bug391728");
+}
+
+function test_blocked() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ is(gUnknown.length, 0, "Should not have been any unknown plugins");
+ is(gDisabled.length, 0, "Should not have been any disabled plugins");
+ is(gBlocked.length, PLUGIN_COUNT, "Should have been blocked plugins");
+ test_list(gBlocked);
+ test_style("dashed");
+ var plugin = get_test_plugin();
+ ok(plugin.blocklisted, "Plugin lost its blocklist status");
+ load_frame(test_unknown, "file_bug391728_2");
+}
+
+function test_unknown() {
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ is(gUnknown.length, PLUGIN_COUNT, "Should have been unknown plugins");
+ test_list(gUnknown);
+ is(gDisabled.length, 0, "Should not have been any disabled plugins");
+ is(gBlocked.length, 0, "Should not have been any blocked plugins");
+ test_style("none");
+ finish_test();
+}
+
+SimpleTest.waitForExplicitFinish();
+window.addEventListener("load", init_test, false);
+</script>
+</pre>
+</body>
+</html>
--- a/content/base/test/test_bug425013.html
+++ b/content/base/test/test_bug425013.html
@@ -51,28 +51,22 @@ document.addEventListener("PluginNotFoun
<p>Alternate content</p>
</object>
<embed type="a/b" id="embed2"></embed>
<script class="testbody" type="text/javascript">
function runtests()
{
- is(missingPlugins[0], document.getElementById("obj1"),
- "Wrong missing plugin element 1");
- is(missingPlugins[1], document.getElementById("embed1"),
- "Wrong missing plugin element 2");
- is(missingPlugins[2], document.getElementById("obj2"),
- "Wrong missing plugin element 3");
- is(missingPlugins[3], document.getElementById("embed2"),
- "Wrong missing plugin element 4");
- is(missingPlugins[4], document.getElementById("obj3"),
- "Wrong missing plugin element 5");
+ ok(missingPlugins.indexOf(document.getElementById("obj1")) >= 0, "Missing plugin element obj1");
+ ok(missingPlugins.indexOf(document.getElementById("embed1")) >= 0, "Missing plugin element embed1");
+ ok(missingPlugins.indexOf(document.getElementById("embed2")) >= 0, "Missing plugin element embed2");
+ ok(missingPlugins.indexOf(document.getElementById("obj3")) >= 0, "Missing plugin element obj3");
- is(missingPlugins.length, 5, "Wrong number of missing plugins");
+ is(missingPlugins.length, 4, "Wrong number of missing plugins");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
--- a/content/events/public/nsIEventStateManager.h
+++ b/content/events/public/nsIEventStateManager.h
@@ -213,10 +213,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventSt
// user (eg an image which hasn't started coming in yet)
#define NS_EVENT_STATE_LOADING 0x00200000
// Content is of a type that gecko can't handle
#define NS_EVENT_STATE_TYPE_UNSUPPORTED \
0x00400000
#ifdef MOZ_MATHML
#define NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL 0x00800000
#endif
+// Handler for the content has been blocked
+#define NS_EVENT_STATE_HANDLER_BLOCKED \
+ 0x01000000
+// Handler for the content has been disabled
+#define NS_EVENT_STATE_HANDLER_DISABLED \
+ 0x02000000
#endif // nsIEventStateManager_h__
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -87,16 +87,18 @@ CSS_PSEUDO_CLASS(nthOfType, ":nth-of-typ
CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type")
// Image, object, etc state pseudo-classes
CSS_PSEUDO_CLASS(mozBroken, ":-moz-broken")
CSS_PSEUDO_CLASS(mozUserDisabled, ":-moz-user-disabled")
CSS_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed")
CSS_PSEUDO_CLASS(mozLoading, ":-moz-loading")
CSS_PSEUDO_CLASS(mozTypeUnsupported, ":-moz-type-unsupported")
+CSS_PSEUDO_CLASS(mozHandlerDisabled, ":-moz-handler-disabled")
+CSS_PSEUDO_CLASS(mozHandlerBlocked, ":-moz-handler-blocked")
CSS_PSEUDO_CLASS(mozHasHandlerRef, ":-moz-has-handlerref")
// Match nodes that are HTML but not XHTML
CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html")
// Matches anything when the specified look-and-feel metric is set
CSS_PSEUDO_CLASS(mozSystemMetric, ":-moz-system-metric")
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1507,16 +1507,22 @@ static PRBool SelectorMatches(RuleProces
stateToCheck = NS_EVENT_STATE_SUPPRESSED;
}
else if (nsCSSPseudoClasses::mozLoading == pseudoClass->mAtom) {
stateToCheck = NS_EVENT_STATE_LOADING;
}
else if (nsCSSPseudoClasses::mozTypeUnsupported == pseudoClass->mAtom) {
stateToCheck = NS_EVENT_STATE_TYPE_UNSUPPORTED;
}
+ else if (nsCSSPseudoClasses::mozHandlerDisabled == pseudoClass->mAtom) {
+ stateToCheck = NS_EVENT_STATE_HANDLER_DISABLED;
+ }
+ else if (nsCSSPseudoClasses::mozHandlerBlocked == pseudoClass->mAtom) {
+ stateToCheck = NS_EVENT_STATE_HANDLER_BLOCKED;
+ }
else if (nsCSSPseudoClasses::defaultPseudo == pseudoClass->mAtom) {
stateToCheck = NS_EVENT_STATE_DEFAULT;
}
else if (nsCSSPseudoClasses::required == pseudoClass->mAtom) {
stateToCheck = NS_EVENT_STATE_REQUIRED;
}
else if (nsCSSPseudoClasses::optional == pseudoClass->mAtom) {
stateToCheck = NS_EVENT_STATE_OPTIONAL;
--- a/modules/plugin/Makefile.in
+++ b/modules/plugin/Makefile.in
@@ -77,16 +77,17 @@ endif
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
TOOL_DIRS += default/mac
endif
ifdef ENABLE_TESTS
ifneq (,$(filter WINNT Darwin Linux,$(OS_ARCH)))
TOOL_DIRS += sdk
endif
+DIRS += test
endif
endif # MOZ_PLUGINS
include $(topsrcdir)/config/rules.mk
ifdef MOZ_PLUGINS
$(DIST)/bin/plugins:
--- a/modules/plugin/base/src/nsPluginsDirDarwin.cpp
+++ b/modules/plugin/base/src/nsPluginsDirDarwin.cpp
@@ -148,16 +148,27 @@ static PRBool IsLoadablePlugin(CFURLRef
close(f);
}
}
return isLoadable;
}
PRBool nsPluginsDir::IsPluginFile(nsIFile* file)
{
+ nsCString temp;
+ file->GetNativeLeafName(temp);
+ /*
+ * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X
+ * 10.5.3 (see bug 436575).
+ */
+ if (!strcmp(temp.get(), "VerifiedDownloadPlugin.plugin")) {
+ NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)");
+ return PR_FALSE;
+ }
+
CFURLRef pluginURL = NULL;
if (NS_FAILED(toCFURLRef(file, pluginURL)))
return PR_FALSE;
PRBool isPluginFile = PR_FALSE;
CFBundleRef pluginBundle = CFBundleCreate(kCFAllocatorDefault, pluginURL);
if (pluginBundle) {
@@ -281,26 +292,16 @@ nsPluginFile::~nsPluginFile() {}
nsresult nsPluginFile::LoadPlugin(PRLibrary* &outLibrary)
{
const char* path;
if (!mPlugin)
return NS_ERROR_NULL_POINTER;
nsCAutoString temp;
- mPlugin->GetNativeLeafName(temp);
- /*
- * Don't load the VDP fake plugin, to avoid tripping a bad bug in OS X
- * 10.5.3 (see bug 436575).
- */
- if (!strcmp(temp.get(), "VerifiedDownloadPlugin.plugin")) {
- NS_WARNING("Preventing load of VerifiedDownloadPlugin.plugin (see bug 436575)");
- return NS_ERROR_FAILURE;
- }
-
mPlugin->GetNativePath(temp);
path = temp.get();
outLibrary = PR_LoadLibrary(path);
pLibrary = outLibrary;
if (!outLibrary) {
return NS_ERROR_FAILURE;
}
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/Makefile.in
@@ -0,0 +1,49 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is mozilla.org
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Dave Townsend <dtownsend@oxymoronical.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = plugin
+
+DIRS = testplugin
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/testplugin/Info.plist
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>libnptest.dylib</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.mozilla.TestPlugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BRPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0.0.0</string>
+ <key>CFBundleSignature</key>
+ <string>TEST</string>
+ <key>CFBundleVersion</key>
+ <string>1.0.0.0</string>
+ <key>WebPluginName</key>
+ <string>Test Plug-in</string>
+ <key>WebPluginDescription</key>
+ <string>Plug-in for testing purposes.</string>
+ <key>WebPluginMIMETypes</key>
+ <dict>
+ <key>application/x-test</key>
+ <dict>
+ <key>WebPluginExtensions</key>
+ <array>
+ <string>tst</string>
+ </array>
+ <key>WebPluginTypeDescription</key>
+ <string>Test mimetype</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/testplugin/Makefile.in
@@ -0,0 +1,76 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is mozilla.org
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Dave Townsend <dtownsend@oxymoronical.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE = nptest
+LIBRARY_NAME = nptest
+MODULE_NAME = TestPlugin
+
+REQUIRES = \
+ plugin \
+ $(NULL)
+
+# Need to custom install plugins
+NO_DIST_INSTALL = 1
+NO_INSTALL = 1
+
+ifeq ($(OS_ARCH),WINNT)
+RCFILE = nptest.rc
+RESFILE = nptest.res
+endif
+
+CPPSRCS = nptest.cpp
+
+include $(topsrcdir)/config/rules.mk
+
+install-plugin: $(SHARED_LIBRARY)
+ifdef SHARED_LIBRARY
+ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
+ $(INSTALL) $(srcdir)/Info.plist $(DIST)/bin/plugins/Test.plugin/Contents
+ $(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins/Test.plugin/Contents/MacOS
+else
+ $(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins
+endif
+endif
+
+libs:: install-plugin
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/testplugin/nptest.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is mozilla.org
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Townsend <dtownsend@oxymoronical.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "npapi.h"
+#include "npupp.h"
+
+#if defined(XP_UNIX)
+
+#define PLUGIN_NAME "Test Plug-in"
+#define PLUGIN_DESCRIPTION "Plug-in for testing purposes."
+#define PLUGIN_VERSION "1.0.0.0"
+
+NP_EXPORT(char*)
+NP_GetPluginVersion(void) {
+ return PLUGIN_VERSION;
+}
+
+NP_EXPORT(char*)
+NP_GetMIMEDescription(void) {
+ return "application/x-test:tst:Test mimetype";
+}
+
+NP_EXPORT(NPError)
+NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*) {
+ return NPERR_NO_ERROR;
+}
+
+NP_EXPORT(NPError)
+NP_Shutdown(void) {
+ return NPERR_NO_ERROR;
+}
+
+NP_EXPORT(NPError)
+NP_GetValue(void *future, NPPVariable aVariable, void *aValue) {
+ switch (aVariable) {
+ case NPPVpluginNameString:
+ *((char **)aValue) = PLUGIN_NAME;
+ break;
+ case NPPVpluginDescriptionString:
+ *((char **)aValue) = PLUGIN_DESCRIPTION;
+ break;
+ default:
+ return NPERR_INVALID_PARAM;
+ break;
+ }
+ return NPERR_NO_ERROR;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/testplugin/nptest.rc
@@ -0,0 +1,42 @@
+#include<winver.h>
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "CompanyName", "mozilla.org"
+ VALUE "FileDescription", "Plug-in for testing purposes."
+ VALUE "FileExtents", "tst"
+ VALUE "FileOpenName", "Test mimetype"
+ VALUE "FileVersion", "1.0"
+ VALUE "InternalName", "nptest"
+ VALUE "MIMEType", "application/x-test"
+ VALUE "OriginalFilename", "nptest.dll"
+ VALUE "ProductName", "Test Plug-in"
+ VALUE "ProductVersion", "1.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END