Bug 558184 - Part 4.3 - Load fake plugin handlers as eType_FakePlugin in nsObjectLoadingContent. r=peterv.
authorJohn Schoenick <jschoenick@mozilla.com>
Wed, 20 May 2015 15:30:05 +0200
changeset 361797 675c893a028dfe609ee6812cba0d1e86b2853d23
parent 361796 980375a7b0292f0b7fcdc4bb47d117fe0f51e158
child 361798 0aa594d8fb39d096c685a04ca69e1b68e081952d
push id31943
push userryanvm@gmail.com
push dateThu, 01 Jun 2017 15:54:45 +0000
treeherdermozilla-central@62005e6aecdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs558184
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 558184 - Part 4.3 - Load fake plugin handlers as eType_FakePlugin in nsObjectLoadingContent. r=peterv.
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsIObjectLoadingContent.idl
dom/base/nsObjectLoadingContent.cpp
dom/base/nsObjectLoadingContent.h
dom/html/HTMLObjectElement.cpp
dom/webidl/HTMLObjectElement.webidl
layout/base/nsCSSFrameConstructor.cpp
netwerk/base/nsNetUtil.cpp
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10346,18 +10346,36 @@ HtmlObjectContentSupportsDocument(const 
     do_GetService("@mozilla.org/streamConverters;1");
   bool canConvert = false;
   if (convServ) {
     rv = convServ->CanConvert(aMimeType.get(), "*/*", &canConvert);
   }
   return NS_SUCCEEDED(rv) && canConvert;
 }
 
+/* static */
+already_AddRefed<nsIPluginTag>
+nsContentUtils::PluginTagForType(const nsCString& aMIMEType, bool aNoFakePlugin)
+{
+  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
+  nsCOMPtr<nsIPluginTag> tag;
+  NS_ENSURE_TRUE(pluginHost, nullptr);
+
+  // ShouldPlay will handle the case where the plugin is disabled
+  pluginHost->GetPluginTagForType(aMIMEType,
+                                  aNoFakePlugin ? nsPluginHost::eExcludeFake
+                                                : nsPluginHost::eExcludeNone,
+                                  getter_AddRefs(tag));
+
+  return tag.forget();
+}
+
 /* static */ uint32_t
 nsContentUtils::HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType,
+                                                 bool aNoFakePlugin,
                                                  nsIContent* aContent)
 {
   if (aMIMEType.IsEmpty()) {
     return nsIObjectLoadingContent::TYPE_NULL;
   }
 
   if (imgLoader::SupportImageWithMimeType(aMIMEType.get())) {
     return nsIObjectLoadingContent::TYPE_IMAGE;
@@ -10370,20 +10388,27 @@ nsContentUtils::HtmlObjectContentTypeFor
     return nsIObjectLoadingContent::TYPE_DOCUMENT;
   }
 
   if (HtmlObjectContentSupportsDocument(aMIMEType, aContent)) {
     return nsIObjectLoadingContent::TYPE_DOCUMENT;
   }
 
   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
-  if (pluginHost &&
-      pluginHost->HavePluginForType(aMIMEType, nsPluginHost::eExcludeNone)) {
-    // ShouldPlay will handle checking for disabled plugins
-    return nsIObjectLoadingContent::TYPE_PLUGIN;
+  if (pluginHost) {
+    nsCOMPtr<nsIPluginTag> tag = PluginTagForType(aMIMEType, aNoFakePlugin);
+    if (tag) {
+      if (!aNoFakePlugin &&
+          nsCOMPtr<nsIFakePluginTag>(do_QueryInterface(tag))) {
+        return nsIObjectLoadingContent::TYPE_FAKE_PLUGIN;
+      }
+
+      // ShouldPlay will handle checking for disabled plugins
+      return nsIObjectLoadingContent::TYPE_PLUGIN;
+    }
   }
 
   return nsIObjectLoadingContent::TYPE_NULL;
 }
 
 /* static */ already_AddRefed<nsIEventTarget>
 nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aCategory)
 {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -78,16 +78,17 @@ class nsIIOService;
 class nsILineBreaker;
 class nsILoadInfo;
 class nsILoadGroup;
 class nsIMessageBroadcaster;
 class nsNameSpaceManager;
 class nsIObserver;
 class nsIParser;
 class nsIParserService;
+class nsIPluginTag;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIRequest;
 class nsIRunnable;
 class nsIScriptContext;
 class nsIScriptSecurityManager;
 class nsIStringBundle;
 class nsIStringBundleService;
@@ -2900,30 +2901,42 @@ public:
 
   /**
    * Walks up the tree from aElement until it finds an element that is
    * not native anonymous content.  aElement must be NAC itself.
    */
   static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
 
   /**
+   * Returns the nsIPluginTag for the plugin we should try to use for a given
+   * MIME type.
+   *
+   * @param aMIMEType  The MIME type of the document being loaded.
+   * @param aNoFakePlugin  If false then this method should consider JS plugins.
+   */
+  static already_AddRefed<nsIPluginTag>
+    PluginTagForType(const nsCString& aMIMEType, bool aNoFakePlugin);
+
+  /**
    * Returns one of the nsIObjectLoadingContent::TYPE_ values describing the
    * content type which will be used for the given MIME type when loaded within
    * an nsObjectLoadingContent.
    *
    * NOTE: This method doesn't take capabilities into account. The caller must
    * take that into account.
    *
    * @param aMIMEType  The MIME type of the document being loaded.
+   * @param aNoFakePlugin  If false then this method should consider JS plugins.
    * @param aContent The nsIContent object which is performing the load. May be
    *                 nullptr in which case the docshell's plugin permissions
    *                 will not be checked.
    */
   static uint32_t
   HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType,
+                                   bool aNoFakePlugin,
                                    nsIContent* aContent);
 
   static already_AddRefed<nsIEventTarget>
   GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, mozilla::TaskCategory aCategory);
 
   /**
    * Detect whether a string is a local-url.
    * https://drafts.csswg.org/css-values/#local-urls
--- a/dom/base/nsIObjectLoadingContent.idl
+++ b/dom/base/nsIObjectLoadingContent.idl
@@ -26,21 +26,22 @@ class nsNPAPIPluginInstance;
  */
 
 [scriptable, uuid(2eb3195e-3eea-4083-bb1d-d2d70fa35ccb)]
 interface nsIObjectLoadingContent : nsISupports
 {
   /**
    * See notes in nsObjectLoadingContent.h
    */
-  const unsigned long TYPE_LOADING  = 0;
-  const unsigned long TYPE_IMAGE    = 1;
-  const unsigned long TYPE_PLUGIN   = 2;
-  const unsigned long TYPE_DOCUMENT = 3;
-  const unsigned long TYPE_NULL     = 4;
+  const unsigned long TYPE_LOADING     = 0;
+  const unsigned long TYPE_IMAGE       = 1;
+  const unsigned long TYPE_PLUGIN      = 2;
+  const unsigned long TYPE_FAKE_PLUGIN = 3;
+  const unsigned long TYPE_DOCUMENT    = 4;
+  const unsigned long TYPE_NULL        = 5;
 
   const unsigned long PLUGIN_ACTIVE               = 0xFF;
 
   // The content type is not supported (e.g. plugin not installed)
   const unsigned long PLUGIN_UNSUPPORTED          = 0;
   // Showing alternate content
   const unsigned long PLUGIN_ALTERNATE            = 1;
   // The plugin exists, but is disabled
@@ -158,9 +159,14 @@ interface nsIObjectLoadingContent : nsIS
    */
   [noscript] void initializeFromChannel(in nsIRequest request);
 
   /**
    * The URL of the data/src loaded in the object. This may be null (i.e.
    * an <embed> with no src).
    */
   readonly attribute nsIURI srcURI;
+
+  /**
+   * Disable the use of fake plugins and reload the tag if necessary.
+   */
+  void skipFakePlugins();
 };
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -11,16 +11,17 @@
 
 // Interface headers
 #include "imgLoader.h"
 #include "nsIClassOfService.h"
 #include "nsIConsoleService.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIDocShell.h"
