From e1a3dcea6d38ffab1fcdceabf93f7775f1f7f048 Mon Sep 17 00:00:00 2001 From: "peterlubczynski%netscape.com" Date: Tue, 11 Dec 2001 15:53:07 +0000 Subject: [PATCH] Fixing the way we pass attributes and parameters to plugins, bug 103940 r=av sr=beard --- layout/generic/nsObjectFrame.cpp | 521 +++++++----------- layout/html/base/src/nsObjectFrame.cpp | 521 +++++++----------- .../plugin/base/src/ns4xPluginInstance.cpp | 47 +- 3 files changed, 440 insertions(+), 649 deletions(-) diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index b6f0954977a8..d265a4412856 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -73,6 +73,9 @@ #include "nsIDocShellTreeOwner.h" #include "nsIWebBrowserChrome.h" #include "nsIDOMElement.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsIDOMHTMLAppletElement.h" #include "nsContentPolicyUtils.h" #include "nsIDOMWindow.h" #include "nsIDOMMouseListener.h" @@ -283,12 +286,6 @@ private: nsPluginWindow mPluginWindow; nsIPluginInstance *mInstance; nsObjectFrame *mOwner; - PRInt32 mNumAttrs; - char **mAttrNames; - char **mAttrVals; - PRInt32 mNumParams; - char **mParamNames; - char **mParamVals; char *mDocumentBase; char *mTagText; nsIWidget *mWidget; @@ -296,10 +293,16 @@ private: nsCOMPtr mPluginTimer; nsIPluginHost *mPluginHost; PRPackedBool mContentFocused; + PRUint16 mNumCachedAttrs; + PRUint16 mNumCachedParams; + char **mCachedAttrParamNames; + char **mCachedAttrParamValues; nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent); nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent); nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent); + + nsresult EnsureCachedAttrParamArrays(); }; // Mac specific code to fix up port position and clip during paint @@ -1929,18 +1932,16 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() memset(&mPluginWindow, 0, sizeof(mPluginWindow)); mInstance = nsnull; mOwner = nsnull; - mNumAttrs = 0; - mAttrNames = nsnull; - mAttrVals = nsnull; mWidget = nsnull; mContext = nsnull; - mNumParams = 0; - mParamNames = nsnull; - mParamVals = nsnull; mDocumentBase = nsnull; mTagText = nsnull; mPluginHost = nsnull; mContentFocused = PR_FALSE; + mNumCachedAttrs = 0; + mNumCachedParams = 0; + mCachedAttrParamNames = nsnull; + mCachedAttrParamValues = nsnull; } nsPluginInstanceOwner::~nsPluginInstanceOwner() @@ -1956,68 +1957,34 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner() NS_IF_RELEASE(mPluginHost); mOwner = nsnull; - for (cnt = 0; cnt < mNumAttrs; cnt++) - { - if ((nsnull != mAttrNames) && (nsnull != mAttrNames[cnt])) - { - PR_Free(mAttrNames[cnt]); - mAttrNames[cnt] = nsnull; + for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) { + if ((nsnull != mCachedAttrParamNames) && (nsnull != mCachedAttrParamNames[cnt])) { + PR_Free(mCachedAttrParamNames[cnt]); + mCachedAttrParamNames[cnt] = nsnull; } - if ((nsnull != mAttrVals) && (nsnull != mAttrVals[cnt])) - { - PR_Free(mAttrVals[cnt]); - mAttrVals[cnt] = nsnull; + if ((nsnull != mCachedAttrParamValues) && (nsnull != mCachedAttrParamValues[cnt])) { + PR_Free(mCachedAttrParamValues[cnt]); + mCachedAttrParamValues[cnt] = nsnull; } } - if (nsnull != mAttrNames) - { - PR_Free(mAttrNames); - mAttrNames = nsnull; + if (nsnull != mCachedAttrParamNames) { + PR_Free(mCachedAttrParamNames); + mCachedAttrParamNames = nsnull; } - if (nsnull != mAttrVals) - { - PR_Free(mAttrVals); - mAttrVals = nsnull; + if (nsnull != mCachedAttrParamValues) { + PR_Free(mCachedAttrParamValues); + mCachedAttrParamValues = nsnull; } - for (cnt = 0; cnt < mNumParams; cnt++) - { - if ((nsnull != mParamNames) && (nsnull != mParamNames[cnt])) - { - PR_Free(mParamNames[cnt]); - mParamNames[cnt] = nsnull; - } - - if ((nsnull != mParamVals) && (nsnull != mParamVals[cnt])) - { - PR_Free(mParamVals[cnt]); - mParamVals[cnt] = nsnull; - } - } - - if (nsnull != mParamNames) - { - PR_Free(mParamNames); - mParamNames = nsnull; - } - - if (nsnull != mParamVals) - { - PR_Free(mParamVals); - mParamVals = nsnull; - } - - if (nsnull != mDocumentBase) - { + if (nsnull != mDocumentBase) { nsCRT::free(mDocumentBase); mDocumentBase = nsnull; } - if (nsnull != mTagText) - { + if (nsnull != mTagText) { nsCRT::free(mTagText); mTagText = nsnull; } @@ -2063,90 +2030,12 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n, const char*const*& names, const char*const*& values) { - nsresult rv; - nsIContent* iContent; + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if ((nsnull == mAttrNames) && (nsnull != mOwner)) { - rv = mOwner->GetContent(&iContent); - - if (NS_SUCCEEDED(rv)) { - PRInt32 count; - - if (NS_SUCCEEDED(iContent->GetAttrCount(count))) { - PRInt32 index; - mAttrNames = (char **)PR_Calloc(sizeof(char *) * count, 1); - mAttrVals = (char **)PR_Calloc(sizeof(char *) * count, 1); - mNumAttrs = 0; - - if ((nsnull != mAttrNames) && (nsnull != mAttrVals)) { - for (index = 0; index < count; index++) { - PRInt32 nameSpaceID; - nsCOMPtr atom; - nsCOMPtr prefix; - iContent->GetAttrNameAt(index, nameSpaceID, - *getter_AddRefs(atom), - *getter_AddRefs(prefix)); - nsAutoString value; - if (NS_CONTENT_ATTR_HAS_VALUE == - iContent->GetAttr(nameSpaceID, atom, value)) { - nsAutoString name; - atom->ToString(name); - -/* Changing to ToNewUTF8String addressing 17169, 39789 - - mAttrNames[mNumAttrs] = (char *)PR_Malloc(name.Length() + 1); - mAttrVals[mNumAttrs] = (char *)PR_Malloc(value.Length() + 1); - - if ((nsnull != mAttrNames[mNumAttrs]) && - (nsnull != mAttrVals[mNumAttrs])) - { - name.ToCString(mAttrNames[mNumAttrs], name.Length() + 1); - value.ToCString(mAttrVals[mNumAttrs], value.Length() + 1); - - mNumAttrs++; - } - else - { - if (nsnull != mAttrNames[mNumAttrs]) - { - PR_Free(mAttrNames[mNumAttrs]); - mAttrNames[mNumAttrs] = nsnull; - } - if (nsnull != mAttrVals[mNumAttrs]) - { - PR_Free(mAttrVals[mNumAttrs]); - mAttrVals[mNumAttrs] = nsnull; - } - } -*/ - mAttrNames[mNumAttrs] = ToNewUTF8String(name); - mAttrVals[mNumAttrs] = ToNewUTF8String(value); - mNumAttrs++; - } - } - } - else { - rv = NS_ERROR_OUT_OF_MEMORY; - if (nsnull != mAttrVals) { - PR_Free(mAttrVals); - mAttrVals = nsnull; - } - if (nsnull != mAttrNames) { - PR_Free(mAttrNames); - mAttrNames = nsnull; - } - } - } - NS_RELEASE(iContent); - } - } - else { - rv = NS_OK; - } - - n = mNumAttrs; - names = (const char **)mAttrNames; - values = (const char **)mAttrVals; + n = mNumCachedAttrs; + names = (const char **)mCachedAttrParamNames; + values = (const char **)mCachedAttrParamValues; return rv; } @@ -2155,18 +2044,15 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* { NS_ENSURE_ARG_POINTER(name); NS_ENSURE_ARG_POINTER(result); - if (nsnull == mAttrNames) { - PRUint16 numattrs; - const char * const *names, * const *vals; + + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - GetAttributes(numattrs, names, vals); - } + *result = nsnull; - *result = NULL; - - for (int i = 0; i < mNumAttrs; i++) { - if (0 == PL_strcasecmp(mAttrNames[i], name)) { - *result = mAttrVals[i]; + for (int i = 0; i < mNumCachedAttrs; i++) { + if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { + *result = mCachedAttrParamValues[i]; return NS_OK; } } @@ -2527,148 +2413,16 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result) NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values) { - nsresult rv = NS_ERROR_FAILURE; + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if ((nsnull == mParamNames) && (nsnull != mOwner)) - { - nsIContent *cont; + // make sure we have at least one param tag because embed's don't have any + if (!mNumCachedParams) + return NS_ERROR_FAILURE; - mOwner->GetContent(&cont); - - if (nsnull != cont) - { - PRBool haskids = PR_FALSE; - - cont->CanContainChildren(haskids); - - if (PR_TRUE == haskids) - { - PRInt32 numkids, idx, numparams = 0; - - cont->ChildCount(numkids); - - //first pass, count number of param tags... - - for (idx = 0; idx < numkids; idx++) - { - nsIContent *kid; - - cont->ChildAt(idx, kid); - - if (nsnull != kid) - { - nsIAtom *atom; - - kid->GetTag(atom); - - if (nsnull != atom) - { - if (atom == nsHTMLAtoms::param) - numparams++; - - NS_RELEASE(atom); - } - - NS_RELEASE(kid); - } - } - - if (numparams > 0) - { - //now we need to create arrays - //representing the parameter name/value pairs... - - mParamNames = (char **)PR_Calloc(sizeof(char *) * numparams, 1); - mParamVals = (char **)PR_Calloc(sizeof(char *) * numparams, 1); - - if ((nsnull != mParamNames) && (nsnull != mParamVals)) - { - for (idx = 0; idx < numkids; idx++) - { - nsIContent *kid; - - cont->ChildAt(idx, kid); - - if (nsnull != kid) - { - nsIAtom *atom; - - kid->GetTag(atom); - - if (nsnull != atom) - { - if (atom == nsHTMLAtoms::param) - { - nsAutoString val, name; - - //add param to list... - - if ((NS_CONTENT_ATTR_HAS_VALUE == kid->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::name, name)) && - (NS_CONTENT_ATTR_HAS_VALUE == kid->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::value, val))) - { - -/* Changing to ToNewUTF8String addressing 17169, 39789 - - mParamNames[mNumParams] = (char *)PR_Malloc(name.Length() + 1); - mParamVals[mNumParams] = (char *)PR_Malloc(val.Length() + 1); - - if ((nsnull != mParamNames[mNumParams]) && - (nsnull != mParamVals[mNumParams])) - { - name.ToCString(mParamNames[mNumParams], name.Length() + 1); - val.ToCString(mParamVals[mNumParams], val.Length() + 1); - - mNumParams++; - } - else - { - if (nsnull != mParamNames[mNumParams]) - { - PR_Free(mParamNames[mNumParams]); - mParamNames[mNumParams] = nsnull; - } - - if (nsnull != mParamVals[mNumParams]) - { - PR_Free(mParamVals[mNumParams]); - mParamVals[mNumParams] = nsnull; - } - } -*/ - /* 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.'' - */ - name.CompressWhitespace(); - val.CompressWhitespace(); - mParamNames[mNumParams] = ToNewUTF8String(name); - mParamVals[mNumParams] = ToNewUTF8String(val); - mNumParams++; - } - } - - NS_RELEASE(atom); - } - } - - NS_RELEASE(kid); - } - } - } - } - - rv = NS_OK; - NS_RELEASE(cont); - } - } - - n = mNumParams; - names = (const char **)mParamNames; - values = (const char **)mParamVals; + n = mNumCachedParams; + names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1); + values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1); return rv; } @@ -2677,32 +2431,20 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* { NS_ENSURE_ARG_POINTER(name); NS_ENSURE_ARG_POINTER(result); - nsresult rv; - PRInt32 count; + + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if (nsnull == mParamNames) - { - PRUint16 numattrs; - const char * const *names, * const *vals; + *result = nsnull; - rv = GetParameters(numattrs, names, vals); - } - - for (count = 0; count < mNumParams; count++) - { - if (0 == PL_strcasecmp(mParamNames[count], name)) - { - *result = mParamVals[count]; - break; + for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) { + if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { + *result = mCachedAttrParamValues[i]; + return NS_OK; } } - if (count >= mNumParams) { - *result = ""; - rv = NS_ERROR_FAILURE; - } - - return rv; + return NS_ERROR_FAILURE; } NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result) @@ -3000,6 +2742,155 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetMayScript(PRBool *result) return NS_OK; } + +// Cache the attributes and/or parameters of our tag into a single set of arrays +// to be compatible with 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 4.x did. See bug 111008. +nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() +{ + if (mCachedAttrParamValues) + return NS_OK; + + NS_PRECONDITION((((mNumCachedAttrs + mNumCachedParams) == 0) && !mCachedAttrParamNames), + "re-cache of attrs/params not implemented! use the DOM node directy instead"); + NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER); + + // first, we need to find out how much we need to allocate for our arrays + // count up attributes + mNumCachedAttrs = 0; + nsCOMPtr content; + nsresult rv = mOwner->GetContent(getter_AddRefs(content)); + NS_ENSURE_TRUE(content, rv); + rv = content->GetAttrCount((PRInt32&)mNumCachedAttrs); // signed 32 bits to unsigned 16 bits conversion + NS_ENSURE_SUCCESS(rv, rv); + + // now, we need to find all the PARAM tags that are children of us + // however, be carefull 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 nsISupportsArray until we can figure out + // what size to make our fixed char* array. + mNumCachedParams = 0; + nsCOMPtr ourParams; + rv = NS_NewISupportsArray(getter_AddRefs(ourParams)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr mydomNode = do_QueryInterface(content); + NS_ENSURE_TRUE(mydomNode, NS_ERROR_NO_INTERFACE); + + // use the DOM to get us ALL our dependant PARAM tags, even if not ours + nsCOMPtr mydomElement = do_QueryInterface(mydomNode); + NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE); + nsCOMPtr allParams; + mydomElement->GetElementsByTagName(NS_LITERAL_STRING("PARAM"), getter_AddRefs(allParams)); + if (allParams) { + PRUint32 numAllParams; + allParams->GetLength(&numAllParams); + // loop through every so called dependant PARAM tag to check if it "belongs" to us + for (PRUint32 i = 0; i < numAllParams; i++) { + nsCOMPtr pnode; + allParams->Item(i, getter_AddRefs(pnode)); + if (pnode) { + nsCOMPtr domelement = do_QueryInterface(pnode); + if (domelement) { + // let's NOT count up param tags that don't have a name attribute + nsAutoString name; + domelement->GetAttribute(NS_LITERAL_STRING("name"), name); + if (name.Length() > 0) { + nsCOMPtr parent; + nsCOMPtr domobject; + nsCOMPtr domapplet; + pnode->GetParentNode(getter_AddRefs(parent)); + // walk up the parents of this PARAM until we find an object (or applet) tag + while (!(domobject || domapplet) && parent) { + domobject = do_QueryInterface(parent); + domapplet = do_QueryInterface(parent); + nsCOMPtr temp; + parent->GetParentNode(getter_AddRefs(temp)); + parent = temp; + } + if (domapplet || domobject) { + parent = domapplet ? do_QueryInterface(domapplet) : do_QueryInterface(domobject); + // now check to see if this PARAM's parent is us. if so, cache it for later + if (parent.get() == mydomNode.get()) { + nsCOMPtr sup = do_QueryInterface(pnode); + NS_ASSERTION(sup, "lame! DOM node does doesn't QI to nsISupports"); + ourParams->AppendElement(sup); + } + } + } + } + } + } + } + ourParams->Count((PRUint32*)&mNumCachedParams); // unsigned 32 bits to unsigned 16 bits conversion + + + + // now lets make the arrays + mCachedAttrParamNames = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1); + NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY); + mCachedAttrParamValues = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1); + NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY); + + // let's fill in our attributes + PRInt16 c = 0; + for (PRInt16 index = 0; index < mNumCachedAttrs; index++) { + PRInt32 nameSpaceID; + nsCOMPtr atom; + nsCOMPtr prefix; + content->GetAttrNameAt(index, nameSpaceID, + *getter_AddRefs(atom), + *getter_AddRefs(prefix)); + nsAutoString value; + if (NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(nameSpaceID, atom, value)) { + nsAutoString name; + atom->ToString(name); + mCachedAttrParamNames [c] = ToNewUTF8String(name); + mCachedAttrParamValues[c] = ToNewUTF8String(value); + c++; + } + } + + // add our PARAM and null seperator + mCachedAttrParamNames [mNumCachedAttrs + 1] = "PARAM"; + mCachedAttrParamValues[mNumCachedAttrs + 1] = nsnull; + + // now fill in the PARAM name/value pairs from the cached DOM nodes + c = 0; + for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) { + nsCOMPtr sup = ourParams->ElementAt(idx); + if (sup) { + nsCOMPtr param = do_QueryInterface(sup); + if (param) { + nsAutoString name; + nsAutoString value; + param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above + param->GetAttribute(NS_LITERAL_STRING("value"), 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.'' + */ + name.CompressWhitespace(); // XXX right function? + value.CompressWhitespace(); + mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name); + mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value); + c++; // rules! + } + } + } + + return NS_OK; +} + + // Here's where we forward events to plugins. #ifdef XP_MAC diff --git a/layout/html/base/src/nsObjectFrame.cpp b/layout/html/base/src/nsObjectFrame.cpp index b6f0954977a8..d265a4412856 100644 --- a/layout/html/base/src/nsObjectFrame.cpp +++ b/layout/html/base/src/nsObjectFrame.cpp @@ -73,6 +73,9 @@ #include "nsIDocShellTreeOwner.h" #include "nsIWebBrowserChrome.h" #include "nsIDOMElement.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsIDOMHTMLAppletElement.h" #include "nsContentPolicyUtils.h" #include "nsIDOMWindow.h" #include "nsIDOMMouseListener.h" @@ -283,12 +286,6 @@ private: nsPluginWindow mPluginWindow; nsIPluginInstance *mInstance; nsObjectFrame *mOwner; - PRInt32 mNumAttrs; - char **mAttrNames; - char **mAttrVals; - PRInt32 mNumParams; - char **mParamNames; - char **mParamVals; char *mDocumentBase; char *mTagText; nsIWidget *mWidget; @@ -296,10 +293,16 @@ private: nsCOMPtr mPluginTimer; nsIPluginHost *mPluginHost; PRPackedBool mContentFocused; + PRUint16 mNumCachedAttrs; + PRUint16 mNumCachedParams; + char **mCachedAttrParamNames; + char **mCachedAttrParamValues; nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent); nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent); nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent); + + nsresult EnsureCachedAttrParamArrays(); }; // Mac specific code to fix up port position and clip during paint @@ -1929,18 +1932,16 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() memset(&mPluginWindow, 0, sizeof(mPluginWindow)); mInstance = nsnull; mOwner = nsnull; - mNumAttrs = 0; - mAttrNames = nsnull; - mAttrVals = nsnull; mWidget = nsnull; mContext = nsnull; - mNumParams = 0; - mParamNames = nsnull; - mParamVals = nsnull; mDocumentBase = nsnull; mTagText = nsnull; mPluginHost = nsnull; mContentFocused = PR_FALSE; + mNumCachedAttrs = 0; + mNumCachedParams = 0; + mCachedAttrParamNames = nsnull; + mCachedAttrParamValues = nsnull; } nsPluginInstanceOwner::~nsPluginInstanceOwner() @@ -1956,68 +1957,34 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner() NS_IF_RELEASE(mPluginHost); mOwner = nsnull; - for (cnt = 0; cnt < mNumAttrs; cnt++) - { - if ((nsnull != mAttrNames) && (nsnull != mAttrNames[cnt])) - { - PR_Free(mAttrNames[cnt]); - mAttrNames[cnt] = nsnull; + for (cnt = 0; cnt < (mNumCachedAttrs + 1 + mNumCachedParams); cnt++) { + if ((nsnull != mCachedAttrParamNames) && (nsnull != mCachedAttrParamNames[cnt])) { + PR_Free(mCachedAttrParamNames[cnt]); + mCachedAttrParamNames[cnt] = nsnull; } - if ((nsnull != mAttrVals) && (nsnull != mAttrVals[cnt])) - { - PR_Free(mAttrVals[cnt]); - mAttrVals[cnt] = nsnull; + if ((nsnull != mCachedAttrParamValues) && (nsnull != mCachedAttrParamValues[cnt])) { + PR_Free(mCachedAttrParamValues[cnt]); + mCachedAttrParamValues[cnt] = nsnull; } } - if (nsnull != mAttrNames) - { - PR_Free(mAttrNames); - mAttrNames = nsnull; + if (nsnull != mCachedAttrParamNames) { + PR_Free(mCachedAttrParamNames); + mCachedAttrParamNames = nsnull; } - if (nsnull != mAttrVals) - { - PR_Free(mAttrVals); - mAttrVals = nsnull; + if (nsnull != mCachedAttrParamValues) { + PR_Free(mCachedAttrParamValues); + mCachedAttrParamValues = nsnull; } - for (cnt = 0; cnt < mNumParams; cnt++) - { - if ((nsnull != mParamNames) && (nsnull != mParamNames[cnt])) - { - PR_Free(mParamNames[cnt]); - mParamNames[cnt] = nsnull; - } - - if ((nsnull != mParamVals) && (nsnull != mParamVals[cnt])) - { - PR_Free(mParamVals[cnt]); - mParamVals[cnt] = nsnull; - } - } - - if (nsnull != mParamNames) - { - PR_Free(mParamNames); - mParamNames = nsnull; - } - - if (nsnull != mParamVals) - { - PR_Free(mParamVals); - mParamVals = nsnull; - } - - if (nsnull != mDocumentBase) - { + if (nsnull != mDocumentBase) { nsCRT::free(mDocumentBase); mDocumentBase = nsnull; } - if (nsnull != mTagText) - { + if (nsnull != mTagText) { nsCRT::free(mTagText); mTagText = nsnull; } @@ -2063,90 +2030,12 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetAttributes(PRUint16& n, const char*const*& names, const char*const*& values) { - nsresult rv; - nsIContent* iContent; + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if ((nsnull == mAttrNames) && (nsnull != mOwner)) { - rv = mOwner->GetContent(&iContent); - - if (NS_SUCCEEDED(rv)) { - PRInt32 count; - - if (NS_SUCCEEDED(iContent->GetAttrCount(count))) { - PRInt32 index; - mAttrNames = (char **)PR_Calloc(sizeof(char *) * count, 1); - mAttrVals = (char **)PR_Calloc(sizeof(char *) * count, 1); - mNumAttrs = 0; - - if ((nsnull != mAttrNames) && (nsnull != mAttrVals)) { - for (index = 0; index < count; index++) { - PRInt32 nameSpaceID; - nsCOMPtr atom; - nsCOMPtr prefix; - iContent->GetAttrNameAt(index, nameSpaceID, - *getter_AddRefs(atom), - *getter_AddRefs(prefix)); - nsAutoString value; - if (NS_CONTENT_ATTR_HAS_VALUE == - iContent->GetAttr(nameSpaceID, atom, value)) { - nsAutoString name; - atom->ToString(name); - -/* Changing to ToNewUTF8String addressing 17169, 39789 - - mAttrNames[mNumAttrs] = (char *)PR_Malloc(name.Length() + 1); - mAttrVals[mNumAttrs] = (char *)PR_Malloc(value.Length() + 1); - - if ((nsnull != mAttrNames[mNumAttrs]) && - (nsnull != mAttrVals[mNumAttrs])) - { - name.ToCString(mAttrNames[mNumAttrs], name.Length() + 1); - value.ToCString(mAttrVals[mNumAttrs], value.Length() + 1); - - mNumAttrs++; - } - else - { - if (nsnull != mAttrNames[mNumAttrs]) - { - PR_Free(mAttrNames[mNumAttrs]); - mAttrNames[mNumAttrs] = nsnull; - } - if (nsnull != mAttrVals[mNumAttrs]) - { - PR_Free(mAttrVals[mNumAttrs]); - mAttrVals[mNumAttrs] = nsnull; - } - } -*/ - mAttrNames[mNumAttrs] = ToNewUTF8String(name); - mAttrVals[mNumAttrs] = ToNewUTF8String(value); - mNumAttrs++; - } - } - } - else { - rv = NS_ERROR_OUT_OF_MEMORY; - if (nsnull != mAttrVals) { - PR_Free(mAttrVals); - mAttrVals = nsnull; - } - if (nsnull != mAttrNames) { - PR_Free(mAttrNames); - mAttrNames = nsnull; - } - } - } - NS_RELEASE(iContent); - } - } - else { - rv = NS_OK; - } - - n = mNumAttrs; - names = (const char **)mAttrNames; - values = (const char **)mAttrVals; + n = mNumCachedAttrs; + names = (const char **)mCachedAttrParamNames; + values = (const char **)mCachedAttrParamValues; return rv; } @@ -2155,18 +2044,15 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetAttribute(const char* name, const char* { NS_ENSURE_ARG_POINTER(name); NS_ENSURE_ARG_POINTER(result); - if (nsnull == mAttrNames) { - PRUint16 numattrs; - const char * const *names, * const *vals; + + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - GetAttributes(numattrs, names, vals); - } + *result = nsnull; - *result = NULL; - - for (int i = 0; i < mNumAttrs; i++) { - if (0 == PL_strcasecmp(mAttrNames[i], name)) { - *result = mAttrVals[i]; + for (int i = 0; i < mNumCachedAttrs; i++) { + if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { + *result = mCachedAttrParamValues[i]; return NS_OK; } } @@ -2527,148 +2413,16 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetTagText(const char* *result) NS_IMETHODIMP nsPluginInstanceOwner::GetParameters(PRUint16& n, const char*const*& names, const char*const*& values) { - nsresult rv = NS_ERROR_FAILURE; + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if ((nsnull == mParamNames) && (nsnull != mOwner)) - { - nsIContent *cont; + // make sure we have at least one param tag because embed's don't have any + if (!mNumCachedParams) + return NS_ERROR_FAILURE; - mOwner->GetContent(&cont); - - if (nsnull != cont) - { - PRBool haskids = PR_FALSE; - - cont->CanContainChildren(haskids); - - if (PR_TRUE == haskids) - { - PRInt32 numkids, idx, numparams = 0; - - cont->ChildCount(numkids); - - //first pass, count number of param tags... - - for (idx = 0; idx < numkids; idx++) - { - nsIContent *kid; - - cont->ChildAt(idx, kid); - - if (nsnull != kid) - { - nsIAtom *atom; - - kid->GetTag(atom); - - if (nsnull != atom) - { - if (atom == nsHTMLAtoms::param) - numparams++; - - NS_RELEASE(atom); - } - - NS_RELEASE(kid); - } - } - - if (numparams > 0) - { - //now we need to create arrays - //representing the parameter name/value pairs... - - mParamNames = (char **)PR_Calloc(sizeof(char *) * numparams, 1); - mParamVals = (char **)PR_Calloc(sizeof(char *) * numparams, 1); - - if ((nsnull != mParamNames) && (nsnull != mParamVals)) - { - for (idx = 0; idx < numkids; idx++) - { - nsIContent *kid; - - cont->ChildAt(idx, kid); - - if (nsnull != kid) - { - nsIAtom *atom; - - kid->GetTag(atom); - - if (nsnull != atom) - { - if (atom == nsHTMLAtoms::param) - { - nsAutoString val, name; - - //add param to list... - - if ((NS_CONTENT_ATTR_HAS_VALUE == kid->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::name, name)) && - (NS_CONTENT_ATTR_HAS_VALUE == kid->GetAttr(kNameSpaceID_HTML, nsHTMLAtoms::value, val))) - { - -/* Changing to ToNewUTF8String addressing 17169, 39789 - - mParamNames[mNumParams] = (char *)PR_Malloc(name.Length() + 1); - mParamVals[mNumParams] = (char *)PR_Malloc(val.Length() + 1); - - if ((nsnull != mParamNames[mNumParams]) && - (nsnull != mParamVals[mNumParams])) - { - name.ToCString(mParamNames[mNumParams], name.Length() + 1); - val.ToCString(mParamVals[mNumParams], val.Length() + 1); - - mNumParams++; - } - else - { - if (nsnull != mParamNames[mNumParams]) - { - PR_Free(mParamNames[mNumParams]); - mParamNames[mNumParams] = nsnull; - } - - if (nsnull != mParamVals[mNumParams]) - { - PR_Free(mParamVals[mNumParams]); - mParamVals[mNumParams] = nsnull; - } - } -*/ - /* 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.'' - */ - name.CompressWhitespace(); - val.CompressWhitespace(); - mParamNames[mNumParams] = ToNewUTF8String(name); - mParamVals[mNumParams] = ToNewUTF8String(val); - mNumParams++; - } - } - - NS_RELEASE(atom); - } - } - - NS_RELEASE(kid); - } - } - } - } - - rv = NS_OK; - NS_RELEASE(cont); - } - } - - n = mNumParams; - names = (const char **)mParamNames; - values = (const char **)mParamVals; + n = mNumCachedParams; + names = (const char **)(mCachedAttrParamNames + mNumCachedAttrs + 1); + values = (const char **)(mCachedAttrParamValues + mNumCachedAttrs + 1); return rv; } @@ -2677,32 +2431,20 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetParameter(const char* name, const char* { NS_ENSURE_ARG_POINTER(name); NS_ENSURE_ARG_POINTER(result); - nsresult rv; - PRInt32 count; + + nsresult rv = EnsureCachedAttrParamArrays(); + NS_ENSURE_SUCCESS(rv, rv); - if (nsnull == mParamNames) - { - PRUint16 numattrs; - const char * const *names, * const *vals; + *result = nsnull; - rv = GetParameters(numattrs, names, vals); - } - - for (count = 0; count < mNumParams; count++) - { - if (0 == PL_strcasecmp(mParamNames[count], name)) - { - *result = mParamVals[count]; - break; + for (int i = mNumCachedAttrs + 1; i < (mNumCachedParams + 1 + mNumCachedAttrs); i++) { + if (0 == PL_strcasecmp(mCachedAttrParamNames[i], name)) { + *result = mCachedAttrParamValues[i]; + return NS_OK; } } - if (count >= mNumParams) { - *result = ""; - rv = NS_ERROR_FAILURE; - } - - return rv; + return NS_ERROR_FAILURE; } NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentBase(const char* *result) @@ -3000,6 +2742,155 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetMayScript(PRBool *result) return NS_OK; } + +// Cache the attributes and/or parameters of our tag into a single set of arrays +// to be compatible with 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 4.x did. See bug 111008. +nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() +{ + if (mCachedAttrParamValues) + return NS_OK; + + NS_PRECONDITION((((mNumCachedAttrs + mNumCachedParams) == 0) && !mCachedAttrParamNames), + "re-cache of attrs/params not implemented! use the DOM node directy instead"); + NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER); + + // first, we need to find out how much we need to allocate for our arrays + // count up attributes + mNumCachedAttrs = 0; + nsCOMPtr content; + nsresult rv = mOwner->GetContent(getter_AddRefs(content)); + NS_ENSURE_TRUE(content, rv); + rv = content->GetAttrCount((PRInt32&)mNumCachedAttrs); // signed 32 bits to unsigned 16 bits conversion + NS_ENSURE_SUCCESS(rv, rv); + + // now, we need to find all the PARAM tags that are children of us + // however, be carefull 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 nsISupportsArray until we can figure out + // what size to make our fixed char* array. + mNumCachedParams = 0; + nsCOMPtr ourParams; + rv = NS_NewISupportsArray(getter_AddRefs(ourParams)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr mydomNode = do_QueryInterface(content); + NS_ENSURE_TRUE(mydomNode, NS_ERROR_NO_INTERFACE); + + // use the DOM to get us ALL our dependant PARAM tags, even if not ours + nsCOMPtr mydomElement = do_QueryInterface(mydomNode); + NS_ENSURE_TRUE(mydomElement, NS_ERROR_NO_INTERFACE); + nsCOMPtr allParams; + mydomElement->GetElementsByTagName(NS_LITERAL_STRING("PARAM"), getter_AddRefs(allParams)); + if (allParams) { + PRUint32 numAllParams; + allParams->GetLength(&numAllParams); + // loop through every so called dependant PARAM tag to check if it "belongs" to us + for (PRUint32 i = 0; i < numAllParams; i++) { + nsCOMPtr pnode; + allParams->Item(i, getter_AddRefs(pnode)); + if (pnode) { + nsCOMPtr domelement = do_QueryInterface(pnode); + if (domelement) { + // let's NOT count up param tags that don't have a name attribute + nsAutoString name; + domelement->GetAttribute(NS_LITERAL_STRING("name"), name); + if (name.Length() > 0) { + nsCOMPtr parent; + nsCOMPtr domobject; + nsCOMPtr domapplet; + pnode->GetParentNode(getter_AddRefs(parent)); + // walk up the parents of this PARAM until we find an object (or applet) tag + while (!(domobject || domapplet) && parent) { + domobject = do_QueryInterface(parent); + domapplet = do_QueryInterface(parent); + nsCOMPtr temp; + parent->GetParentNode(getter_AddRefs(temp)); + parent = temp; + } + if (domapplet || domobject) { + parent = domapplet ? do_QueryInterface(domapplet) : do_QueryInterface(domobject); + // now check to see if this PARAM's parent is us. if so, cache it for later + if (parent.get() == mydomNode.get()) { + nsCOMPtr sup = do_QueryInterface(pnode); + NS_ASSERTION(sup, "lame! DOM node does doesn't QI to nsISupports"); + ourParams->AppendElement(sup); + } + } + } + } + } + } + } + ourParams->Count((PRUint32*)&mNumCachedParams); // unsigned 32 bits to unsigned 16 bits conversion + + + + // now lets make the arrays + mCachedAttrParamNames = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1); + NS_ENSURE_TRUE(mCachedAttrParamNames, NS_ERROR_OUT_OF_MEMORY); + mCachedAttrParamValues = (char **)PR_Calloc(sizeof(char *) * (mNumCachedAttrs + 1 + mNumCachedParams), 1); + NS_ENSURE_TRUE(mCachedAttrParamValues, NS_ERROR_OUT_OF_MEMORY); + + // let's fill in our attributes + PRInt16 c = 0; + for (PRInt16 index = 0; index < mNumCachedAttrs; index++) { + PRInt32 nameSpaceID; + nsCOMPtr atom; + nsCOMPtr prefix; + content->GetAttrNameAt(index, nameSpaceID, + *getter_AddRefs(atom), + *getter_AddRefs(prefix)); + nsAutoString value; + if (NS_CONTENT_ATTR_NOT_THERE != content->GetAttr(nameSpaceID, atom, value)) { + nsAutoString name; + atom->ToString(name); + mCachedAttrParamNames [c] = ToNewUTF8String(name); + mCachedAttrParamValues[c] = ToNewUTF8String(value); + c++; + } + } + + // add our PARAM and null seperator + mCachedAttrParamNames [mNumCachedAttrs + 1] = "PARAM"; + mCachedAttrParamValues[mNumCachedAttrs + 1] = nsnull; + + // now fill in the PARAM name/value pairs from the cached DOM nodes + c = 0; + for (PRInt16 idx = 0; idx < mNumCachedParams; idx++) { + nsCOMPtr sup = ourParams->ElementAt(idx); + if (sup) { + nsCOMPtr param = do_QueryInterface(sup); + if (param) { + nsAutoString name; + nsAutoString value; + param->GetAttribute(NS_LITERAL_STRING("name"), name); // check for empty done above + param->GetAttribute(NS_LITERAL_STRING("value"), 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.'' + */ + name.CompressWhitespace(); // XXX right function? + value.CompressWhitespace(); + mCachedAttrParamNames [mNumCachedAttrs + 1 + c] = ToNewUTF8String(name); + mCachedAttrParamValues[mNumCachedAttrs + 1 + c] = ToNewUTF8String(value); + c++; // rules! + } + } + } + + return NS_OK; +} + + // Here's where we forward events to plugins. #ifdef XP_MAC diff --git a/modules/plugin/base/src/ns4xPluginInstance.cpp b/modules/plugin/base/src/ns4xPluginInstance.cpp index 9efaac7204df..e217b7e57c1b 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.cpp +++ b/modules/plugin/base/src/ns4xPluginInstance.cpp @@ -796,36 +796,45 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void) //////////////////////////////////////////////////////////////////////// nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer) { + NS_ENSURE_ARG_POINTER(peer); + mPeer = peer; + + nsCOMPtr taginfo = do_QueryInterface(mPeer); + NS_ENSURE_TRUE(taginfo, NS_ERROR_NO_INTERFACE); + + nsPluginTagType tagtype; + nsresult rv = taginfo->GetTagType(&tagtype); + NS_ENSURE_SUCCESS(rv, rv); + PRUint16 count = 0; const char* const* names = nsnull; const char* const* values = nsnull; - nsresult rv; - NPError error; - + rv = taginfo->GetAttributes(count, names, values); + NS_ENSURE_SUCCESS(rv, rv); - NS_ASSERTION(peer != NULL, "null peer"); - - mPeer = peer; - - nsCOMPtr taginfo = do_QueryInterface(mPeer, &rv); - - if (NS_SUCCEEDED(rv)) - { - nsPluginTagType tagtype; - taginfo->GetTagType(&tagtype); - if (tagtype == nsPluginTagType_Embed) - taginfo->GetAttributes(count, names, values); - else // nsPluginTagType_Object - taginfo->GetParameters(count, names, values); + // 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 GetAtributes() + // with a null entry as a seperator. This is for 4.x backwards compatibility! + // see bug 111008 for details + if (tagtype != nsPluginTagType_Embed) { + PRUint16 pcount = 0; + const char* const* pnames = nsnull; + const char* const* pvalues = nsnull; + if (NS_SUCCEEDED(taginfo->GetParameters(pcount, pnames, pvalues))) { + NS_ASSERTION(nsnull == values[count+1], "attribute/parameter array not setup correctly for 4.x plugins"); + count += ++pcount; //if it's all setup correctly, then all we need is to change the count + } } - if (fCallbacks->newp == nsnull) - return NS_ERROR_FAILURE; // XXX right error? + + NS_ENSURE_TRUE(fCallbacks->newp, NS_ERROR_FAILURE); // XXX Note that the NPPluginType_* enums were crafted to be // backward compatible... nsPluginMode mode; nsMIMEType mimetype; + NPError error; mPeer->GetMode(&mode); mPeer->GetMIMEType(&mimetype);