Bug 853995 - Move plugin parameters array from nsPluginInstanceOwner to content. r=johns,jst
authorCatalin Badea <cbadea@mozilla.com>
Fri, 15 Aug 2014 14:17:35 -0700
changeset 199923 f8829fe7dfe1b65bdc8c3e82fcd2110657dbd8f0
parent 199922 0b3ddcde7580a8a7a3c014fc334adacf62855826
child 199924 39c9d9bba87e29382bcd5f0f08447cad3116456d
push id27326
push userryanvm@gmail.com
push dateSat, 16 Aug 2014 21:43:28 +0000
treeherdermozilla-central@94ba78a42305 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohns, jst
bugs853995
milestone34.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 853995 - Move plugin parameters array from nsPluginInstanceOwner to content. r=johns,jst
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/base/nsPluginInstanceOwner.h
dom/webidl/HTMLObjectElement.webidl
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -7,16 +7,17 @@
  * A base class implementing nsIObjectLoadingContent for use by
  * various content nodes that want to provide plugin/document/image
  * loading functionality (eg <embed>, <object>, <applet>, etc).
  */
 
 // Interface headers
 #include "imgLoader.h"
 #include "nsIContent.h"
+#include "nsIContentInlines.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIDOMCustomEvent.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsIObjectFrame.h"
@@ -77,16 +78,17 @@
 #include "mozilla/BasicEvents.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/dom/HTMLObjectElementBinding.h"
 
 #ifdef XP_WIN
 // Thanks so much, Microsoft! :(
 #ifdef CreateEvent
 #undef CreateEvent
 #endif
 #endif // XP_WIN
 
@@ -911,16 +913,177 @@ nsObjectLoadingContent::InstantiatePlugi
                             doc,
                             NS_LITERAL_STRING("PluginInstantiated"));
   NS_DispatchToCurrentThread(ev);
 
   return NS_OK;
 }
 
 void
+nsObjectLoadingContent::GetPluginAttributes(nsTArray<MozPluginParameter>& aAttributes)
+{
+  aAttributes = mCachedAttributes;
+}
+
+void
+nsObjectLoadingContent::GetPluginParameters(nsTArray<MozPluginParameter>& aParameters)
+{
+  aParameters = mCachedParameters;
+}
+
+void
+nsObjectLoadingContent::GetNestedParams(nsTArray<MozPluginParameter>& aParams,
+                                        bool aIgnoreCodebase)
+{
+  nsCOMPtr<nsIDOMElement> domElement =
+    do_QueryInterface(static_cast<nsIObjectLoadingContent*>(this));
+
+  nsCOMPtr<nsIDOMHTMLCollection> allParams;
+  NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
+  domElement->GetElementsByTagNameNS(xhtml_ns,
+        NS_LITERAL_STRING("param"), getter_AddRefs(allParams));
+
+  if (!allParams)
+    return;
+
+  uint32_t numAllParams;
+  allParams->GetLength(&numAllParams);
+  for (uint32_t i = 0; i < numAllParams; i++) {
+    nsCOMPtr<nsIDOMNode> pNode;
+    allParams->Item(i, getter_AddRefs(pNode));
+    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(pNode);
+
+    if (!element)
+      continue;
+
+    nsAutoString name;
+    element->GetAttribute(NS_LITERAL_STRING("name"), name);
+
+    if (name.IsEmpty())
+      continue;
+
+    nsCOMPtr<nsIDOMNode> parent;
+    nsCOMPtr<nsIDOMHTMLObjectElement> domObject;
+    nsCOMPtr<nsIDOMHTMLAppletElement> domApplet;
+    pNode->GetParentNode(getter_AddRefs(parent));
+    while (!(domObject || domApplet) && parent) {
+      domObject = do_QueryInterface(parent);
+      domApplet = do_QueryInterface(parent);
+      nsCOMPtr<nsIDOMNode> temp;
+      parent->GetParentNode(getter_AddRefs(temp));
+      parent = temp;
+    }
+
+    if (domApplet) {
+      parent = do_QueryInterface(domApplet);
+    } else if (domObject) {
+      parent = do_QueryInterface(domObject);
+    } else {
+      continue;
+    }
+
+    nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(domElement);
+    if (parent == domNode) {
+      MozPluginParameter param;
+      element->GetAttribute(NS_LITERAL_STRING("name"), param.mName);
+      element->GetAttribute(NS_LITERAL_STRING("value"), param.mValue);
+
+      param.mName.Trim(" \n\r\t\b", true, true, false);
+      param.mValue.Trim(" \n\r\t\b", true, true, false);
+
+      // ignore codebase param if it was already added in the attributes array.
+      if (aIgnoreCodebase && param.mName.EqualsIgnoreCase("codebase")) {
+        continue;
+      }
+
+      aParams.AppendElement(param);
+    }
+  }
+}
+
+void
+nsObjectLoadingContent::BuildParametersArray()
+{
+  if (mCachedAttributes.Length() || mCachedParameters.Length()) {
+    MOZ_ASSERT(false, "Parameters array should be empty.");
+    return;
+  }
+
+  nsCOMPtr<nsIContent> content =
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
+
+  int32_t start = 0, end = content->GetAttrCount(), step = 1;
+  // HTML attributes are stored in reverse order.
+  if (content->IsHTML() && content->IsInHTMLDocument()) {
+    start = end - 1;
+    end = -1;
+    step = -1;
+  }
+
+  for (int32_t i = start; i != end; i += step) {
+    MozPluginParameter param;
+    const nsAttrName* attrName = content->GetAttrNameAt(i);
+    nsIAtom* atom = attrName->LocalName();
+    content->GetAttr(attrName->NamespaceID(), atom, param.mValue);
+    atom->ToString(param.mName);
+    mCachedAttributes.AppendElement(param);
+  }
+
+  bool isJava = nsPluginHost::IsJavaMIMEType(mContentType.get());
+
+  nsCString codebase;
+  if (isJava) {
+      mBaseURI->GetSpec(codebase);
+  }
+
+  nsAdoptingCString wmodeOverride = Preferences::GetCString("plugins.force.wmode");
+
+  for (uint32_t i = 0; i < mCachedAttributes.Length(); i++) {
+    if (!wmodeOverride.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("wmode")) {
+      CopyASCIItoUTF16(wmodeOverride, mCachedAttributes[i].mValue);
+      wmodeOverride.Truncate();
+    } else if (!codebase.IsEmpty() && mCachedAttributes[i].mName.EqualsIgnoreCase("codebase")) {
+      CopyASCIItoUTF16(codebase, mCachedAttributes[i].mValue);
+      codebase.Truncate();
+    }
+  }
+
+  if (!wmodeOverride.IsEmpty()) {
+    MozPluginParameter param;
+    param.mName = NS_LITERAL_STRING("wmode");
+    CopyASCIItoUTF16(wmodeOverride, param.mValue);
+    mCachedAttributes.AppendElement(param);
+  }
+
+  if (!codebase.IsEmpty()) {
+    MozPluginParameter param;
+    param.mName = NS_LITERAL_STRING("codebase");
+    CopyASCIItoUTF16(codebase, param.mValue);
+    mCachedAttributes.AppendElement(param);
+  }
+
+  // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
+  // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
+  // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
+  // look for "data", lets instead copy the "data" attribute and add another entry
+  // to the bottom of the array if there isn't already a "src" specified.
+  if (content->Tag() == nsGkAtoms::object &&
+      !content->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
+    MozPluginParameter param;
+    content->GetAttr(kNameSpaceID_None, nsGkAtoms::data, param.mValue);
+    if (!param.mValue.IsEmpty()) {
+      param.mName = NS_LITERAL_STRING("SRC");
+      mCachedAttributes.AppendElement(param);
+    }
+  }
+
+  GetNestedParams(mCachedParameters, isJava);
+}
+
+void
 nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
 {
   // XXX(johns): We cannot touch plugins or run arbitrary script from this call,
   //             as nsDocument is in a non-reentrant state.
 
   // If we have a plugin we want to queue an event to stop it unless we are
   // moved into an active document before returning to the event loop.
   if (mInstanceOwner || mInstantiating) {
@@ -1497,69 +1660,25 @@ nsObjectLoadingContent::UpdateObjectPara
   nsAutoString codebaseStr;
   nsCOMPtr<nsIURI> docBaseURI = thisContent->GetBaseURI();
   bool hasCodebase = thisContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase);
   if (hasCodebase)
     thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase, codebaseStr);
 
 
   // Java wants the codebase attribute even if it occurs in <param> tags