+#include "nsIDocShellLoadInfo.h"
 #include "nsIDocument.h"
 #include "nsIDOMCustomEvent.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIObjectFrame.h"
@@ -141,16 +142,23 @@ InActiveDocument(nsIContent *aContent)
 {
   if (!aContent->IsInComposedDoc()) {
     return false;
   }
   nsIDocument *doc = aContent->OwnerDoc();
   return (doc && doc->IsActive());
 }
 
+static bool
+IsPluginType(nsObjectLoadingContent::ObjectType type)
+{
+  return type == nsObjectLoadingContent::eType_Plugin ||
+         type == nsObjectLoadingContent::eType_FakePlugin;
+}
+
 ///
 /// Runnables and helper classes
 ///
 
 class nsAsyncInstantiateEvent : public Runnable {
 public:
   explicit nsAsyncInstantiateEvent(nsObjectLoadingContent* aContent)
     : Runnable("nsAsyncInstantiateEvent"), mContent(aContent) {}
@@ -543,16 +551,54 @@ nsObjectLoadingContent::MakePluginListen
   NS_ENSURE_SUCCESS(rv, false);
   rv = pluginHost->NewPluginStreamListener(mURI, inst,
                                            getter_AddRefs(finalListener));
   NS_ENSURE_SUCCESS(rv, false);
   mFinalListener = finalListener;
   return true;
 }
 
+// Helper to spawn the frameloader and return a pointer to its docshell
+already_AddRefed<nsIDocShell>
+nsObjectLoadingContent::SetupFrameLoader(nsIURI *aRecursionCheckURI)
+{
+  nsCOMPtr<nsIContent> thisContent =
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+  NS_ASSERTION(thisContent, "must be a content");
+
+  mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
+                                       /* aOpener = */ nullptr,
+                                       mNetworkCreated);
+  if (!mFrameLoader) {
+    NS_NOTREACHED("nsFrameLoader::Create failed");
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDocShell> docShell;
+
+  if (aRecursionCheckURI) {
+    nsresult rv = mFrameLoader->CheckForRecursiveLoad(aRecursionCheckURI);
+    if (NS_SUCCEEDED(rv)) {
+      rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
+      if (NS_FAILED(rv)) {
+        NS_NOTREACHED("Could not get DocShell from mFrameLoader?");
+      }
+    } else {
+      LOG(("OBJLC [%p]: Aborting recursive load", this));
+    }
+  }
+
+  if (!docShell) {
+    mFrameLoader->Destroy();
+    mFrameLoader = nullptr;
+    return nullptr;
+  }
+
+  return docShell.forget();
+}
 
 nsresult
 nsObjectLoadingContent::BindToTree(nsIDocument* aDocument,
                                    nsIContent* aParent,
                                    nsIContent* aBindingParent,
                                    bool aCompileEventHandlers)
 {
   nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
@@ -570,16 +616,18 @@ nsObjectLoadingContent::UnbindFromTree(b
   nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
 
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
   MOZ_ASSERT(thisContent);
   nsIDocument* ownerDoc = thisContent->OwnerDoc();
   ownerDoc->RemovePlugin(this);
 
+  /// XXX(johns): Do we want to somehow propogate the reparenting behavior to
+  ///             FakePlugin types as well?
   if (mType == eType_Plugin && (mInstanceOwner || mInstantiating)) {
     // we'll let the plugin continue to run at least until we get back to
     // the event loop. If we get back to the event loop and the node
     // has still not been added back to the document then we tear down the
     // plugin
     QueueCheckPluginStopEvent();
   } else if (mType != eType_Image) {
     // nsImageLoadingContent handles the image case.
@@ -603,16 +651,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   , mFallbackType(eFallbackAlternate)
   , mRunID(0)
   , mHasRunID(false)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
   , mContentBlockingEnabled(false)
+  , mSkipFakePlugins(false)
   , mIsStopping(false)
   , mIsLoading(false)
   , mScriptRequested(false)
   , mRewrittenYoutubeEmbed(false)
   , mPreferFallback(false)
   , mPreferFallbackKnown(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
@@ -1194,17 +1243,17 @@ nsObjectLoadingContent::GetPluginInstanc
 
   return mInstanceOwner->GetInstance(aInstance);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
                                                   uint32_t* aType)
 {
-  *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
+  *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType), false);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetBaseURI(nsIURI **aResult)
 {
   NS_IF_ADDREF(*aResult = mBaseURI);
   return NS_OK;
@@ -1289,16 +1338,17 @@ EventStates
 nsObjectLoadingContent::ObjectState() const
 {
   switch (mType) {
     case eType_Loading:
       return NS_EVENT_STATE_LOADING;
     case eType_Image:
       return ImageState();
     case eType_Plugin:
+    case eType_FakePlugin:
     case eType_Document:
       // These are OK. If documents start to load successfully, they display
       // something, and are thus not broken in this sense. The same goes for
       // plugins.
       return EventStates();
     case eType_Null:
       switch (mFallbackType) {
         case eFallbackSuppressed:
@@ -1532,16 +1582,19 @@ nsObjectLoadingContent::CheckProcessPoli
   int32_t objectType;
   switch (mType) {
     case eType_Image:
       objectType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
       break;
     case eType_Document:
       objectType = nsIContentPolicy::TYPE_DOCUMENT;
       break;
+    // FIXME Fake plugins look just like real plugins to CSP, should they use
+    // the fake plugin's handler URI and look like documents instead?
+    case eType_FakePlugin:
     case eType_Plugin:
       objectType = GetContentPolicyType();
       break;
     default:
       NS_NOTREACHED("Calling checkProcessPolicy with a unloadable type");
       return false;
   }
 
@@ -1745,17 +1798,17 @@ nsObjectLoadingContent::UpdateObjectPara
       NS_TryToSetImmutable(newURI);
     } else {
       stateInvalid = true;
     }
   }
 
   // For eAllowPluginSkipChannel tags, if we have a non-plugin type, but can get
   // a plugin type from the extension, prefer that to falling back to a channel.
-  if (GetTypeOfContent(newMime) != eType_Plugin && newURI &&
+  if (!IsPluginType(GetTypeOfContent(newMime, mSkipFakePlugins)) && newURI &&
       (caps & eAllowPluginSkipChannel) &&
       IsPluginEnabledByExtension(newURI, newMime)) {
     LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
     if (!isJava && IsJavaMIME(newMime)) {
       return UpdateObjectParameters(true);
     }
   }
 
@@ -1811,18 +1864,18 @@ nsObjectLoadingContent::UpdateObjectPara
 
     // Channel can change our URI through redirection
     rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(newURI));
     if (NS_FAILED(rv)) {
       NS_NOTREACHED("NS_GetFinalChannelURI failure");
       stateInvalid = true;
     }
 
-    ObjectType typeHint = newMime.IsEmpty() ?
-                          eType_Null : GetTypeOfContent(newMime);
+    ObjectType typeHint = newMime.IsEmpty() ? eType_Null
+                          : GetTypeOfContent(newMime, mSkipFakePlugins);
 
     //
     // In order of preference:
     //
     // 1) Perform typemustmatch check.
     //    If check is sucessful use type without further checks.
     //    If check is unsuccessful set stateInvalid to true
     // 2) Use our type hint if it matches a plugin
@@ -1833,17 +1886,17 @@ nsObjectLoadingContent::UpdateObjectPara
     //    4b) If the uri file extension matches a plugin type, use that
     // 5) Use the channel type
 
     bool overrideChannelType = false;
     if (thisContent->HasAttr(kNameSpaceID_None, nsGkAtoms::typemustmatch)) {
       if (!typeAttr.LowerCaseEqualsASCII(channelType.get())) {
         stateInvalid = true;
       }
-    } else if (typeHint == eType_Plugin) {
+    } else if (IsPluginType(typeHint)) {
       LOG(("OBJLC [%p]: Using plugin type hint in favor of any channel type",
            this));
       overrideChannelType = true;
     } else if ((caps & eAllowPluginSkipChannel) &&
                IsPluginEnabledByExtension(newURI, newMime)) {
       LOG(("OBJLC [%p]: Using extension as type hint for "
            "eAllowPluginSkipChannel tag (%s)", this, newMime.get()));
       overrideChannelType = true;
@@ -1895,26 +1948,28 @@ nsObjectLoadingContent::UpdateObjectPara
   //     type.
   //  3) If we have a plugin type and no URI, use that type.
   //  4) If we have a plugin type and eAllowPluginSkipChannel, use that type.
   //  5) if we have a URI, set type to loading to indicate we'd need a channel
   //     to proceed.
   //  6) Otherwise, type null to indicate unloadable content (fallback)
   //
 
+  ObjectType newMime_Type = GetTypeOfContent(newMime, mSkipFakePlugins);
+
   if (stateInvalid) {
     newType = eType_Null;
     newMime.Truncate();
   } else if (newChannel) {
     // If newChannel is set above, we considered it in setting newMime
-    newType = GetTypeOfContent(newMime);
+    newType = newMime_Type;
     LOG(("OBJLC [%p]: Using channel type", this));
   } else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
-             GetTypeOfContent(newMime) == eType_Plugin) {
-    newType = eType_Plugin;
+             IsPluginType(newMime_Type)) {
+    newType = newMime_Type;
     LOG(("OBJLC [%p]: Plugin type with no URI, skipping channel load", this));
   } else if (newURI) {
     // We could potentially load this if we opened a channel on mURI, indicate
     // This by leaving type as loading
     newType = eType_Loading;
   } else {
     // Unloadable - no URI, and no plugin type. Non-plugin types (images,
     // documents) always load with a channel.
@@ -2076,33 +2131,36 @@ nsObjectLoadingContent::LoadObject(bool 
   LOG(("OBJLC [%p]: LoadObject - plugin state changed (%u)",
        this, stateChange));
 
   // Setup fallback info. We may also change type to fallback below in case of
   // sanity/OOM/etc. errors. We default to showing alternate content
   // NOTE LoadFallback can override this in some cases
   FallbackType fallbackType = eFallbackAlternate;
 
-  // mType can differ with GetTypeOfContent(mContentType) if we support this
-  // type, but the parameters are invalid e.g. a embed tag with type "image/png"
-  // but no URI -- don't show a plugin error or unknown type error in that case.
-  if (mType == eType_Null && GetTypeOfContent(mContentType) == eType_Null) {
+  // If GetTypeOfContent(mContentType) is null we truly have no handler for the
+  // type -- otherwise, we have a handler but UpdateObjectParameters rejected
+  // the configuration for another reason (e.g. an embed tag with type
+  // "image/png" but no URI). Don't show a plugin error or unknown type error in
+  // the latter case.
+  if (mType == eType_Null &&
+      GetTypeOfContent(mContentType, mSkipFakePlugins) == eType_Null) {
     fallbackType = eFallbackUnsupported;
   }
 
   // Explicit user activation should reset if the object changes content types
   if (mActivated && (stateChange & eParamContentTypeChanged)) {
     LOG(("OBJLC [%p]: Content type changed, clearing activation state", this));
     mActivated = false;
   }
 
   // We synchronously start/stop plugin instances below, which may spin the
   // event loop. Re-entering into the load is fine, but at that point the
   // original load call needs to abort when unwinding
-  // NOTE this is located *after* the state change check, a subseqent load
+  // NOTE this is located *after* the state change check, a subsequent load
   //      with no subsequently changed state will be a no-op.
   if (mIsLoading) {
     LOG(("OBJLC [%p]: Re-entering into LoadObject", this));
   }
   mIsLoading = true;
   AutoSetLoadingToFalse reentryCheck(this);
 
   // Unload existing content, keeping in mind stopping plugins might spin the
@@ -2207,34 +2265,33 @@ nsObjectLoadingContent::LoadObject(bool 
 
       nestedURI->GetInnerURI(getter_AddRefs(tempURI));
       nestedURI = do_QueryInterface(tempURI);
     }
   }
 
   // Items resolved as Image/Document are no candidates for content blocking,
   // as well as invalid plugins (they will not have the mContentType set).
-  if ((mType == eType_Null || mType == eType_Plugin) && ShouldBlockContent()) {
+  if ((mType == eType_Null || IsPluginType(mType)) && ShouldBlockContent()) {
     LOG(("OBJLC [%p]: Enable content blocking", this));
     mType = eType_Loading;
   }
 
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead. Items resolved as Image/Document
   // will not be checked for previews, as well as invalid plugins
   // (they will not have the mContentType set).
   FallbackType clickToPlayReason;
-  if (!mActivated && (mType == eType_Null || mType == eType_Plugin) &&
-      !ShouldPlay(clickToPlayReason, false)) {
+  if (!mActivated && IsPluginType(mType) && !ShouldPlay(clickToPlayReason)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
     mType = eType_Null;
     fallbackType = clickToPlayReason;
   }
 
-  if (!mActivated && mType == eType_Plugin) {
+  if (!mActivated && IsPluginType(mType)) {
     // Object passed ShouldPlay, so it should be considered
     // activated until it changes content type
     LOG(("OBJLC [%p]: Object implicitly activated", this));
     mActivated = true;
   }
 
   // Sanity check: We shouldn't have any loaded resources, pending events, or
   // a final listener at this point
@@ -2301,69 +2358,113 @@ nsObjectLoadingContent::LoadObject(bool 
 
         // We'll handle this below
         doSpawnPlugin = true;
       } else {
         rv = AsyncStartPluginInstance();
       }
     }
     break;
+    case eType_FakePlugin:
+    {
+      if (mChannel) {
+        /// XXX(johns): Ideally we'd have some way to pass the channel to the
+        ///             fake plugin handler, but for now handlers will need to
+        ///             request element.srcURI themselves if they want it
+        LOG(("OBJLC [%p]: Closing unused channel for fake plugin type", this));
+        CloseChannel();
+      }
+
+      /// XXX(johns) Bug FIXME - We need to cleanup the various plugintag
+      ///            classes to be more sane and avoid this dance
+      nsCOMPtr<nsIPluginTag> basetag =
+        nsContentUtils::PluginTagForType(mContentType, false);
+      nsCOMPtr<nsIFakePluginTag> tag = do_QueryInterface(basetag);
+      nsCOMPtr<nsIURI> handlerURI;
+      if (tag) {
+        tag->GetHandlerURI(getter_AddRefs(handlerURI));
+      }
+
+      if (!handlerURI) {
+        NS_NOTREACHED("Selected type is not a proper fake plugin handler");
+        rv = NS_ERROR_FAILURE;
+        break;
+      }
+
+      nsCOMPtr<nsIDocShell> docShell = SetupFrameLoader(handlerURI);
+      if (!docShell) {
+        rv = NS_ERROR_FAILURE;
+        break;
+      }
+
+      nsCString spec;
+      handlerURI->GetSpec(spec);
+      LOG(("OBJLC [%p]: Loading fake plugin handler (%s)", this, spec.get()));
+
+      // XXX(johns): This and moreso the document case below are
+      //             sidestepping/duplicating nsFrameLoader's LoadURI code,
+      //             which is not great.
+
+      nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
+      docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
+      if (loadInfo) {
+        loadInfo->SetTriggeringPrincipal(thisContent->NodePrincipal());
+        nsCOMPtr<nsIURI> referrer;
+        thisContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
+        loadInfo->SetReferrer(referrer);
+
+        rv = docShell->LoadURI(handlerURI, loadInfo,
+                               nsIWebNavigation::LOAD_FLAGS_NONE, false);
+      } else {
+        NS_NOTREACHED("CreateLoadInfo failed");
+        rv = NS_ERROR_FAILURE;
+      }
+
+      if (NS_FAILED(rv)) {
+        LOG(("OBJLC [%p]: LoadURI() failed for fake handler", this));
+        mFrameLoader->Destroy();
+        mFrameLoader = nullptr;
+      }
+    }
+    break;
     case eType_Document:
     {
       if (!mChannel) {
         // We could mFrameLoader->LoadURI(mURI), but UpdateObjectParameters
         // requires documents have a channel, so this is not a valid state.
         NS_NOTREACHED("Attempting to load a document without a channel");
-        mType = eType_Null;
+        rv = NS_ERROR_FAILURE;
         break;
       }
 
-      mFrameLoader = nsFrameLoader::Create(thisContent->AsElement(),
-                                           /* aOpener = */ nullptr,
-                                           mNetworkCreated);
-      if (!mFrameLoader) {
-        NS_NOTREACHED("nsFrameLoader::Create failed");
-        mType = eType_Null;
-        break;
-      }
-
-      rv = mFrameLoader->CheckForRecursiveLoad(mURI);
-      if (NS_FAILED(rv)) {
-        LOG(("OBJLC [%p]: Aborting recursive load", this));
-        mFrameLoader->Destroy();
-        mFrameLoader = nullptr;
-        mType = eType_Null;
+      nsCOMPtr<nsIDocShell> docShell = SetupFrameLoader(mURI);
+      if (!docShell) {
+        rv = NS_ERROR_FAILURE;
         break;
       }
 
       // We're loading a document, so we have to set LOAD_DOCUMENT_URI
       // (especially important for firing onload)
       nsLoadFlags flags = 0;
       mChannel->GetLoadFlags(&flags);
       flags |= nsIChannel::LOAD_DOCUMENT_URI;
       mChannel->SetLoadFlags(flags);
 
-      nsCOMPtr<nsIDocShell> docShell;
-      rv = mFrameLoader->GetDocShell(getter_AddRefs(docShell));
-      if (NS_FAILED(rv)) {
-        NS_NOTREACHED("Could not get DocShell from mFrameLoader?");
-        mType = eType_Null;
-        break;
-      }
-
       nsCOMPtr<nsIInterfaceRequestor> req(do_QueryInterface(docShell));
       NS_ASSERTION(req, "Docshell must be an ifreq");
 
       nsCOMPtr<nsIURILoader>
         uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID, &rv));
       if (NS_FAILED(rv)) {
         NS_NOTREACHED("Failed to get uriLoader service");
-        mType = eType_Null;
+        mFrameLoader->Destroy();
+        mFrameLoader = nullptr;
         break;
       }
+
       rv = uriLoader->OpenChannel(mChannel, nsIURILoader::DONT_RETARGET, req,
                                   getter_AddRefs(finalListener));
       // finalListener will receive OnStartRequest below
     }
     break;
     case eType_Loading:
       // If our type remains Loading, we need a channel to proceed
       rv = OpenChannel();
@@ -2707,34 +2808,37 @@ nsObjectLoadingContent::NotifyStateChang
   if (aSync) {
     NS_ASSERTION(InActiveDocument(thisContent), "Something is confused");
     // Make sure that frames are actually constructed immediately.
     doc->FlushPendingNotifications(FlushType::Frames);
   }
 }
 
 nsObjectLoadingContent::ObjectType
-nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType)
+nsObjectLoadingContent::GetTypeOfContent(const nsCString& aMIMEType,
+                                         bool aNoFakePlugin)
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
 
   ObjectType type = static_cast<ObjectType>(
-    nsContentUtils::HtmlObjectContentTypeForMIMEType(aMIMEType, thisContent));
+    nsContentUtils::HtmlObjectContentTypeForMIMEType(aMIMEType, aNoFakePlugin,
+                                                     thisContent));
 
   // Switch the result type to eType_Null ic the capability is not present.
   uint32_t caps = GetCapabilities();
   if (!(caps & eSupportImages) && type == eType_Image) {
     type = eType_Null;
   }
   if (!(caps & eSupportDocuments) && type == eType_Document) {
     type = eType_Null;
   }
-  if (!(caps & eSupportPlugins) && type == eType_Plugin) {
+  if (!(caps & eSupportPlugins) &&
+      (type == eType_Plugin || type == eType_FakePlugin)) {
     type = eType_Null;
   }
 
   return type;
 }
 
 nsPluginFrame*
 nsObjectLoadingContent::GetExistingFrame()
@@ -3119,39 +3223,55 @@ nsObjectLoadingContent::PlayPlugin(Syste
   }
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::Reload(bool aClearActivation)
 {
   if (aClearActivation) {
     mActivated = false;
+    mSkipFakePlugins = false;
   }
 
   return LoadObject(true, true);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetActivated(bool *aActivated)
 {
   *aActivated = Activated();
   return NS_OK;
 }
 
 uint32_t
 nsObjectLoadingContent::DefaultFallbackType()
 {
   FallbackType reason;
-  bool go = ShouldPlay(reason, true);
-  if (go) {
+  if (ShouldPlay(reason)) {
     return PLUGIN_ACTIVE;
   }
   return reason;
 }
 
+NS_IMETHODIMP
+nsObjectLoadingContent::SkipFakePlugins()
+{
+  if (!nsContentUtils::IsCallerChrome())
+    return NS_ERROR_NOT_AVAILABLE;
+
+  mSkipFakePlugins = true;
+
+  // If we're showing a fake plugin now, reload
+  if (mType == eType_FakePlugin) {
+    return LoadObject(true, true);
+  }
+
+  return NS_OK;
+}
+
 uint32_t
 nsObjectLoadingContent::GetRunID(SystemCallerGuarantee, ErrorResult& aRv)
 {
   if (!mHasRunID) {
     // The plugin instance must not have a run ID, so we must
     // be running the plugin in-process.
     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return 0;
@@ -3188,17 +3308,17 @@ nsObjectLoadingContent::ShouldBlockConte
   if (mContentBlockingEnabled && mURI && IsFlashMIME(mContentType) && sBlockURIs ) {
     return true;
   }
 
   return false;
 }
 
 bool
-nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType)
+nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
 {
   nsresult rv;
 
   if (!sPrefsInitialized) {
     initializeObjectLoadingContentPrefs();
   }
 
   if (BrowserTabsRemoteAutostart()) {
@@ -3211,21 +3331,16 @@ nsObjectLoadingContent::ShouldPlay(Fallb
       // the other. Otherwise we'll get hangs.
       aReason = eFallbackDisabled;
       return false;
     }
   }
 
   RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
 
-  // at this point if it's not a plugin, we let it play/fallback
-  if (!aIgnoreCurrentType && mType != eType_Plugin) {
-    return true;
-  }
-
   // Order of checks:
   // * Assume a default of click-to-play
   // * If globally disabled, per-site permissions cannot override.
   // * If blocklisted, override the reason with the blocklist reason
   // * Check if the flash blocking status for this page denies flash from loading.
   // * Check per-site permissions and follow those if specified.
   // * Honor per-plugin disabled permission
   // * Blocklisted plugins are forced to CtP
@@ -3251,18 +3366,17 @@ nsObjectLoadingContent::ShouldPlay(Fallb
   if (blocklistState == nsIBlocklistService::STATE_BLOCKED) {
     // no override possible
     aReason = eFallbackBlocklisted;
     return false;
   }
 
   if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE) {
     aReason = eFallbackVulnerableUpdatable;
-  }
-  else if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
+  } else if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
     aReason = eFallbackVulnerableNoUpdate;
   }
 
   // Document and window lookup
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
   MOZ_ASSERT(thisContent);
   nsIDocument* ownerDoc = thisContent->OwnerDoc();
 
@@ -3286,20 +3400,20 @@ nsObjectLoadingContent::ShouldPlay(Fallb
   }
 
   // Check the permission manager for permission based on the principal of
   // the toplevel content.
   nsCOMPtr<nsIPermissionManager> permissionManager = services::GetPermissionManager();
   NS_ENSURE_TRUE(permissionManager, false);
 
   // For now we always say that the system principal uses click-to-play since
-  // that maintains current behavior and we have tests that expect this.
-  // What we really should do is disable plugins entirely in pages that use
-  // the system principal, i.e. in chrome pages. That way the click-to-play
-  // code here wouldn't matter at all. Bug 775301 is tracking this.
+  // that maintains current behavior and we have tests that expect this.  What
+  // we really should do is disable plugins entirely in pages that use the
+  // system principal, i.e. in chrome pages. That way the click-to-play code
+  // here wouldn't matter at all. Bug 775301 is tracking this.
   if (!nsContentUtils::IsSystemPrincipal(topDoc->NodePrincipal())) {
     nsAutoCString permissionString;
     rv = pluginHost->GetPermissionStringForType(mContentType,
                                                 nsPluginHost::eExcludeNone,
                                                 permissionString);
     NS_ENSURE_SUCCESS(rv, false);
     uint32_t permission;
     rv = permissionManager->TestPermissionFromPrincipal(topDoc->NodePrincipal(),
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -59,22 +59,26 @@ class nsObjectLoadingContent : public ns
     // nsIObjectLoadingContent
     enum ObjectType {
       // Loading, type not yet known. We may be waiting for a channel to open.
       eType_Loading        = TYPE_LOADING,
       // Content is a *non-svg* image
       eType_Image          = TYPE_IMAGE,
       // Content is a plugin
       eType_Plugin         = TYPE_PLUGIN,
+      // Content is a fake plugin, which loads as a document but behaves as a
+      // plugin (see nsPluginHost::CreateFakePlugin)
+      eType_FakePlugin     = TYPE_FAKE_PLUGIN,
       // Content is a subdocument, possibly SVG
       eType_Document       = TYPE_DOCUMENT,
       // No content loaded (fallback). May be showing alternate content or
       // a custom error handler - *including* click-to-play dialogs
       eType_Null           = TYPE_NULL
     };
+
     enum FallbackType {
       // The content type is not supported (e.g. plugin not installed)
       eFallbackUnsupported = nsIObjectLoadingContent::PLUGIN_UNSUPPORTED,
       // Showing alternate content
       eFallbackAlternate = nsIObjectLoadingContent::PLUGIN_ALTERNATE,
       // The plugin exists, but is disabled
       eFallbackDisabled = nsIObjectLoadingContent::PLUGIN_DISABLED,
       // The plugin is blocklisted and disabled
@@ -187,17 +191,17 @@ class nsObjectLoadingContent : public ns
       CopyUTF8toUTF16(mContentType, aType);
     }
     uint32_t DisplayedType() const
     {
       return mType;
     }
     uint32_t GetContentTypeForMIMEType(const nsAString& aMIMEType)
     {
-      return GetTypeOfContent(NS_ConvertUTF16toUTF8(aMIMEType));
+      return GetTypeOfContent(NS_ConvertUTF16toUTF8(aMIMEType), false);
     }
     void PlayPlugin(mozilla::dom::SystemCallerGuarantee,
                     mozilla::ErrorResult& aRv);
     void Reload(bool aClearActivation, mozilla::ErrorResult& aRv)
     {
       aRv = Reload(aClearActivation);
     }
     bool Activated() const
@@ -218,16 +222,21 @@ class nsObjectLoadingContent : public ns
     uint32_t PluginFallbackType() const
     {
       return mFallbackType;
     }
     bool HasRunningPlugin() const
     {
       return !!mInstanceOwner;
     }
+    // FIXME rename this
+    void SkipFakePlugins(mozilla::ErrorResult& aRv)
+    {
+      aRv = SkipFakePlugins();
+    }
     void SwapFrameLoaders(mozilla::dom::HTMLIFrameElement& aOtherLoaderOwner,
                           mozilla::ErrorResult& aRv)
     {
       aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     }
     void SwapFrameLoaders(nsXULElement& aOtherLoaderOwner,
                           mozilla::ErrorResult& aRv)
     {
@@ -456,19 +465,20 @@ class nsObjectLoadingContent : public ns
      * If this object should be tested against blocking list.
      */
     bool ShouldBlockContent();
 
     /**
      * If this object is allowed to play plugin content, or if it would display
      * click-to-play instead.
      * NOTE that this does not actually check if the object is a loadable plugin
-     * NOTE This ignores the current activated state. The caller should check this if appropriate.
+     * NOTE This ignores the current activated state. The caller should check
+     *      this if appropriate.
      */
-    bool ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType);
+    bool ShouldPlay(FallbackType &aReason);
 
     /**
      * This method tells if the fallback content should be attempted to be used
      * over the original object content.
      * It will look at prefs and this plugin's CTP state to make a decision.
      *
      * NOTE that this doesn't say whether the fallback _will_ be used, only whether
      * we should look into it to possibly use it. The final answer will be
@@ -517,16 +527,24 @@ class nsObjectLoadingContent : public ns
 
     /**
      * Gets the plugin instance and creates a plugin stream listener, assigning
      * it to mFinalListener
      */
     bool MakePluginListener();
 
     /**
+     * Helper to spawn mFrameLoader and return a pointer to its docshell
+     *
+     * @param aURI URI we intend to load for the recursive load check (does not
+     *             actually load anything)
+     */
+    already_AddRefed<nsIDocShell> SetupFrameLoader(nsIURI *aRecursionCheckURI);
+
+    /**
      * Unloads all content and resets the object to a completely unloaded state
      *
      * NOTE Calls StopPluginInstance() and may spin the event loop
      *
      * @param aResetState Reset the object type to 'loading' and destroy channel
      *                    as well
      */
     void UnloadObject(bool aResetState = true);
@@ -545,20 +563,24 @@ class nsObjectLoadingContent : public ns
                             mozilla::EventStates aOldState,
                             bool aSync, bool aNotify);
 
     /**
      * Returns a ObjectType value corresponding to the type of content we would
      * support the given MIME type as, taking capabilities and plugin state
      * into account
      *
+     * @param aNoFakePlugin Don't select a fake plugin handler as a valid type,
+     *                      as when SkipFakePlugins() is called.
+     * @return The ObjectType enum value that we would attempt to load
+     *
      * NOTE this does not consider whether the content would be suppressed by
      *      click-to-play or other content policy checks
      */
-    ObjectType GetTypeOfContent(const nsCString& aMIMEType);
+    ObjectType GetTypeOfContent(const nsCString& aMIMEType, bool aNoFakePlugin);
 
     /**
      * Gets the frame that's associated with this content node.
      * Does not flush.
      */
     nsPluginFrame* GetExistingFrame();
 
     /**
@@ -682,24 +704,27 @@ class nsObjectLoadingContent : public ns
 
     // Used to keep track of whether or not a plugin has been explicitly
     // activated by PlayPlugin(). (see ShouldPlay())
     bool                        mActivated : 1;
 
     // Whether content blocking is enabled or not for this object.
     bool                        mContentBlockingEnabled : 1;
 
+    // If we should not use fake plugins until the next type change
+    bool                        mSkipFakePlugins : 1;
+
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
-    // For plugin stand-in types (click-to-play) tracks
-    // whether content js has tried to access the plugin script object.
+    // For plugin stand-in types (click-to-play) tracks whether content js has
+    // tried to access the plugin script object.
     bool                        mScriptRequested : 1;
 
     // True if object represents an object/embed tag pointing to a flash embed
     // for a youtube video. When possible (see IsRewritableYoutubeEmbed function
     // comments for details), we change these to try to load HTML5 versions of
     // videos.
     bool                        mRewrittenYoutubeEmbed : 1;
 
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -340,17 +340,17 @@ bool
 HTMLObjectElement::IsFocusableForTabIndex()
 {
   nsIDocument* doc = GetComposedDoc();
   if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
     return false;
   }
 
   return IsEditableRoot() ||
-         (Type() == eType_Document &&
+         ((Type() == eType_Document || Type() == eType_FakePlugin) &&
           nsContentUtils::IsSubDocumentTabbable(this));
 }
 
 bool
 HTMLObjectElement::IsHTMLFocusable(bool aWithMouse,
                                    bool *aIsFocusable, int32_t *aTabIndex)
 {
   // TODO: this should probably be managed directly by IsHTMLFocusable.
@@ -364,17 +364,18 @@ HTMLObjectElement::IsHTMLFocusable(bool 
     *aIsFocusable = false;
 
     return false;
   }
 
   // This method doesn't call nsGenericHTMLFormElement intentionally.
   // TODO: It should probably be changed when bug 597242 will be fixed.
   if (Type() == eType_Plugin || IsEditableRoot() ||
-      (Type() == eType_Document && nsContentUtils::IsSubDocumentTabbable(this))) {
+      ((Type() == eType_Document || Type() == eType_FakePlugin) &&
+       nsContentUtils::IsSubDocumentTabbable(this))) {
     // Has plugin content: let the plugin decide what to do in terms of
     // internal focus from mouse clicks
     if (aTabIndex) {
       GetTabIndex(aTabIndex);
     }
 
     *aIsFocusable = true;
 
@@ -395,17 +396,17 @@ HTMLObjectElement::IsHTMLFocusable(bool 
 }
 
 nsIContent::IMEState
 HTMLObjectElement::GetDesiredIMEState()
 {
   if (Type() == eType_Plugin) {
     return IMEState(IMEState::PLUGIN);
   }
-   
+
   return nsGenericHTMLFormElement::GetDesiredIMEState();
 }
 
 NS_IMETHODIMP
 HTMLObjectElement::Reset()
 {
   return NS_OK;
 }
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -78,25 +78,27 @@ partial interface HTMLObjectElement {
 };
 
 [NoInterfaceObject]
 interface MozObjectLoadingContent {
   // Mirrored chrome-only scriptable nsIObjectLoadingContent methods.  Please
   // make sure to update this list if nsIObjectLoadingContent changes.  Also,
   // make sure everything on here is [ChromeOnly].
   [ChromeOnly]
-  const unsigned long TYPE_LOADING  = 0;
+  const unsigned long TYPE_LOADING     = 0;
   [ChromeOnly]
-  const unsigned long TYPE_IMAGE    = 1;
+  const unsigned long TYPE_IMAGE       = 1;
+  [ChromeOnly]
+  const unsigned long TYPE_PLUGIN      = 2;
   [ChromeOnly]
-  const unsigned long TYPE_PLUGIN   = 2;
+  const unsigned long TYPE_FAKE_PLUGIN = 3;
   [ChromeOnly]
-  const unsigned long TYPE_DOCUMENT = 3;
+  const unsigned long TYPE_DOCUMENT    = 4;
   [ChromeOnly]
-  const unsigned long TYPE_NULL     = 4;
+  const unsigned long TYPE_NULL        = 5;
 
   // The content type is not supported (e.g. plugin not installed)
   [ChromeOnly]
   const unsigned long PLUGIN_UNSUPPORTED          = 0;
   // Showing alternate content
   [ChromeOnly]
   const unsigned long PLUGIN_ALTERNATE            = 1;
   // The plugin exists, but is disabled
@@ -199,16 +201,22 @@ interface MozObjectLoadingContent {
 
   /**
    * If this object currently owns a running plugin, regardless of whether or
    * not one is pending spawn/despawn.
    */
   [ChromeOnly]
   readonly attribute boolean hasRunningPlugin;
 
+  /**
+   * Disable the use of fake plugins and reload the tag if necessary
+   */
+  [ChromeOnly, Throws]
+  void skipFakePlugins();
+
   [ChromeOnly, Throws, NeedsCallerType]
   readonly attribute unsigned long runID;
 };
 
 /**
  * Name:Value pair type used for passing parameters to NPAPI or javascript
  * plugins.
  */
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3804,16 +3804,19 @@ nsCSSFrameConstructor::FindObjectData(El
   static const FrameConstructionDataByInt sObjectData[] = {
     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
                       NS_NewEmptyFrame),
     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
                       NS_NewObjectFrame),
     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
                       NS_NewImageFrame),
     SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
+                      NS_NewSubDocumentFrame),
+    // Fake plugin handlers load as documents
+    SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_FAKE_PLUGIN,
                       NS_NewSubDocumentFrame)
     // Nothing for TYPE_NULL so we'll construct frames by display there
   };
 
   return FindDataByInt((int32_t)type, aElement, aStyleContext,
                        sObjectData, ArrayLength(sObjectData));
 }
 
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -379,17 +379,17 @@ NS_GetIsDocumentChannel(nsIChannel * aCh
       *aIsDocument = false;
       return NS_OK;
   }
   nsAutoCString mimeType;
   rv = aChannel->GetContentType(mimeType);
   if (NS_FAILED(rv)) {
       return rv;
   }
-  if (nsContentUtils::HtmlObjectContentTypeForMIMEType(mimeType, nullptr) ==
+  if (nsContentUtils::HtmlObjectContentTypeForMIMEType(mimeType, false, nullptr) ==
       nsIObjectLoadingContent::TYPE_DOCUMENT) {
       *aIsDocument = true;
       return NS_OK;
   }
   *aIsDocument = false;
   return NS_OK;
 }