-  // XXX(johns): This duplicates a chunk of code from nsInstanceOwner, see
-  //             bug 853995
   if (isJava) {
     // Find all <param> tags that are nested beneath us, but not beneath another
     // object/applet tag.
-    nsCOMArray<nsIDOMElement> ourParams;
-    nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(thisContent);
-
-    nsCOMPtr<nsIDOMHTMLCollection> allParams;
-    NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
-    mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
-                                         getter_AddRefs(allParams));
-    if (allParams) {
-      uint32_t numAllParams;
-      allParams->GetLength(&numAllParams);
-      for (uint32_t i = 0; i < numAllParams; i++) {
-        nsCOMPtr<nsIDOMNode> pnode;
-        allParams->Item(i, getter_AddRefs(pnode));
-        nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
-        if (domelement) {
-          nsAutoString name;
-          domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
-          name.Trim(" \n\r\t\b", true, true, false);
-          if (name.EqualsIgnoreCase("codebase")) {
-            // Find the first plugin element parent
-            nsCOMPtr<nsIDOMNode> parent;
-            nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
-            nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
-            pnode->GetParentNode(getter_AddRefs(parent));
-            while (!(domobject || domapplet) && parent) {
-              domobject = do_QueryInterface(parent);
-              domapplet = do_QueryInterface(parent);
-              nsCOMPtr<nsIDOMNode> temp;
-              parent->GetParentNode(getter_AddRefs(temp));
-              parent = temp;
-            }
-            if (domapplet || domobject) {
-              if (domapplet) {
-                parent = do_QueryInterface(domapplet);
-              }
-              else {
-                parent = do_QueryInterface(domobject);
-              }
-              nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
-              if (parent == mydomNode) {
-                hasCodebase = true;
-                domelement->GetAttribute(NS_LITERAL_STRING("value"),
-                                         codebaseStr);
-                codebaseStr.Trim(" \n\r\t\b", true, true, false);
-              }
-            }
-          }
-        }
+    nsTArray<MozPluginParameter> params;
+    GetNestedParams(params, false);
+    for (uint32_t i = 0; i < params.Length(); i++) {
+      if (params[i].mName.EqualsIgnoreCase("codebase")) {
+        hasCodebase = true;
+        codebaseStr = params[i].mValue;
       }
     }
   }
 
   if (isJava && hasCodebase && codebaseStr.IsEmpty()) {
     // Java treats codebase="" as "/"
     codebaseStr.Assign('/');
     // XXX(johns): This doesn't cover the case of "https:" which java would
@@ -2116,16 +2235,22 @@ nsObjectLoadingContent::LoadObject(bool 
     rv = NS_ERROR_UNEXPECTED;
     return NS_OK;
   }
 
   ///
   /// Attempt to load new type
   ///
 
+
+  // Cache the current attributes and parameters.
+  if (mType == eType_Plugin || mType == eType_Null) {
+    BuildParametersArray();
+  }
+
   // We don't set mFinalListener until OnStartRequest has been called, to
   // prevent re-entry ugliness with CloseChannel()
   nsCOMPtr<nsIStreamListener> finalListener;
   // If we decide to synchronously spawn a plugin, we do it after firing
   // notifications to avoid re-entry causing notifications to fire out of order.
   bool doSpawnPlugin = false;
   switch (mType) {
     case eType_Image:
@@ -2472,16 +2597,19 @@ nsObjectLoadingContent::UnloadObject(boo
   if (mIsStopping) {
     // The protochain is normally thrown out after a plugin stops, but if we
     // re-enter while stopping a plugin and try to load something new, we need
     // to throw away the old protochain in the nested unload.
     TeardownProtoChain();
     mIsStopping = false;
   }
 
+  mCachedAttributes.Clear();
+  mCachedParameters.Clear();
+
   // This call should be last as it may re-enter
   StopPluginInstance();
 }
 
 void
 nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
                                            EventStates aOldState,
                                            bool aSync,
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -29,16 +29,17 @@ class AutoSetInstantiatingToFalse;
 class nsObjectFrame;
 class nsFrameLoader;
 class nsXULElement;
 class nsPluginInstanceOwner;
 
 namespace mozilla {
 namespace dom {
 template<typename T> class Sequence;
+struct MozPluginParameter;
 }
 }
 
 class nsObjectLoadingContent : public nsImageLoadingContent
                              , public nsIStreamListener
                              , public nsIFrameLoaderOwner
                              , public nsIObjectLoadingContent
                              , public nsIChannelEventSink
@@ -115,16 +116,29 @@ class nsObjectLoadingContent : public ns
     ObjectType Type() const { return mType; }
 
     void SetIsNetworkCreated(bool aNetworkCreated)
     {
       mNetworkCreated = aNetworkCreated;
     }
 
     /**
+     * When the object is loaded, the attributes and all nested <param>
+     * elements are cached as name:value string pairs to be passed as
+     * parameters when instantiating the plugin.
+     *
+     * Note: these cached values can be overriden for different quirk cases.
+     */
+    // Returns the cached attributes array.
+    void GetPluginAttributes(nsTArray<mozilla::dom::MozPluginParameter>& aAttributes);
+
+    // Returns the cached <param> array.
+    void GetPluginParameters(nsTArray<mozilla::dom::MozPluginParameter>& aParameters);
+
+    /**
      * Immediately instantiate a plugin instance. This is a no-op if mType !=
      * eType_Plugin or a plugin is already running.
      *
      * aIsLoading indicates that we are in the loading code, and we can bypass
      * the mIsLoading check.
      */
     nsresult InstantiatePluginInstance(bool aIsLoading = false);
 
@@ -318,16 +332,36 @@ class nsObjectLoadingContent : public ns
       // necessarily happen when changing between object types. E.g., if a PDF
       // handler was installed between the last load of this object and now, we
       // might change from eType_Document -> eType_Plugin without changing
       // ContentType
       eParamContentTypeChanged = 1u << 2
     };
 
     /**
+     * Getter for child <param> elements that are not nested in another plugin
+     * dom element.
+     * This is an internal helper function and should not be used directly for
+     * passing parameters to the plugin instance.
+     *
+     * See GetPluginParameters and GetPluginAttributes, which also handle
+     * quirk-overrides.
+     *
+     * @param aParameters     The array containing pairs of name/value strings
+     *                        from nested <param> objects.
+     * @param aIgnoreCodebase Flag for ignoring the "codebase" param when
+     *                        building the array. This is useful when loading
+     *                        java.
+     */
+    void GetNestedParams(nsTArray<mozilla::dom::MozPluginParameter>& aParameters,
+                         bool aIgnoreCodebase);
+
+    void BuildParametersArray();
+
+    /**
      * Loads fallback content with the specified FallbackType
      *
      * @param aType   FallbackType value for type of fallback we're loading
      * @param aNotify Send notifications and events. If false, caller is
      *                responsible for doing so
      */
     void LoadFallback(FallbackType aType, bool aNotify);
 
@@ -574,11 +608,13 @@ class nsObjectLoadingContent : public ns
 
     // For plugin stand-in types (click-to-play, play preview, ...) tracks
     // whether content js has tried to access the plugin script object.
     bool                        mScriptRequested : 1;
 
     nsWeakFrame                 mPrintFrame;
 
     nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
+    nsTArray<mozilla::dom::MozPluginParameter> mCachedAttributes;
+    nsTArray<mozilla::dom::MozPluginParameter> mCachedParameters;
 };
 
 #endif
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -34,18 +34,20 @@
 #include "nsPluginStreamListenerPeer.h"
 #include "nsSize.h"
 #include "nsNetCID.h"
 #include "nsIContent.h"
 #include "nsVersionComparator.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "nsILoadContext.h"
+#include "mozilla/dom/HTMLObjectElementBinding.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "ANPBase.h"
 #include <android/log.h>
 #include "android_npapi.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "AndroidBridge.h"
@@ -191,16 +193,19 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
     mPlugin(nullptr),
     mMIMEType(nullptr),
     mOwner(nullptr),
     mCurrentPluginEvent(nullptr)
 #ifdef MOZ_WIDGET_ANDROID
   , mOnScreen(true)
 #endif
   , mHaveJavaC2PJSObjectQuirk(false)
+  , mCachedParamLength(0)
+  , mCachedParamNames(nullptr)
+  , mCachedParamValues(nullptr)
 {
   mNPP.pdata = nullptr;
   mNPP.ndata = this;
 
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
 
 #ifdef MOZ_WIDGET_ANDROID
   sPluginNPPMap[&mNPP] = this;
@@ -214,16 +219,38 @@ nsNPAPIPluginInstance::~nsNPAPIPluginIns
 #ifdef MOZ_WIDGET_ANDROID
   sPluginNPPMap.erase(&mNPP);
 #endif
 
   if (mMIMEType) {
     PR_Free((void *)mMIMEType);
     mMIMEType = nullptr;
   }
+
+  if (!mCachedParamValues || !mCachedParamNames) {
+    return;
+  }
+  MOZ_ASSERT(mCachedParamValues && mCachedParamNames);
+
+  for (uint32_t i = 0; i < mCachedParamLength; i++) {
+    if (mCachedParamNames[i]) {
+      NS_Free(mCachedParamNames[i]);
+      mCachedParamNames[i] = nullptr;
+    }
+    if (mCachedParamValues[i]) {
+      NS_Free(mCachedParamValues[i]);
+      mCachedParamValues[i] = nullptr;
+    }
+  }
+
+  NS_Free(mCachedParamNames);
+  mCachedParamNames = nullptr;
+
+  NS_Free(mCachedParamValues);
+  mCachedParamValues = nullptr;
 }
 
 uint32_t nsNPAPIPluginInstance::gInUnsafePluginCalls = 0;
 
 void
 nsNPAPIPluginInstance::Destroy()
 {
   Stop();
@@ -373,38 +400,16 @@ nsNPAPIPluginInstance::GetTagType(nsPlug
   if (!mOwner) {
     return NS_ERROR_FAILURE;
   }
 
   return mOwner->GetTagType(result);
 }
 
 nsresult
-nsNPAPIPluginInstance::GetAttributes(uint16_t& n, const char*const*& names,
-                                     const char*const*& values)
-{
-  if (!mOwner) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return mOwner->GetAttributes(n, names, values);
-}
-
-nsresult
-nsNPAPIPluginInstance::GetParameters(uint16_t& n, const char*const*& names,
-                                     const char*const*& values)
-{
-  if (!mOwner) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return mOwner->GetParameters(n, names, values);
-}
-
-nsresult
 nsNPAPIPluginInstance::GetMode(int32_t *result)
 {
   if (mOwner)
     return mOwner->GetMode(result);
   else
     return NS_ERROR_FAILURE;
 }
 
@@ -422,109 +427,73 @@ nsNPAPIPluginInstance::FileCachedStreamL
 
 nsresult
 nsNPAPIPluginInstance::Start()
 {
   if (mRunning == RUNNING) {
     return NS_OK;
   }
 
+  if (!mOwner) {
+    MOZ_ASSERT(false, "Should not be calling Start() on unowned plugin.");
+    return NS_ERROR_FAILURE;
+  }
+
   PluginDestructionGuard guard(this);
 
-  uint16_t count = 0;
-  const char* const* names = nullptr;
-  const char* const* values = nullptr;
+  nsTArray<MozPluginParameter> attributes;
+  nsTArray<MozPluginParameter> params;
+
   nsPluginTagType tagtype;
   nsresult rv = GetTagType(&tagtype);
   if (NS_SUCCEEDED(rv)) {
-    // Note: If we failed to get the tag type, we may be a full page plugin, so no arguments
-    rv = GetAttributes(count, names, values);
-    NS_ENSURE_SUCCESS(rv, rv);
+    mOwner->GetAttributes(attributes);
+    mOwner->GetParameters(params);
+  } else {
+    MOZ_ASSERT(false, "Failed to get tag type.");
+  }
+
+  mCachedParamLength = attributes.Length() + 1 + params.Length();
+
+  // We add an extra entry "PARAM" as a separator between the attribute
+  // and param values, but we don't count it if there are no <param> entries.
+  // Legacy behavior quirk.
+  uint32_t quirkParamLength = params.Length() ?
+                                mCachedParamLength : attributes.Length();
+
+  mCachedParamNames = (char**)NS_Alloc(sizeof(char*) * mCachedParamLength);
+  mCachedParamValues = (char**)NS_Alloc(sizeof(char*) * mCachedParamLength);
 
-    // nsPluginTagType_Object or Applet may also have PARAM tags
-    // Note: The arrays handed back by GetParameters() are
-    // crafted specially to be directly behind the arrays from GetAttributes()
-    // with a null entry as a separator. This is for 4.x backwards compatibility!
-    // see bug 111008 for details
-    if (tagtype != nsPluginTagType_Embed) {
-      uint16_t pcount = 0;
-      const char* const* pnames = nullptr;
-      const char* const* pvalues = nullptr;
-      if (NS_SUCCEEDED(GetParameters(pcount, pnames, pvalues))) {
-        // Android expects an empty string as the separator instead of null
-#ifdef MOZ_WIDGET_ANDROID
-        NS_ASSERTION(PL_strcmp(values[count], "") == 0, "attribute/parameter array not setup correctly for Android NPAPI plugins");
-#else
-        NS_ASSERTION(!values[count], "attribute/parameter array not setup correctly for NPAPI plugins");
-#endif
-        if (pcount)
-          count += ++pcount; // if it's all setup correctly, then all we need is to
-                             // change the count (attrs + PARAM/blank + params)
-      }
-    }
+  for (uint32_t i = 0; i < attributes.Length(); i++) {
+    mCachedParamNames[i] = ToNewUTF8String(attributes[i].mName);
+    mCachedParamValues[i] = ToNewUTF8String(attributes[i].mValue);
+  }
+
+  // Android expects and empty string instead of null.
+  mCachedParamNames[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
+  #ifdef MOZ_WIDGET_ANDROID
+    mCachedParamValues[attributes.Length()] = ToNewUTF8String(NS_LITERAL_STRING(""));
+  #else
+    mCachedParamValues[attributes.Length()] = nullptr;
+  #endif
+
+  for (uint32_t i = 0, pos = attributes.Length() + 1; i < params.Length(); i ++) {
+    mCachedParamNames[pos] = ToNewUTF8String(params[i].mName);
+    mCachedParamValues[pos] = ToNewUTF8String(params[i].mValue);
+    pos++;
   }
 
   int32_t       mode;
   const char*   mimetype;
   NPError       error = NPERR_GENERIC_ERROR;
 
   GetMode(&mode);
   GetMIMEType(&mimetype);
 
-  CheckJavaC2PJSObjectQuirk(count, names, values);
-
-  // Some older versions of Flash have a bug in them
-  // that causes the stack to become currupt if we
-  // pass swliveconnect=1 in the NPP_NewProc arrays.
-  // See bug 149336 (UNIX), bug 186287 (Mac)
-  //
-  // The code below disables the attribute unless
-  // the environment variable:
-  // MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK
-  // is set.
-  //
-  // It is okay to disable this attribute because
-  // back in 4.x, scripting required liveconnect to
-  // start Java which was slow. Scripting no longer
-  // requires starting Java and is quick plus controled
-  // from the browser, so Flash now ignores this attribute.
-  //
-  // This code can not be put at the time of creating
-  // the array because we may need to examine the
-  // stream header to determine we want Flash.
-
-  static const char flashMimeType[] = "application/x-shockwave-flash";
-  static const char blockedParam[] = "swliveconnect";
-  if (count && !PL_strcasecmp(mimetype, flashMimeType)) {
-    static int cachedDisableHack = 0;
-    if (!cachedDisableHack) {
-       if (PR_GetEnv("MOZILLA_PLUGIN_DISABLE_FLASH_SWLIVECONNECT_HACK"))
-         cachedDisableHack = -1;
-       else
-         cachedDisableHack = 1;
-    }
-    if (cachedDisableHack > 0) {
-      for (uint16_t i=0; i<count; i++) {
-        if (!PL_strcasecmp(names[i], blockedParam)) {
-          // BIG FAT WARNIG:
-          // I'm ugly casting |const char*| to |char*| and altering it
-          // because I know we do malloc it values in
-          // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/layout/html/base/src/nsObjectFrame.cpp&rev=1.349&root=/cvsroot#3020
-          // and free it at line #2096, so it couldn't be a const ptr to string literal
-          char *val = (char*) values[i];
-          if (val && *val) {
-            // we cannot just *val=0, it won't be free properly in such case
-            val[0] = '0';
-            val[1] = 0;
-          }
-          break;
-        }
-      }
-    }
-  }
+  CheckJavaC2PJSObjectQuirk(quirkParamLength, mCachedParamNames, mCachedParamValues);
 
   bool oldVal = mInPluginInitCall;
   mInPluginInitCall = true;
 
   // Need this on the stack before calling NPP_New otherwise some callbacks that
   // the plugin may make could fail (NPN_HasProperty, for example).
   NPPAutoPusher autopush(&mNPP);
 
@@ -536,23 +505,23 @@ nsNPAPIPluginInstance::Start()
     return NS_ERROR_FAILURE;
 
   // Mark this instance as running before calling NPP_New because the plugin may
   // call other NPAPI functions, like NPN_GetURLNotify, that assume this is set
   // before returning. If the plugin returns failure, we'll clear it out below.
   mRunning = RUNNING;
 
   nsresult newResult = library->NPP_New((char*)mimetype, &mNPP, (uint16_t)mode,
-                                        count, (char**)names, (char**)values,
-                                        nullptr, &error);
+                                        quirkParamLength, mCachedParamNames,
+                                        mCachedParamValues, nullptr, &error);
   mInPluginInitCall = oldVal;
 
   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   ("NPP New called: this=%p, npp=%p, mime=%s, mode=%d, argc=%d, return=%d\n",
-  this, &mNPP, mimetype, mode, count, error));
+  this, &mNPP, mimetype, mode, quirkParamLength, error));
 
   if (NS_FAILED(newResult) || error != NPERR_NO_ERROR) {
     mRunning = DESTROYED;
     nsJSNPRuntime::OnPluginDestroy(&mNPP);
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -300,20 +300,16 @@ public:
     }
   }
 
 protected:
 
   virtual ~nsNPAPIPluginInstance();
 
   nsresult GetTagType(nsPluginTagType *result);
-  nsresult GetAttributes(uint16_t& n, const char*const*& names,
-                         const char*const*& values);
-  nsresult GetParameters(uint16_t& n, const char*const*& names,
-                         const char*const*& values);
   nsresult GetMode(int32_t *result);
 
   // check if this is a Java applet and affected by bug 750480
   void CheckJavaC2PJSObjectQuirk(uint16_t paramCount,
                                  const char* const* names,
                                  const char* const* values);
 
   // The structure used to communicate between the plugin instance and
@@ -393,16 +389,22 @@ private:
 
   nsIntSize mCurrentSize;
 #endif
 
   // is this instance Java and affected by bug 750480?
   bool mHaveJavaC2PJSObjectQuirk;
 
   static uint32_t gInUnsafePluginCalls;
+
+  // The arrays can only be released when the plugin instance is destroyed,
+  // because the plugin, in in-process mode, might keep a reference to them.
+  uint32_t mCachedParamLength;
+  char **mCachedParamNames;
+  char **mCachedParamValues;
 };
 
 // On Android, we need to guard against plugin code leaking entries in the local
 // JNI ref table. See https://bugzilla.mozilla.org/show_bug.cgi?id=780831#c21
 #ifdef MOZ_WIDGET_ANDROID
   #define MAIN_THREAD_JNI_REF_GUARD mozilla::AutoLocalJNIFrame jniFrame
 #else
   #define MAIN_THREAD_JNI_REF_GUARD
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -34,30 +34,32 @@ using mozilla::DefaultXDisplay;
 #include "nsLayoutUtils.h"
 #include "nsIPluginWidget.h"
 #include "nsViewManager.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsIAppShell.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsIObjectLoadingContent.h"
+#include "nsObjectLoadingContent.h"
 #include "nsAttrName.h"
 #include "nsIFocusManager.h"
 #include "nsFocusManager.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDocShell.h"
 #include "ImageContainer.h"
 #include "nsIDOMHTMLCollection.h"
 #include "GLContext.h"
 #include "GLSharedHandleHelpers.h"
 #include "nsIContentInlines.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
+#include "mozilla/dom/HTMLObjectElementBinding.h"
 
 #include "nsContentCID.h"
 #include "nsWidgetsCID.h"
 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #ifdef XP_WIN
 #include <wtypes.h>
@@ -83,16 +85,17 @@ static nsPluginInstanceOwner* sFullScree
 
 using namespace mozilla::dom;
 
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
 #endif
 
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::layers;
 
 // special class for handeling DOM context menu events because for
 // some reason it starves other mouse events if implemented on the
 // same class
 class nsPluginDOMContextMenuListener : public nsIDOMEventListener
 {
   virtual ~nsPluginDOMContextMenuListener();
@@ -275,20 +278,16 @@ nsPluginInstanceOwner::nsPluginInstanceO
   mSentInitialTopLevelWindowEvent = false;
   mColorProfile = nullptr;
   mPluginPortChanged = false;
 #endif
   mContentFocused = false;
   mWidgetVisible = true;
   mPluginWindowVisible = false;
   mPluginDocumentActiveState = true;
-  mNumCachedAttrs = 0;
-  mNumCachedParams = 0;
-  mCachedAttrParamNames = nullptr;
-  mCachedAttrParamValues = nullptr;
   mLastMouseDownButtonType = -1;
 
 #ifdef XP_MACOSX
 #ifndef NP_NO_CARBON
   // We don't support Carbon, but it is still the default model for i386 NPAPI.
   mEventModel = NPEventModelCarbon;
 #else
   mEventModel = NPEventModelCocoa;
@@ -301,49 +300,25 @@ nsPluginInstanceOwner::nsPluginInstanceO
 #ifdef MOZ_WIDGET_ANDROID
   mFullScreen = false;
   mJavaView = nullptr;
 #endif
 }
 
 nsPluginInstanceOwner::~nsPluginInstanceOwner()
 {
-  int32_t cnt;
-
   if (mWaitingForPaint) {
     // We don't care when the event is dispatched as long as it's "soon",
     // since whoever needs it will be waiting for it.
     nsCOMPtr<nsIRunnable> event = new AsyncPaintWaitEvent(mContent, true);
     NS_DispatchToMainThread(event);
   }
 
   mObjectFrame = nullptr;
 
-  for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) {
-    if (mCachedAttrParamNames && mCachedAttrParamNames[cnt]) {
-      NS_Free(mCachedAttrParamNames[cnt]);
-      mCachedAttrParamNames[cnt] = nullptr;
-    }
-
-    if (mCachedAttrParamValues && mCachedAttrParamValues[cnt]) {
-      NS_Free(mCachedAttrParamValues[cnt]);
-      mCachedAttrParamValues[cnt] = nullptr;
-    }
-  }
-
-  if (mCachedAttrParamNames) {
-    NS_Free(mCachedAttrParamNames);
-    mCachedAttrParamNames = nullptr;
-  }
-
-  if (mCachedAttrParamValues) {
-    NS_Free(mCachedAttrParamValues);
-    mCachedAttrParamValues = nullptr;
-  }
-
   PLUG_DeletePluginNativeWindow(mPluginWindow);
   mPluginWindow = nullptr;
 
 #ifdef MOZ_WIDGET_ANDROID
   RemovePluginView();
 #endif
 
   if (mInstance) {
@@ -406,48 +381,23 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
     *aMode = NP_FULL;
   } else {
     *aMode = NP_EMBED;
   }
 
   return rv;
 }
 
-NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(uint16_t& n,
-                                                   const char*const*& names,
-                                                   const char*const*& values)
-{
-  nsresult rv = EnsureCachedAttrParamArrays();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  n = mNumCachedAttrs;
-  names  = (const char **)mCachedAttrParamNames;
-  values = (const char **)mCachedAttrParamValues;
-
-  return rv;
-}
-
-NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* *result)
+void nsPluginInstanceOwner::GetAttributes(nsTArray<MozPluginParameter>& attributes)
 {
-  NS_ENSURE_ARG_POINTER(name);
-  NS_ENSURE_ARG_POINTER(result);
-
-  nsresult rv = EnsureCachedAttrParamArrays();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *result = nullptr;
-
-  for (int i = 0; i < mNumCachedAttrs; i++) {
-    if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
-      *result = mCachedAttrParamValues[i];
-      return NS_OK;
-    }
-  }
-
-  return NS_ERROR_FAILURE;
+  nsCOMPtr<nsIObjectLoadingContent> content = do_QueryInterface(mContent);
+  nsObjectLoadingContent *loadingContent =
+    static_cast<nsObjectLoadingContent*>(content.get());
+
+  loadingContent->GetPluginAttributes(attributes);
 }
 
 NS_IMETHODIMP nsPluginInstanceOwner::GetDOMElement(nsIDOMElement* *result)
 {
   return CallQueryInterface(mContent, result);
 }
 
 nsresult nsPluginInstanceOwner::GetInstance(nsNPAPIPluginInstance **aInstance)
@@ -784,336 +734,23 @@ NS_IMETHODIMP nsPluginInstanceOwner::Get
   else if (atom == nsGkAtoms::embed)
     *result = nsPluginTagType_Embed;
   else if (atom == nsGkAtoms::object)
     *result = nsPluginTagType_Object;
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(uint16_t& n, const char*const*& names, const char*const*& values)
-{
-  nsresult rv = EnsureCachedAttrParamArrays();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  n = mNumCachedParams;
-  if (n) {
-    names  = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1);
-    values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1);
-  } else
-    names = values = nullptr;
-
-  return rv;
-}
-
-NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* *result)
-{
-  NS_ENSURE_ARG_POINTER(name);
-  NS_ENSURE_ARG_POINTER(result);
-
-  nsresult rv = EnsureCachedAttrParamArrays();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *result = nullptr;
-
-  for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) {
-    if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) {
-      *result = mCachedAttrParamValues[i];
-      return NS_OK;
-    }
-  }
-
-  return NS_ERROR_FAILURE;
-}
-
-
-// Cache the attributes and/or parameters of our tag into a single set
-// of arrays to be compatible with Netscape 4.x. The attributes go first,
-// followed by a PARAM/null and then any PARAM tags. Also, hold the
-// cached array around for the duration of the life of the instance
-// because Netscape 4.x did. See bug 111008.
-nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays()
+void nsPluginInstanceOwner::GetParameters(nsTArray<MozPluginParameter>& parameters)
 {
-  if (mCachedAttrParamValues)
-    return NS_OK;
-
-  NS_PRECONDITION(((mNumCachedAttrs + mNumCachedParams) == 0) &&
-                    !mCachedAttrParamNames,
-                  "re-cache of attrs/params not implemented! use the DOM "
-                    "node directy instead");
-
-  // Convert to a 16-bit count. Subtract 3 in case we add an extra
-  // "src", "wmode", or "codebase" entry below.
-  uint32_t cattrs = mContent->GetAttrCount();
-  if (cattrs < 0x0000FFFC) {
-    mNumCachedAttrs = static_cast<uint16_t>(cattrs);
-  } else {
-    mNumCachedAttrs = 0xFFFC;
-  }
-
-  // Check if we are java for special codebase handling
-  const char* mime = nullptr;
-  bool isJava = NS_SUCCEEDED(mInstance->GetMIMEType(&mime)) && mime &&
-                nsPluginHost::IsJavaMIMEType(mime);
-
-  // now, we need to find all the PARAM tags that are children of us
-  // however, be careful not to include any PARAMs that don't have us
-  // as a direct parent. For nested object (or applet) tags, be sure
-  // to only round up the param tags that coorespond with THIS
-  // instance. And also, weed out any bogus tags that may get in the
-  // way, see bug 39609. Then, with any param tag that meet our
-  // qualification, temporarly cache them in an nsCOMArray until
-  // we can figure out what size to make our fixed char* array.
-  nsCOMArray<nsIDOMElement> ourParams;
-
-  // Get all dependent PARAM tags, even if they are not direct children.
-  nsCOMPtr<nsIDOMElement> mydomElement = do_QueryInterface(mContent);
-  NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE);
-
-  // Making DOM method calls can cause our frame to go away.
-  nsCOMPtr<nsIPluginInstanceOwner> kungFuDeathGrip(this);
-
-  nsCOMPtr<nsIDOMHTMLCollection> allParams;
-  NS_NAMED_LITERAL_STRING(xhtml_ns, "http://www.w3.org/1999/xhtml");
-  mydomElement->GetElementsByTagNameNS(xhtml_ns, NS_LITERAL_STRING("param"),
-                                       getter_AddRefs(allParams));
-  if (allParams) {
-    uint32_t numAllParams;
-    allParams->GetLength(&numAllParams);
-    for (uint32_t i = 0; i < numAllParams; i++) {
-      nsCOMPtr<nsIDOMNode> pnode;
-      allParams->Item(i, getter_AddRefs(pnode));
-      nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(pnode);
-      if (domelement) {
-        // Ignore params without a name attribute.
-        nsAutoString name;
-        domelement->GetAttribute(NS_LITERAL_STRING("name"), name);
-        if (!name.IsEmpty()) {
-          // Find the first object or applet parent.
-          nsCOMPtr<nsIDOMNode> parent;
-          nsCOMPtr<nsIDOMHTMLObjectElement> domobject;
-          nsCOMPtr<nsIDOMHTMLAppletElement> domapplet;
-          pnode->GetParentNode(getter_AddRefs(parent));
-          while (!(domobject || domapplet) && parent) {
-            domobject = do_QueryInterface(parent);
-            domapplet = do_QueryInterface(parent);
-            nsCOMPtr<nsIDOMNode> temp;
-            parent->GetParentNode(getter_AddRefs(temp));
-            parent = temp;
-          }
-          if (domapplet || domobject) {
-            if (domapplet) {
-              parent = do_QueryInterface(domapplet);
-            }
-            else {
-              parent = do_QueryInterface(domobject);
-            }
-            nsCOMPtr<nsIDOMNode> mydomNode = do_QueryInterface(mydomElement);
-            if (parent == mydomNode) {
-              ourParams.AppendObject(domelement);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  // Convert to a 16-bit count.
-  uint32_t cparams = ourParams.Count();
-  if (cparams < 0x0000FFFF) {
-    mNumCachedParams = static_cast<uint16_t>(cparams);
-  } else {
-    mNumCachedParams = 0xFFFF;
-  }
-
-  uint16_t numRealAttrs = mNumCachedAttrs;
-
-  // Some plugins were never written to understand the "data" attribute of the OBJECT tag.
-  // Real and WMP will not play unless they find a "src" attribute, see bug 152334.
-  // Nav 4.x would simply replace the "data" with "src". Because some plugins correctly
-  // look for "data", lets instead copy the "data" attribute and add another entry
-  // to the bottom of the array if there isn't already a "src" specified.
-  nsAutoString data;
-  if (mContent->Tag() == nsGkAtoms::object &&
-      !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
-      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, data) &&
-      !data.IsEmpty()) {
-    mNumCachedAttrs++;
-  }
-
-  // "plugins.force.wmode" forces us to send a specific "wmode" parameter,
-  // used by flash to select a rendering mode. Common values include
-  // "opaque", "transparent", "windowed", "direct"
-  nsCString wmodeType;
-  nsAdoptingCString wmodePref = Preferences::GetCString("plugins.force.wmode");
-  if (!wmodePref.IsEmpty()) {
-    mNumCachedAttrs++;
-    wmodeType = wmodePref;
-  }
-#if defined(XP_WIN) || defined(XP_LINUX)
-  // Bug 923745 - Until we support windowed mode plugins in content processes,
-  // force flash to use a windowless rendering mode. This hack should go away
-  // when bug 923746 lands. (OS X plugins always use some native widgets, so
-  // unfortunately this does not help there)
-  else if (XRE_GetProcessType() == GeckoProcessType_Content) {
-    mNumCachedAttrs++;
-    wmodeType.AssignLiteral("transparent");
-  }
-#endif
-
-  // (Bug 738396) java has quirks in its codebase parsing, pass the
-  // absolute codebase URI as content sees it.
-  bool addCodebase = false;
-  nsAutoCString codebaseStr;
-  if (isJava) {
-    nsCOMPtr<nsIObjectLoadingContent> objlc = do_QueryInterface(mContent);
-    NS_ENSURE_TRUE(objlc, NS_ERROR_UNEXPECTED);
-    nsCOMPtr<nsIURI> codebaseURI;
-    nsresult rv = objlc->GetBaseURI(getter_AddRefs(codebaseURI));
-    NS_ENSURE_SUCCESS(rv, rv);
-    codebaseURI->GetSpec(codebaseStr);
-    if (!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::codebase)) {
-      mNumCachedAttrs++;
-      addCodebase = true;
-    }
-  }
-
-  mCachedAttrParamNames  = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
-  NS_ENSURE_TRUE(mCachedAttrParamNames,  NS_ERROR_OUT_OF_MEMORY);
-  mCachedAttrParamValues = (char**)NS_Alloc(sizeof(char*) * (mNumCachedAttrs + 1 + mNumCachedParams));
-  NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY);
-
-  // Some plugins (eg Flash, see bug 234675.) are actually sensitive to the
-  // attribute order.  So we want to make sure we give the plugin the
-  // attributes in the order they came in in the source, to be compatible with
-  // other browsers.  Now in HTML, the storage order is the reverse of the
-  // source order, while in XML and XHTML it's the same as the source order
-  // (see the AddAttributes functions in the HTML and XML content sinks).
-  int32_t start, end, increment;
-  if (mContent->IsHTML() &&
-      mContent->IsInHTMLDocument()) {
-    // HTML.  Walk attributes in reverse order.
-    start = numRealAttrs - 1;
-    end = -1;
-    increment = -1;
-  } else {
-    // XHTML or XML.  Walk attributes in forward order.
-    start = 0;
-    end = numRealAttrs;
-    increment = 1;
-  }
-
-  // Set to the next slot to fill in name and value cache arrays.
-  uint32_t nextAttrParamIndex = 0;
-
-  // Whether or not we force the wmode below while traversing
-  // the name/value pairs.
-  bool wmodeSet = false;
-
-  // Add attribute name/value pairs.
-  for (int32_t index = start; index != end; index += increment) {
-    const nsAttrName* attrName = mContent->GetAttrNameAt(index);
-    nsIAtom* atom = attrName->LocalName();
-    nsAutoString value;
-    mContent->GetAttr(attrName->NamespaceID(), atom, value);
-    nsAutoString name;
-    atom->ToString(name);
-
-    FixUpURLS(name, value);
-
-    mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
-    if (!wmodeType.IsEmpty() &&
-        0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "wmode")) {
-      mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
-
-      if (!wmodeSet) {
-        // We allocated space to add a wmode attr, but we don't need it now.
-        mNumCachedAttrs--;
-        wmodeSet = true;
-      }
-    } else if (isJava && 0 == PL_strcasecmp(mCachedAttrParamNames[nextAttrParamIndex], "codebase")) {
-      mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
-    } else {
-      mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
-    }
-    nextAttrParamIndex++;
-  }
-
-  // Potentially add CODEBASE attribute
-  if (addCodebase) {
-    mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("codebase"));
-    mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(codebaseStr));
-    nextAttrParamIndex++;
-  }
-
-  // Potentially add WMODE attribute.
-  if (!wmodeType.IsEmpty() && !wmodeSet) {
-    mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("wmode"));
-    mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_ConvertUTF8toUTF16(wmodeType));
-    nextAttrParamIndex++;
-  }
-
-  // Potentially add SRC attribute.
-  if (!data.IsEmpty()) {
-    mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("SRC"));
-    mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(data);
-    nextAttrParamIndex++;
-  }
-
-  // Add PARAM and null separator.
-  mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING("PARAM"));
-#ifdef MOZ_WIDGET_ANDROID
-  // Flash expects an empty string on android
-  mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(NS_LITERAL_STRING(""));
-#else
-  mCachedAttrParamValues[nextAttrParamIndex] = nullptr;
-#endif
-  nextAttrParamIndex++;
-
-  // Add PARAM name/value pairs.
-
-  // We may decrement mNumCachedParams below
-  uint16_t totalParams = mNumCachedParams;
-  for (uint16_t i = 0; i < totalParams; i++) {
-    nsIDOMElement* param = ourParams.ObjectAt(i);
-    if (!param) {
-      continue;
-    }
-
-    nsAutoString name;
-    nsAutoString value;
-    param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above
-    param->GetAttribute(NS_LITERAL_STRING("value"), value);
-
-    FixUpURLS(name, value);
-
-    /*
-     * According to the HTML 4.01 spec, at
-     * http://www.w3.org/TR/html4/types.html#type-cdata
-     * ''User agents may ignore leading and trailing
-     * white space in CDATA attribute values (e.g., "
-     * myval " may be interpreted as "myval"). Authors
-     * should not declare attribute values with
-     * leading or trailing white space.''
-     * However, do not trim consecutive spaces as in bug 122119
-     */
-    name.Trim(" \n\r\t\b", true, true, false);
-    value.Trim(" \n\r\t\b", true, true, false);
-    if (isJava && name.EqualsIgnoreCase("codebase")) {
-      // We inserted normalized codebase above, don't include other versions in
-      // params
-      mNumCachedParams--;
-      continue;
-    }
-    mCachedAttrParamNames [nextAttrParamIndex] = ToNewUTF8String(name);
-    mCachedAttrParamValues[nextAttrParamIndex] = ToNewUTF8String(value);
-    nextAttrParamIndex++;
-  }
-
-  return NS_OK;
+  nsCOMPtr<nsIObjectLoadingContent> content = do_QueryInterface(mContent);
+  nsObjectLoadingContent *loadingContent =
+    static_cast<nsObjectLoadingContent*>(content.get());
+
+  loadingContent->GetPluginParameters(parameters);
 }
 
 #ifdef XP_MACOSX
 
 static void InitializeNPCocoaEvent(NPCocoaEvent* event)
 {
   memset(event, 0, sizeof(NPCocoaEvent));
 }
@@ -3163,29 +2800,16 @@ void nsPluginInstanceOwner::SetFrame(nsO
   }
 }
 
 nsObjectFrame* nsPluginInstanceOwner::GetFrame()
 {
   return mObjectFrame;
 }
 
-// Little helper function to resolve relative URL in
-// |value| for certain inputs of |name|
-void nsPluginInstanceOwner::FixUpURLS(const nsString &name, nsAString &value)
-{
-  if (name.LowerCaseEqualsLiteral("pluginspage")) {
-    nsCOMPtr<nsIURI> baseURI = GetBaseURI();
-    nsAutoString newURL;
-    NS_MakeAbsoluteURI(newURL, value, baseURI);
-    if (!newURL.IsEmpty())
-      value = newURL;
-  }
-}
-
 NS_IMETHODIMP nsPluginInstanceOwner::PrivateModeChanged(bool aEnabled)
 {
   return mInstance ? mInstance->PrivateModeStateChanged(aEnabled) : NS_OK;
 }
 
 already_AddRefed<nsIURI> nsPluginInstanceOwner::GetBaseURI() const
 {
   if (!mContent) {
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -24,16 +24,22 @@
 #endif
 
 class nsIInputStream;
 struct nsIntRect;
 class nsPluginDOMContextMenuListener;
 class nsObjectFrame;
 class nsDisplayListBuilder;
 
+namespace mozilla {
+namespace dom {
+struct MozPluginParameter;
+}
+}
+
 #ifdef MOZ_X11
 class gfxXlibSurface;
 #ifdef MOZ_WIDGET_QT
 #include "gfxQtNativeRenderer.h"
 #else
 #include "gfxXlibNativeRenderer.h"
 #endif
 #endif
@@ -67,60 +73,18 @@ public:
   virtual void SetCurrentAsyncSurface(NPAsyncSurface *surface, NPRect *changed) MOZ_OVERRIDE;
 
   /**
    * Get the type of the HTML tag that was used ot instantiate this
    * plugin.  Currently supported tags are EMBED, OBJECT and APPLET.
    */
   NS_IMETHOD GetTagType(nsPluginTagType *aResult);
 
-  /**
-   * Get a ptr to the paired list of parameter names and values,
-   * returns the length of the array.
-   *
-   * Each name or value is a null-terminated string.
-   */
-  NS_IMETHOD GetParameters(uint16_t& aCount,
-                           const char*const*& aNames,
-                           const char*const*& aValues);
-
-  /**
-   * Get the value for the named parameter.  Returns null
-   * if the parameter was not set.
-   *
-   * @param aName   - name of the parameter
-   * @param aResult - parameter value
-   * @result        - NS_OK if this operation was successful
-   */
-  NS_IMETHOD GetParameter(const char* aName, const char* *aResult);
-
-  /**
-   * QueryInterface on nsIPluginInstancePeer to get this.
-   *
-   * (Corresponds to NPP_New's argc, argn, and argv arguments.)
-   * Get a ptr to the paired list of attribute names and values,
-   * returns the length of the array.
-   *
-   * Each name or value is a null-terminated string.
-   */
-  NS_IMETHOD GetAttributes(uint16_t& aCount,
-                           const char*const*& aNames,
-                           const char*const*& aValues);
-
-
-  /**
-   * Gets the value for the named attribute.
-   *
-   * @param aName   - the name of the attribute to find
-   * @param aResult - the resulting attribute
-   * @result - NS_OK if this operation was successful, NS_ERROR_FAILURE if
-   * this operation failed. result is set to NULL if the attribute is not found
-   * else to the found value.
-   */
-  NS_IMETHOD GetAttribute(const char* aName, const char* *aResult);
+  void GetParameters(nsTArray<mozilla::dom::MozPluginParameter>& parameters);
+  void GetAttributes(nsTArray<mozilla::dom::MozPluginParameter>& attributes);
 
   /**
    * Returns the DOM element corresponding to the tag which references
    * this plugin in the document.
    *
    * @param aDOMElement - resulting DOM element
    * @result - NS_OK if this operation was successful
    */
@@ -295,18 +259,17 @@ private:
 
   // return FALSE if LayerSurface dirty (newly created and don't have valid plugin content yet)
   bool IsUpToDate()
   {
     nsIntSize size;
     return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
     size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
   }
-  
-  void FixUpURLS(const nsString &name, nsAString &value);
+
 #ifdef MOZ_WIDGET_ANDROID
   mozilla::LayoutDeviceRect GetPluginRect();
   bool AddPluginView(const mozilla::LayoutDeviceRect& aRect = mozilla::LayoutDeviceRect(0, 0, 0, 0));
   void RemovePluginView();
 
   bool mFullScreen;
   void* mJavaView;
 #endif 
@@ -342,21 +305,16 @@ private:
 #endif
 #ifdef MOZ_X11
   // Used with windowless plugins only, initialized in CreateWidget().
   bool                        mFlash10Quirks;
 #endif
   bool                        mPluginWindowVisible;
   bool                        mPluginDocumentActiveState;
 
-  uint16_t          mNumCachedAttrs;
-  uint16_t          mNumCachedParams;
-  char              **mCachedAttrParamNames;
-  char              **mCachedAttrParamValues;
-  
 #ifdef XP_MACOSX
   NPEventModel mEventModel;
   // This is a hack! UseAsyncRendering() can incorrectly return false
   // when we don't have an object frame (possible as of bug 90268).
   // We hack around this by always returning true if we've ever
   // returned true.
   bool mUseAsyncRendering;
 #endif
@@ -365,19 +323,17 @@ private:
   nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
   
   nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
   nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
                                  bool aAllowPropagate = false);
   nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
 
   int mLastMouseDownButtonType;
-  
-  nsresult EnsureCachedAttrParamArrays();
-  
+
 #ifdef MOZ_X11
   class Renderer
 #if defined(MOZ_WIDGET_QT)
   : public gfxQtNativeRenderer
 #else
   : public gfxXlibNativeRenderer
 #endif
   {
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -150,16 +150,23 @@ interface MozObjectLoadingContent {
   /**
    * Gets the content type that corresponds to the give MIME type.  See the
    * constants above for the list of possible values.  If nothing else fits,
    * TYPE_NULL will be returned.
    */
   [ChromeOnly]
   unsigned long getContentTypeForMIMEType(DOMString aMimeType);
 
+
+  [ChromeOnly]
+  sequence<MozPluginParameter> getPluginAttributes();
+
+  [ChromeOnly]
+  sequence<MozPluginParameter> getPluginParameters();
+
   /**
    * This method will play a plugin that has been stopped by the
    * click-to-play plugins or play-preview features.
    */
   [ChromeOnly, Throws]
   void playPlugin();
 
   /**
@@ -201,11 +208,20 @@ interface MozObjectLoadingContent {
 
   /**
    * This method will disable the play-preview plugin state.
    */
   [ChromeOnly, Throws]
   void cancelPlayPreview();
 };
 
+/**
+ * Name:Value pair type used for passing parameters to NPAPI or javascript
+ * plugins.
+ */
+dictionary MozPluginParameter {
+  DOMString name = "";
+  DOMString value = "";
+};
+
 HTMLObjectElement implements MozImageLoadingContent;
 HTMLObjectElement implements MozFrameLoaderOwner;
 HTMLObjectElement implements MozObjectLoadingContent;