2001-09-25 05:32:19 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2013-05-02 02:50:08 +04:00
|
|
|
/* vim: set ts=2 sw=2 et tw=79: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2000-03-21 16:14:34 +03:00
|
|
|
|
2000-01-13 05:23:54 +03:00
|
|
|
#include "nsCOMPtr.h"
|
2002-07-25 22:31:10 +04:00
|
|
|
#include "nsIAtom.h"
|
2010-07-15 05:53:11 +04:00
|
|
|
#include "nsXBLDocumentInfo.h"
|
2000-01-13 05:23:54 +03:00
|
|
|
#include "nsIInputStream.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2000-01-13 05:23:54 +03:00
|
|
|
#include "nsHashtable.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsIChannel.h"
|
|
|
|
#include "nsXPIDLString.h"
|
2001-09-29 12:28:41 +04:00
|
|
|
#include "nsReadableUtils.h"
|
2000-01-13 05:23:54 +03:00
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "plstr.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
2004-09-01 20:50:12 +04:00
|
|
|
#include "nsContentUtils.h"
|
2013-05-02 02:50:08 +04:00
|
|
|
#include "ChildIterator.h"
|
2013-05-22 20:05:26 +04:00
|
|
|
#include "nsCxPusher.h"
|
2003-04-11 04:56:27 +04:00
|
|
|
#ifdef MOZ_XUL
|
2001-02-20 04:05:34 +03:00
|
|
|
#include "nsIXULDocument.h"
|
2003-04-11 04:56:27 +04:00
|
|
|
#endif
|
2000-01-13 05:23:54 +03:00
|
|
|
#include "nsIXMLContentSink.h"
|
2001-02-19 15:55:42 +03:00
|
|
|
#include "nsContentCID.h"
|
2013-03-20 20:22:26 +04:00
|
|
|
#include "mozilla/dom/XMLDocument.h"
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 20:46:42 +04:00
|
|
|
#include "jsapi.h"
|
2000-05-28 08:10:50 +04:00
|
|
|
#include "nsXBLService.h"
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 20:46:42 +04:00
|
|
|
#include "nsIXPConnect.h"
|
2001-07-16 06:40:48 +04:00
|
|
|
#include "nsIScriptContext.h"
|
2002-05-15 22:55:21 +04:00
|
|
|
#include "nsCRT.h"
|
2000-01-13 05:23:54 +03:00
|
|
|
|
2000-01-26 14:43:31 +03:00
|
|
|
// Event listeners
|
2014-03-17 10:56:53 +04:00
|
|
|
#include "mozilla/EventListenerManager.h"
|
2011-08-08 22:26:26 +04:00
|
|
|
#include "nsIDOMEventListener.h"
|
2005-12-29 00:52:39 +03:00
|
|
|
#include "nsAttrName.h"
|
2000-01-26 14:43:31 +03:00
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2001-11-02 04:53:13 +03:00
|
|
|
|
|
|
|
#include "nsXBLPrototypeHandler.h"
|
2000-09-20 11:16:04 +04:00
|
|
|
|
2003-03-07 02:59:18 +03:00
|
|
|
#include "nsXBLPrototypeBinding.h"
|
2000-06-22 04:36:19 +04:00
|
|
|
#include "nsXBLBinding.h"
|
2005-06-03 05:54:50 +04:00
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
2013-07-02 02:09:37 +04:00
|
|
|
#include "mozilla/dom/XBLChildrenElement.h"
|
2000-01-13 05:23:54 +03:00
|
|
|
|
2004-01-06 02:19:58 +03:00
|
|
|
#include "prprf.h"
|
2006-09-12 16:49:04 +04:00
|
|
|
#include "nsNodeUtils.h"
|
2013-02-08 18:24:21 +04:00
|
|
|
#include "nsJSUtils.h"
|
2004-01-06 02:19:58 +03:00
|
|
|
|
2007-09-28 17:45:01 +04:00
|
|
|
// Nasty hack. Maybe we could move some of the classinfo utility methods
|
2012-06-20 03:01:10 +04:00
|
|
|
// (e.g. WrapNative) over to nsContentUtils?
|
2007-09-28 17:45:01 +04:00
|
|
|
#include "nsDOMClassInfo.h"
|
|
|
|
|
2011-07-20 23:18:54 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2013-12-02 14:26:11 +04:00
|
|
|
#include "mozilla/dom/ShadowRoot.h"
|
2011-07-20 23:18:54 +04:00
|
|
|
|
2012-12-16 05:26:05 +04:00
|
|
|
using namespace mozilla;
|
2012-09-13 00:29:30 +04:00
|
|
|
using namespace mozilla::dom;
|
2012-12-16 05:26:05 +04:00
|
|
|
|
2000-01-25 09:35:27 +03:00
|
|
|
// Helper classes
|
2000-01-13 05:23:54 +03:00
|
|
|
|
2000-03-31 07:13:43 +04:00
|
|
|
/***********************************************************************/
|
|
|
|
//
|
|
|
|
// The JS class for XBLBinding
|
|
|
|
//
|
2008-09-07 02:21:43 +04:00
|
|
|
static void
|
2012-03-19 18:34:55 +04:00
|
|
|
XBLFinalize(JSFreeOp *fop, JSObject *obj)
|
2000-03-31 07:13:43 +04:00
|
|
|
{
|
2010-07-15 05:53:11 +04:00
|
|
|
nsXBLDocumentInfo* docInfo =
|
2012-02-06 00:07:23 +04:00
|
|
|
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
|
2013-08-09 20:25:14 +04:00
|
|
|
nsContentUtils::DeferredFinalize(docInfo);
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2013-09-11 16:49:04 +04:00
|
|
|
nsXBLJSClass* c = nsXBLJSClass::fromJSClass(::JS_GetClass(obj));
|
2000-07-01 06:36:18 +04:00
|
|
|
c->Drop();
|
2000-03-31 07:13:43 +04:00
|
|
|
}
|
|
|
|
|
2013-08-09 02:53:04 +04:00
|
|
|
static bool
|
2012-05-29 23:01:30 +04:00
|
|
|
XBLEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
|
|
|
|
{
|
|
|
|
nsXBLPrototypeBinding* protoBinding =
|
|
|
|
static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
|
|
|
|
MOZ_ASSERT(protoBinding);
|
|
|
|
|
|
|
|
return protoBinding->ResolveAllFields(cx, obj);
|
2007-09-28 17:45:01 +04:00
|
|
|
}
|
|
|
|
|
2012-12-12 19:10:02 +04:00
|
|
|
uint64_t nsXBLJSClass::sIdCount = 0;
|
|
|
|
|
|
|
|
nsXBLJSClass::nsXBLJSClass(const nsAFlatCString& aClassName,
|
|
|
|
const nsCString& aKey)
|
2013-08-22 10:34:44 +04:00
|
|
|
: LinkedListElement<nsXBLJSClass>()
|
|
|
|
, mRefCnt(0)
|
|
|
|
, mKey(aKey)
|
2000-07-01 06:36:18 +04:00
|
|
|
{
|
2013-08-22 10:34:44 +04:00
|
|
|
memset(static_cast<JSClass*>(this), 0, sizeof(JSClass));
|
2001-06-17 09:23:38 +04:00
|
|
|
name = ToNewCString(aClassName);
|
2007-09-28 17:45:01 +04:00
|
|
|
flags =
|
|
|
|
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
|
2012-05-29 23:01:30 +04:00
|
|
|
JSCLASS_NEW_RESOLVE |
|
2007-09-28 17:45:01 +04:00
|
|
|
// Our one reserved slot holds the relevant nsXBLPrototypeBinding
|
|
|
|
JSCLASS_HAS_RESERVED_SLOTS(1);
|
2013-04-06 08:22:55 +04:00
|
|
|
addProperty = getProperty = ::JS_PropertyStub;
|
|
|
|
delProperty = ::JS_DeletePropertyStub;
|
2011-02-09 22:31:40 +03:00
|
|
|
setProperty = ::JS_StrictPropertyStub;
|
2012-05-29 23:01:30 +04:00
|
|
|
enumerate = XBLEnumerate;
|
2013-02-08 18:24:21 +04:00
|
|
|
resolve = JS_ResolveStub;
|
2000-07-01 06:36:18 +04:00
|
|
|
convert = ::JS_ConvertStub;
|
|
|
|
finalize = XBLFinalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsrefcnt
|
|
|
|
nsXBLJSClass::Destroy()
|
2000-05-27 12:20:04 +04:00
|
|
|
{
|
2013-08-22 10:34:44 +04:00
|
|
|
NS_ASSERTION(!isInList(),
|
2000-07-01 06:36:18 +04:00
|
|
|
"referenced nsXBLJSClass is on LRU list already!?");
|
|
|
|
|
2000-08-02 01:39:28 +04:00
|
|
|
if (nsXBLService::gClassTable) {
|
2014-03-19 01:25:39 +04:00
|
|
|
nsXBLService::gClassTable->Remove(mKey);
|
2012-12-12 19:10:02 +04:00
|
|
|
mKey.Truncate();
|
2000-08-02 01:39:28 +04:00
|
|
|
}
|
|
|
|
|
2000-07-01 06:36:18 +04:00
|
|
|
if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
|
|
|
|
// Over LRU list quota, just unhash and delete this class.
|
|
|
|
delete this;
|
|
|
|
} else {
|
|
|
|
// Put this most-recently-used class on end of the LRU-sorted freelist.
|
2013-08-22 10:34:44 +04:00
|
|
|
nsXBLService::gClassLRUList->insertBack(this);
|
2000-07-01 06:36:18 +04:00
|
|
|
nsXBLService::gClassLRUListLength++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2000-05-27 12:20:04 +04:00
|
|
|
}
|
|
|
|
|
2013-09-11 16:49:04 +04:00
|
|
|
nsXBLJSClass*
|
|
|
|
nsXBLService::getClass(const nsCString& k)
|
|
|
|
{
|
2014-03-19 01:25:39 +04:00
|
|
|
return nsXBLService::gClassTable->Get(k);
|
2013-09-11 16:49:04 +04:00
|
|
|
}
|
|
|
|
|
2000-01-13 05:23:54 +03:00
|
|
|
// Implementation /////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Constructors/Destructors
|
2003-03-07 02:59:18 +03:00
|
|
|
nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
|
2013-11-01 18:31:58 +04:00
|
|
|
: mMarkedForDeath(false)
|
|
|
|
, mUsingXBLScope(false)
|
|
|
|
, mPrototypeBinding(aBinding)
|
2000-01-13 05:23:54 +03:00
|
|
|
{
|
2004-02-15 22:24:42 +03:00
|
|
|
NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
|
|
|
|
// Grab a ref to the document info so the prototype binding won't die
|
|
|
|
NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
|
2000-01-13 05:23:54 +03:00
|
|
|
}
|
|
|
|
|
2013-12-02 14:26:11 +04:00
|
|
|
// Constructor used by web components.
|
|
|
|
nsXBLBinding::nsXBLBinding(ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aBinding)
|
|
|
|
: mMarkedForDeath(false),
|
|
|
|
mPrototypeBinding(aBinding),
|
|
|
|
mContent(aShadowRoot)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
|
|
|
|
// Grab a ref to the document info so the prototype binding won't die
|
|
|
|
NS_ADDREF(mPrototypeBinding->XBLDocumentInfo());
|
|
|
|
}
|
2000-04-03 11:13:07 +04:00
|
|
|
|
2000-01-13 05:23:54 +03:00
|
|
|
nsXBLBinding::~nsXBLBinding(void)
|
|
|
|
{
|
2009-01-06 22:37:28 +03:00
|
|
|
if (mContent) {
|
2011-10-18 14:53:36 +04:00
|
|
|
nsXBLBinding::UninstallAnonymousContent(mContent->OwnerDoc(), mContent);
|
2009-01-06 22:37:28 +03:00
|
|
|
}
|
2010-07-15 05:53:11 +04:00
|
|
|
nsXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
|
2004-02-15 22:24:42 +03:00
|
|
|
NS_RELEASE(info);
|
2000-01-13 05:23:54 +03:00
|
|
|
}
|
|
|
|
|
2013-08-02 05:29:05 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding)
|
|
|
|
|
2012-11-22 21:15:38 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLBinding)
|
2007-05-24 18:10:02 +04:00
|
|
|
// XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
|
|
|
|
// mPrototypeBinding is weak.
|
2009-01-06 22:37:28 +03:00
|
|
|
if (tmp->mContent) {
|
2011-10-18 14:53:36 +04:00
|
|
|
nsXBLBinding::UninstallAnonymousContent(tmp->mContent->OwnerDoc(),
|
2009-01-06 22:37:28 +03:00
|
|
|
tmp->mContent);
|
|
|
|
}
|
2012-11-15 11:32:40 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mNextBinding)
|
2013-05-02 02:50:08 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDefaultInsertionPoint)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInsertionPoints)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousContentList)
|
2007-05-24 18:10:02 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
2012-11-22 21:15:38 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLBinding)
|
2012-01-24 03:25:53 +04:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
|
|
|
"mPrototypeBinding->XBLDocumentInfo()");
|
2013-08-09 20:25:14 +04:00
|
|
|
cb.NoteXPCOMChild(tmp->mPrototypeBinding->XBLDocumentInfo());
|
2012-11-15 11:32:40 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNextBinding)
|
2013-05-02 02:50:08 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDefaultInsertionPoint)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInsertionPoints)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContentList)
|
2007-05-24 18:10:02 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXBLBinding, AddRef)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsXBLBinding, Release)
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
|
|
|
nsXBLBinding::SetBaseBinding(nsXBLBinding* aBinding)
|
2000-01-13 05:23:54 +03:00
|
|
|
{
|
2000-08-14 08:04:18 +04:00
|
|
|
if (mNextBinding) {
|
|
|
|
NS_ERROR("Base XBL binding is already defined!");
|
2005-02-26 01:07:01 +03:00
|
|
|
return;
|
2000-08-14 08:04:18 +04:00
|
|
|
}
|
|
|
|
|
2000-01-13 12:21:09 +03:00
|
|
|
mNextBinding = aBinding; // Comptr handles rel/add
|
2000-01-13 05:23:54 +03:00
|
|
|
}
|
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
nsXBLBinding*
|
|
|
|
nsXBLBinding::GetBindingWithContent()
|
|
|
|
{
|
|
|
|
if (mContent) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mNextBinding ? mNextBinding->GetBindingWithContent() : nullptr;
|
|
|
|
}
|
|
|
|
|
2001-03-07 04:46:13 +03:00
|
|
|
void
|
2012-10-10 23:04:42 +04:00
|
|
|
nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement,
|
|
|
|
bool aChromeOnlyContent)
|
2000-01-13 05:23:54 +03:00
|
|
|
{
|
2001-03-07 04:46:13 +03:00
|
|
|
// We need to ensure two things.
|
2000-01-13 12:43:42 +03:00
|
|
|
// (1) The anonymous content should be fooled into thinking it's in the bound
|
2004-12-02 05:24:28 +03:00
|
|
|
// element's document, assuming that the bound element is in a document
|
2005-04-06 03:54:35 +04:00
|
|
|
// Note that we don't change the current doc of aAnonParent here, since that
|
|
|
|
// quite simply does not matter. aAnonParent is just a way of keeping refs
|
|
|
|
// to all its kids, which are anonymous content from the point of view of
|
|
|
|
// aElement.
|
2000-01-13 12:43:42 +03:00
|
|
|
// (2) The children's parent back pointer should not be to this synthetic root
|
2001-03-07 04:46:13 +03:00
|
|
|
// but should instead point to the enclosing parent element.
|
2005-04-06 03:54:35 +04:00
|
|
|
nsIDocument* doc = aElement->GetCurrentDoc();
|
2011-09-29 10:19:26 +04:00
|
|
|
bool allowScripts = AllowScripts();
|
2005-04-06 03:54:35 +04:00
|
|
|
|
2008-04-11 21:29:06 +04:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* child = aAnonParent->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2005-04-06 03:54:35 +04:00
|
|
|
child->UnbindFromTree();
|
2012-10-10 23:04:42 +04:00
|
|
|
if (aChromeOnlyContent) {
|
|
|
|
child->SetFlags(NODE_CHROME_ONLY_ACCESS |
|
|
|
|
NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS);
|
|
|
|
}
|
2005-04-06 03:54:35 +04:00
|
|
|
nsresult rv =
|
|
|
|
child->BindToTree(doc, aElement, mBoundElement, allowScripts);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Oh, well... Just give up.
|
|
|
|
// XXXbz This really shouldn't be a void method!
|
|
|
|
child->UnbindFromTree();
|
|
|
|
return;
|
2014-03-19 01:25:39 +04:00
|
|
|
}
|
2001-02-20 04:05:34 +03:00
|
|
|
|
2013-09-24 23:28:32 +04:00
|
|
|
child->SetFlags(NODE_IS_ANONYMOUS_ROOT);
|
2009-02-24 21:39:09 +03:00
|
|
|
|
2003-04-11 04:56:27 +04:00
|
|
|
#ifdef MOZ_XUL
|
2001-02-20 04:05:34 +03:00
|
|
|
// To make XUL templates work (and other goodies that happen when
|
|
|
|
// an element is added to a XUL document), we need to notify the
|
|
|
|
// XUL document using its special API.
|
2003-04-11 04:56:27 +04:00
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
|
2001-02-20 04:05:34 +03:00
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->AddSubtreeToDocument(child);
|
2003-04-11 04:56:27 +04:00
|
|
|
#endif
|
2000-01-13 12:43:42 +03:00
|
|
|
}
|
2001-03-07 04:46:13 +03:00
|
|
|
}
|
2000-01-13 12:43:42 +03:00
|
|
|
|
2009-01-06 22:37:28 +03:00
|
|
|
void
|
|
|
|
nsXBLBinding::UninstallAnonymousContent(nsIDocument* aDocument,
|
|
|
|
nsIContent* aAnonParent)
|
|
|
|
{
|
2013-12-02 14:26:11 +04:00
|
|
|
if (aAnonParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
|
|
|
|
// It is unnecessary to uninstall anonymous content in a shadow tree
|
|
|
|
// because the ShadowRoot itself is a DocumentFragment and does not
|
|
|
|
// need any additional cleanup.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-06 22:37:28 +03:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
// Hold a strong ref while doing this, just in case.
|
|
|
|
nsCOMPtr<nsIContent> anonParent = aAnonParent;
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc =
|
|
|
|
do_QueryInterface(aDocument);
|
|
|
|
#endif
|
2011-09-27 11:54:58 +04:00
|
|
|
for (nsIContent* child = aAnonParent->GetFirstChild();
|
|
|
|
child;
|
|
|
|
child = child->GetNextSibling()) {
|
2009-01-06 22:37:28 +03:00
|
|
|
child->UnbindFromTree();
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
if (xuldoc) {
|
|
|
|
xuldoc->RemoveSubtreeFromDocument(child);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-06-02 12:13:29 +04:00
|
|
|
nsXBLBinding::SetBoundElement(nsIContent* aElement)
|
2000-01-13 11:54:16 +03:00
|
|
|
{
|
2000-06-02 12:13:29 +04:00
|
|
|
mBoundElement = aElement;
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->SetBoundElement(aElement);
|
2013-11-01 18:31:58 +04:00
|
|
|
|
|
|
|
if (!mBoundElement) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute whether we're using an XBL scope.
|
|
|
|
//
|
|
|
|
// We disable XBL scopes for remote XUL, where we care about compat more
|
|
|
|
// than security. So we need to know whether we're using an XBL scope so that
|
|
|
|
// we can decide what to do about untrusted events when "allowuntrusted"
|
|
|
|
// is not given in the handler declaration.
|
|
|
|
nsCOMPtr<nsIGlobalObject> go = mBoundElement->OwnerDoc()->GetScopeObject();
|
|
|
|
NS_ENSURE_TRUE_VOID(go && go->GetGlobalJSObject());
|
|
|
|
mUsingXBLScope = xpc::UseXBLScope(js::GetObjectCompartment(go->GetGlobalJSObject()));
|
2000-06-02 12:13:29 +04:00
|
|
|
}
|
2000-01-13 12:43:42 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2005-02-26 01:07:01 +03:00
|
|
|
nsXBLBinding::HasStyleSheets() const
|
2000-09-08 14:01:18 +04:00
|
|
|
{
|
|
|
|
// Find out if we need to re-resolve style. We'll need to do this
|
|
|
|
// if we have additional stylesheets in our binding document.
|
2005-02-26 01:07:01 +03:00
|
|
|
if (mPrototypeBinding->HasStyleSheets())
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2000-09-08 14:01:18 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return mNextBinding ? mNextBinding->HasStyleSheets() : false;
|
2000-09-08 14:01:18 +04:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2001-02-23 02:47:30 +03:00
|
|
|
nsXBLBinding::GenerateAnonymousContent()
|
2000-06-02 12:13:29 +04:00
|
|
|
{
|
2009-11-18 18:14:14 +03:00
|
|
|
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
|
|
|
|
"Someone forgot a script blocker");
|
|
|
|
|
2000-01-13 12:21:09 +03:00
|
|
|
// Fetch the content element for this binding.
|
2005-03-02 06:20:00 +03:00
|
|
|
nsIContent* content =
|
2006-12-26 20:47:52 +03:00
|
|
|
mPrototypeBinding->GetImmediateChild(nsGkAtoms::content);
|
2000-01-13 12:21:09 +03:00
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
// We have no anonymous content.
|
|
|
|
if (mNextBinding)
|
2005-02-26 01:07:01 +03:00
|
|
|
mNextBinding->GenerateAnonymousContent();
|
|
|
|
|
|
|
|
return;
|
2000-01-13 12:21:09 +03:00
|
|
|
}
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2000-09-28 00:23:49 +04:00
|
|
|
// Find out if we're really building kids or if we're just
|
|
|
|
// using the attribute-setting shorthand hack.
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t contentCount = content->GetChildCount();
|
2000-07-27 10:20:57 +04:00
|
|
|
|
2000-09-28 00:23:49 +04:00
|
|
|
// Plan to build the content by default.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool hasContent = (contentCount > 0);
|
2013-05-02 02:50:08 +04:00
|
|
|
if (hasContent) {
|
2011-10-18 14:53:36 +04:00
|
|
|
nsIDocument* doc = mBoundElement->OwnerDoc();
|
2001-03-17 03:27:13 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
nsCOMPtr<nsINode> clonedNode;
|
|
|
|
nsCOMArray<nsINode> nodesWithProperties;
|
|
|
|
nsNodeUtils::Clone(content, true, doc->NodeInfoManager(),
|
|
|
|
nodesWithProperties, getter_AddRefs(clonedNode));
|
|
|
|
mContent = clonedNode->AsElement();
|
|
|
|
|
|
|
|
// Search for <xbl:children> elements in the XBL content. In the presence
|
|
|
|
// of multiple default insertion points, we use the last one in document
|
|
|
|
// order.
|
|
|
|
for (nsIContent* child = mContent; child; child = child->GetNextNode(mContent)) {
|
|
|
|
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
|
2013-07-02 02:09:37 +04:00
|
|
|
XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child);
|
2013-05-02 02:50:08 +04:00
|
|
|
if (point->IsDefaultInsertion()) {
|
|
|
|
mDefaultInsertionPoint = point;
|
|
|
|
} else {
|
|
|
|
mInsertionPoints.AppendElement(point);
|
2000-01-13 12:21:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-03-14 14:09:46 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
// Do this after looking for <children> as this messes up the parent
|
|
|
|
// pointer which would make the GetNextNode call above fail
|
|
|
|
InstallAnonymousContent(mContent, mBoundElement,
|
|
|
|
mPrototypeBinding->ChromeOnlyContent());
|
2001-03-07 04:46:13 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
// Insert explicit children into insertion points
|
|
|
|
if (mDefaultInsertionPoint && mInsertionPoints.IsEmpty()) {
|
|
|
|
ExplicitChildIterator iter(mBoundElement);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2013-07-17 20:05:06 +04:00
|
|
|
mDefaultInsertionPoint->AppendInsertedChild(child);
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
2013-07-12 01:05:54 +04:00
|
|
|
} else {
|
|
|
|
// It is odd to come into this code if mInsertionPoints is not empty, but
|
|
|
|
// we need to make sure to do the compatibility hack below if the bound
|
2013-07-18 03:20:37 +04:00
|
|
|
// node has any non <xul:template> or <xul:observes> children.
|
2013-05-02 02:50:08 +04:00
|
|
|
ExplicitChildIterator iter(mBoundElement);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
2013-07-02 02:09:37 +04:00
|
|
|
XBLChildrenElement* point = FindInsertionPointForInternal(child);
|
2013-05-02 02:50:08 +04:00
|
|
|
if (point) {
|
2013-07-17 20:05:06 +04:00
|
|
|
point->AppendInsertedChild(child);
|
2013-07-12 01:05:54 +04:00
|
|
|
} else {
|
|
|
|
nsINodeInfo *ni = child->NodeInfo();
|
|
|
|
if (ni->NamespaceID() != kNameSpaceID_XUL ||
|
|
|
|
(!ni->Equals(nsGkAtoms::_template) &&
|
2013-07-18 03:20:37 +04:00
|
|
|
!ni->Equals(nsGkAtoms::observes))) {
|
2013-07-12 01:05:54 +04:00
|
|
|
// Compatibility hack. For some reason the original XBL
|
|
|
|
// implementation dropped the content of a binding if any child of
|
|
|
|
// the bound element didn't match any of the <children> in the
|
|
|
|
// binding. This became a pseudo-API that we have to maintain.
|
|
|
|
|
|
|
|
// Undo InstallAnonymousContent
|
|
|
|
UninstallAnonymousContent(doc, mContent);
|
|
|
|
|
|
|
|
// Clear out our children elements to avoid dangling references.
|
|
|
|
ClearInsertionPoints();
|
|
|
|
|
|
|
|
// Pretend as though there was no content in the binding.
|
|
|
|
mContent = nullptr;
|
|
|
|
return;
|
|
|
|
}
|
2006-09-19 01:35:21 +04:00
|
|
|
}
|
2001-03-17 03:27:13 +03:00
|
|
|
}
|
2001-02-02 03:54:47 +03:00
|
|
|
}
|
2001-08-14 04:07:36 +04:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
// Set binding parent on default content if need
|
|
|
|
if (mDefaultInsertionPoint) {
|
2013-07-17 20:05:06 +04:00
|
|
|
mDefaultInsertionPoint->MaybeSetupDefaultContent();
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
|
|
|
for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
|
2013-07-17 20:05:06 +04:00
|
|
|
mInsertionPoints[i]->MaybeSetupDefaultContent();
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
|
|
|
|
2001-08-14 04:07:36 +04:00
|
|
|
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
|
2000-09-28 00:23:49 +04:00
|
|
|
}
|
2000-03-14 14:09:46 +03:00
|
|
|
|
2000-09-28 00:23:49 +04:00
|
|
|
// Always check the content element for potential attributes.
|
|
|
|
// This shorthand hack always happens, even when we didn't
|
|
|
|
// build anonymous content.
|
2005-12-29 00:52:39 +03:00
|
|
|
const nsAttrName* attrName;
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; (attrName = content->GetAttrNameAt(i)); ++i) {
|
|
|
|
int32_t namespaceID = attrName->NamespaceID();
|
2008-03-19 22:44:08 +03:00
|
|
|
// Hold a strong reference here so that the atom doesn't go away during
|
|
|
|
// UnsetAttr.
|
|
|
|
nsCOMPtr<nsIAtom> name = attrName->LocalName();
|
2000-09-15 10:38:35 +04:00
|
|
|
|
2006-12-26 20:47:52 +03:00
|
|
|
if (name != nsGkAtoms::includes) {
|
2006-04-24 09:40:11 +04:00
|
|
|
if (!nsContentUtils::HasNonEmptyAttr(mBoundElement, namespaceID, name)) {
|
2000-09-28 00:23:49 +04:00
|
|
|
nsAutoString value2;
|
2001-08-17 12:14:14 +04:00
|
|
|
content->GetAttr(namespaceID, name, value2);
|
2006-04-07 00:55:25 +04:00
|
|
|
mBoundElement->SetAttr(namespaceID, name, attrName->GetPrefix(),
|
2011-10-17 18:59:28 +04:00
|
|
|
value2, false);
|
2000-09-28 00:23:49 +04:00
|
|
|
}
|
2000-03-14 14:09:46 +03:00
|
|
|
}
|
2000-09-28 00:23:49 +04:00
|
|
|
|
|
|
|
// Conserve space by wiping the attributes off the clone.
|
|
|
|
if (mContent)
|
2011-10-17 18:59:28 +04:00
|
|
|
mContent->UnsetAttr(namespaceID, name, false);
|
2000-01-13 12:21:09 +03:00
|
|
|
}
|
2000-01-13 11:54:16 +03:00
|
|
|
}
|
|
|
|
|
2013-07-02 02:09:37 +04:00
|
|
|
XBLChildrenElement*
|
2013-05-02 02:50:08 +04:00
|
|
|
nsXBLBinding::FindInsertionPointFor(nsIContent* aChild)
|
|
|
|
{
|
|
|
|
// XXX We should get rid of this function as it causes us to traverse the
|
|
|
|
// binding chain multiple times
|
|
|
|
if (mContent) {
|
|
|
|
return FindInsertionPointForInternal(aChild);
|
|
|
|
}
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
return mNextBinding ? mNextBinding->FindInsertionPointFor(aChild)
|
|
|
|
: nullptr;
|
|
|
|
}
|
|
|
|
|
2013-07-02 02:09:37 +04:00
|
|
|
XBLChildrenElement*
|
2013-05-02 02:50:08 +04:00
|
|
|
nsXBLBinding::FindInsertionPointForInternal(nsIContent* aChild)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
|
2013-07-02 02:09:37 +04:00
|
|
|
XBLChildrenElement* point = mInsertionPoints[i];
|
2013-05-02 02:50:08 +04:00
|
|
|
if (point->Includes(aChild)) {
|
|
|
|
return point;
|
|
|
|
}
|
|
|
|
}
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
return mDefaultInsertionPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsXBLBinding::ClearInsertionPoints()
|
|
|
|
{
|
|
|
|
if (mDefaultInsertionPoint) {
|
|
|
|
mDefaultInsertionPoint->ClearInsertedChildren();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mInsertionPoints.Length(); ++i) {
|
|
|
|
mInsertionPoints[i]->ClearInsertedChildren();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAnonymousContentList*
|
|
|
|
nsXBLBinding::GetAnonymousNodeList()
|
|
|
|
{
|
|
|
|
if (!mContent) {
|
|
|
|
return mNextBinding ? mNextBinding->GetAnonymousNodeList() : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mAnonymousContentList) {
|
|
|
|
mAnonymousContentList = new nsAnonymousContentList(mContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mAnonymousContentList;
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2001-03-10 04:43:09 +03:00
|
|
|
nsXBLBinding::InstallEventHandlers()
|
2000-01-13 11:54:16 +03:00
|
|
|
{
|
2000-09-02 05:09:47 +04:00
|
|
|
// Don't install handlers if scripts aren't allowed.
|
2000-09-03 09:35:36 +04:00
|
|
|
if (AllowScripts()) {
|
|
|
|
// Fetch the handlers prototypes for this binding.
|
2003-03-07 02:59:18 +03:00
|
|
|
nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
|
2000-06-02 12:13:29 +04:00
|
|
|
|
2003-05-21 07:14:47 +04:00
|
|
|
if (handlerChain) {
|
2014-03-17 10:56:53 +04:00
|
|
|
EventListenerManager* manager = mBoundElement->GetOrCreateListenerManager();
|
2005-08-22 02:20:36 +04:00
|
|
|
if (!manager)
|
|
|
|
return;
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isChromeDoc =
|
2011-10-18 14:53:36 +04:00
|
|
|
nsContentUtils::IsChromeDoc(mBoundElement->OwnerDoc());
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isChromeBinding = mPrototypeBinding->IsChrome();
|
2003-09-11 16:25:06 +04:00
|
|
|
nsXBLPrototypeHandler* curr;
|
|
|
|
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
|
2003-05-21 07:14:47 +04:00
|
|
|
// Fetch the event type.
|
|
|
|
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
|
2003-09-11 16:25:06 +04:00
|
|
|
if (!eventAtom ||
|
2006-12-26 20:47:52 +03:00
|
|
|
eventAtom == nsGkAtoms::keyup ||
|
|
|
|
eventAtom == nsGkAtoms::keydown ||
|
|
|
|
eventAtom == nsGkAtoms::keypress)
|
2003-05-21 07:14:47 +04:00
|
|
|
continue;
|
2003-09-11 16:25:06 +04:00
|
|
|
|
|
|
|
nsXBLEventHandler* handler = curr->GetEventHandler();
|
|
|
|
if (handler) {
|
2005-08-22 02:20:36 +04:00
|
|
|
// Figure out if we're using capturing or not.
|
2014-03-17 10:56:52 +04:00
|
|
|
EventListenerFlags flags;
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
|
2005-08-22 02:20:36 +04:00
|
|
|
|
2011-06-24 06:18:02 +04:00
|
|
|
// If this is a command, add it in the system event group
|
|
|
|
if ((curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
|
|
|
|
NS_HANDLER_TYPE_SYSTEM)) &&
|
|
|
|
(isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mInSystemGroup = true;
|
2011-06-24 06:18:02 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool hasAllowUntrustedAttr = curr->HasAllowUntrustedAttr();
|
2007-04-15 20:28:53 +04:00
|
|
|
if ((hasAllowUntrustedAttr && curr->AllowUntrustedEvents()) ||
|
2013-11-01 18:31:58 +04:00
|
|
|
(!hasAllowUntrustedAttr && !isChromeDoc && !mUsingXBLScope)) {
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mAllowUntrustedEvents = true;
|
2005-08-22 02:20:36 +04:00
|
|
|
}
|
|
|
|
|
2010-03-08 18:45:00 +03:00
|
|
|
manager->AddEventListenerByType(handler,
|
|
|
|
nsDependentAtomString(eventAtom),
|
2011-06-24 06:18:02 +04:00
|
|
|
flags);
|
2001-03-30 06:30:17 +04:00
|
|
|
}
|
2003-09-11 16:25:06 +04:00
|
|
|
}
|
2000-09-03 09:35:36 +04:00
|
|
|
|
2003-09-11 16:25:06 +04:00
|
|
|
const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
|
|
|
|
mPrototypeBinding->GetKeyEventHandlers();
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i;
|
2003-09-11 16:25:06 +04:00
|
|
|
for (i = 0; i < keyHandlers->Count(); ++i) {
|
|
|
|
nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
|
2007-04-15 20:28:53 +04:00
|
|
|
handler->SetIsBoundToChrome(isChromeDoc);
|
2013-11-01 18:31:58 +04:00
|
|
|
handler->SetUsingXBLScope(mUsingXBLScope);
|
2000-09-03 09:35:36 +04:00
|
|
|
|
2003-09-11 16:25:06 +04:00
|
|
|
nsAutoString type;
|
|
|
|
handler->GetEventName(type);
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
// If this is a command, add it in the system event group, otherwise
|
2003-09-11 16:25:06 +04:00
|
|
|
// add it to the standard event group.
|
|
|
|
|
2005-08-22 02:20:36 +04:00
|
|
|
// Figure out if we're using capturing or not.
|
2014-03-17 10:56:52 +04:00
|
|
|
EventListenerFlags flags;
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
|
2005-08-22 02:20:36 +04:00
|
|
|
|
2011-06-24 06:18:02 +04:00
|
|
|
if ((handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
|
|
|
|
NS_HANDLER_TYPE_SYSTEM)) &&
|
|
|
|
(isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mInSystemGroup = true;
|
2011-06-24 06:18:02 +04:00
|
|
|
}
|
|
|
|
|
2012-12-16 05:26:05 +04:00
|
|
|
// For key handlers we have to set mAllowUntrustedEvents flag.
|
2005-08-22 02:20:36 +04:00
|
|
|
// Whether the handling of the event is allowed or not is handled in
|
|
|
|
// nsXBLKeyEventHandler::HandleEvent
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mAllowUntrustedEvents = true;
|
2005-08-22 02:20:36 +04:00
|
|
|
|
2011-06-24 06:18:02 +04:00
|
|
|
manager->AddEventListenerByType(handler, type, flags);
|
2000-01-26 14:43:31 +03:00
|
|
|
}
|
2000-09-03 09:35:36 +04:00
|
|
|
}
|
2000-01-26 14:43:31 +03:00
|
|
|
}
|
|
|
|
|
2001-03-10 04:43:09 +03:00
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->InstallEventHandlers();
|
2000-01-13 11:54:16 +03:00
|
|
|
}
|
|
|
|
|
2005-06-12 01:30:20 +04:00
|
|
|
nsresult
|
2001-11-13 07:09:56 +03:00
|
|
|
nsXBLBinding::InstallImplementation()
|
2000-03-29 05:24:35 +04:00
|
|
|
{
|
|
|
|
// Always install the base class properties first, so that
|
|
|
|
// derived classes can reference the base class properties.
|
2001-09-05 11:36:55 +04:00
|
|
|
|
2005-06-12 01:30:20 +04:00
|
|
|
if (mNextBinding) {
|
|
|
|
nsresult rv = mNextBinding->InstallImplementation();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2013-04-05 17:21:03 +04:00
|
|
|
|
2001-09-05 11:36:55 +04:00
|
|
|
// iterate through each property in the prototype's list and install the property.
|
2001-11-13 07:09:56 +03:00
|
|
|
if (AllowScripts())
|
2013-02-08 18:24:20 +04:00
|
|
|
return mPrototypeBinding->InstallImplementation(this);
|
2005-06-12 01:30:20 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
2000-03-29 05:24:35 +04:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
nsIAtom*
|
2012-08-22 19:56:38 +04:00
|
|
|
nsXBLBinding::GetBaseTag(int32_t* aNameSpaceID)
|
2000-03-11 13:36:39 +03:00
|
|
|
{
|
2005-02-26 01:07:01 +03:00
|
|
|
nsIAtom *tag = mPrototypeBinding->GetBaseTag(aNameSpaceID);
|
|
|
|
if (!tag && mNextBinding)
|
|
|
|
return mNextBinding->GetBaseTag(aNameSpaceID);
|
|
|
|
|
|
|
|
return tag;
|
2000-03-11 13:36:39 +03:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2012-08-22 19:56:38 +04:00
|
|
|
nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aRemoveFlag, bool aNotify)
|
2000-01-25 09:35:27 +03:00
|
|
|
{
|
2000-09-28 00:23:49 +04:00
|
|
|
// XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
|
|
|
|
if (!mContent) {
|
|
|
|
if (mNextBinding)
|
2005-02-26 01:07:01 +03:00
|
|
|
mNextBinding->AttributeChanged(aAttribute, aNameSpaceID,
|
|
|
|
aRemoveFlag, aNotify);
|
|
|
|
} else {
|
|
|
|
mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag,
|
|
|
|
mBoundElement, mContent, aNotify);
|
2000-01-25 09:35:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-07-28 04:35:02 +04:00
|
|
|
nsXBLBinding::ExecuteAttachedHandler()
|
|
|
|
{
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->ExecuteAttachedHandler();
|
|
|
|
|
2011-06-12 00:43:33 +04:00
|
|
|
if (AllowScripts())
|
2005-01-27 22:21:14 +03:00
|
|
|
mPrototypeBinding->BindingAttached(mBoundElement);
|
2000-07-28 04:35:02 +04:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-07-28 04:35:02 +04:00
|
|
|
nsXBLBinding::ExecuteDetachedHandler()
|
|
|
|
{
|
2005-01-27 22:21:14 +03:00
|
|
|
if (AllowScripts())
|
|
|
|
mPrototypeBinding->BindingDetached(mBoundElement);
|
2000-07-28 04:35:02 +04:00
|
|
|
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->ExecuteDetachedHandler();
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-06-22 04:36:19 +04:00
|
|
|
nsXBLBinding::UnhookEventHandlers()
|
|
|
|
{
|
2003-09-11 16:25:06 +04:00
|
|
|
nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
|
|
|
|
|
|
|
|
if (handlerChain) {
|
2014-03-17 10:56:53 +04:00
|
|
|
EventListenerManager* manager = mBoundElement->GetExistingListenerManager();
|
2007-11-16 01:29:08 +03:00
|
|
|
if (!manager) {
|
|
|
|
return;
|
|
|
|
}
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool isChromeBinding = mPrototypeBinding->IsChrome();
|
2003-09-11 16:25:06 +04:00
|
|
|
nsXBLPrototypeHandler* curr;
|
|
|
|
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
|
|
|
|
nsXBLEventHandler* handler = curr->GetCachedEventHandler();
|
2007-11-16 01:29:08 +03:00
|
|
|
if (!handler) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2007-11-16 01:29:08 +03:00
|
|
|
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
|
|
|
|
if (!eventAtom ||
|
|
|
|
eventAtom == nsGkAtoms::keyup ||
|
|
|
|
eventAtom == nsGkAtoms::keydown ||
|
|
|
|
eventAtom == nsGkAtoms::keypress)
|
|
|
|
continue;
|
2003-09-11 16:25:06 +04:00
|
|
|
|
2007-11-16 01:29:08 +03:00
|
|
|
// Figure out if we're using capturing or not.
|
2014-03-17 10:56:52 +04:00
|
|
|
EventListenerFlags flags;
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
|
2003-09-11 16:25:06 +04:00
|
|
|
|
2007-11-16 01:29:08 +03:00
|
|
|
// If this is a command, remove it from the system event group,
|
|
|
|
// otherwise remove it from the standard event group.
|
2003-09-11 16:25:06 +04:00
|
|
|
|
2011-06-24 06:18:02 +04:00
|
|
|
if ((curr->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND |
|
|
|
|
NS_HANDLER_TYPE_SYSTEM)) &&
|
2009-06-23 14:07:39 +04:00
|
|
|
(isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mInSystemGroup = true;
|
2003-09-11 16:25:06 +04:00
|
|
|
}
|
2007-11-16 01:29:08 +03:00
|
|
|
|
2010-03-08 18:45:00 +03:00
|
|
|
manager->RemoveEventListenerByType(handler,
|
|
|
|
nsDependentAtomString(eventAtom),
|
2011-06-24 06:18:02 +04:00
|
|
|
flags);
|
2003-09-11 16:25:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
|
|
|
|
mPrototypeBinding->GetKeyEventHandlers();
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t i;
|
2003-09-11 16:25:06 +04:00
|
|
|
for (i = 0; i < keyHandlers->Count(); ++i) {
|
|
|
|
nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
|
|
|
|
|
|
|
|
nsAutoString type;
|
|
|
|
handler->GetEventName(type);
|
|
|
|
|
|
|
|
// Figure out if we're using capturing or not.
|
2014-03-17 10:56:52 +04:00
|
|
|
EventListenerFlags flags;
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
|
2003-09-11 16:25:06 +04:00
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
// If this is a command, remove it from the system event group, otherwise
|
2003-09-11 16:25:06 +04:00
|
|
|
// remove it from the standard event group.
|
|
|
|
|
2009-06-23 14:07:39 +04:00
|
|
|
if ((handler->GetType() & (NS_HANDLER_TYPE_XBL_COMMAND | NS_HANDLER_TYPE_SYSTEM)) &&
|
|
|
|
(isChromeBinding || mBoundElement->IsInNativeAnonymousSubtree())) {
|
2012-12-16 05:26:05 +04:00
|
|
|
flags.mInSystemGroup = true;
|
2003-09-11 16:25:06 +04:00
|
|
|
}
|
|
|
|
|
2011-06-24 06:18:02 +04:00
|
|
|
manager->RemoveEventListenerByType(handler, type, flags);
|
2003-09-11 16:25:06 +04:00
|
|
|
}
|
2000-06-22 04:36:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
static void
|
2013-07-17 20:05:06 +04:00
|
|
|
UpdateInsertionParent(XBLChildrenElement* aPoint,
|
2013-05-02 02:50:08 +04:00
|
|
|
nsIContent* aOldBoundElement)
|
|
|
|
{
|
|
|
|
if (aPoint->IsDefaultInsertion()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < aPoint->InsertedChildrenLength(); ++i) {
|
|
|
|
nsIContent* child = aPoint->mInsertedChildren[i];
|
|
|
|
|
|
|
|
MOZ_ASSERT(child->GetParentNode());
|
|
|
|
|
|
|
|
// Here, we're iterating children that we inserted. There are two cases:
|
|
|
|
// either |child| is an explicit child of |aOldBoundElement| and is no
|
|
|
|
// longer inserted anywhere or it's a child of a <children> element
|
|
|
|
// parented to |aOldBoundElement|. In the former case, the child is no
|
|
|
|
// longer inserted anywhere, so we set its insertion parent to null. In the
|
|
|
|
// latter case, the child is now inserted into |aOldBoundElement| from some
|
|
|
|
// binding above us, so we set its insertion parent to aOldBoundElement.
|
|
|
|
if (child->GetParentNode() == aOldBoundElement) {
|
2013-07-17 20:05:06 +04:00
|
|
|
child->SetXBLInsertionParent(nullptr);
|
2013-05-02 02:50:08 +04:00
|
|
|
} else {
|
2013-07-17 20:05:06 +04:00
|
|
|
child->SetXBLInsertionParent(aOldBoundElement);
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-05-04 08:25:50 +04:00
|
|
|
nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
|
2000-03-31 14:27:12 +04:00
|
|
|
{
|
2013-04-05 17:21:01 +04:00
|
|
|
if (aOldDocument == aNewDocument)
|
|
|
|
return;
|
|
|
|
|
2013-07-11 19:58:28 +04:00
|
|
|
// Now the binding dies. Unhook our prototypes.
|
|
|
|
if (mPrototypeBinding->HasImplementation()) {
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(
|
|
|
|
aOldDocument->GetScopeObject());
|
|
|
|
if (global) {
|
|
|
|
nsCOMPtr<nsIScriptContext> context = global->GetContext();
|
|
|
|
if (context) {
|
|
|
|
JSContext *cx = context->GetNativeContext();
|
|
|
|
|
|
|
|
nsCxPusher pusher;
|
|
|
|
pusher.Push(cx);
|
|
|
|
|
|
|
|
// scope might be null if we've cycle-collected the global
|
|
|
|
// object, since the Unlink phase of cycle collection happens
|
|
|
|
// after JS GC finalization. But in that case, we don't care
|
|
|
|
// about fixing the prototype chain, since everything's going
|
|
|
|
// away immediately.
|
|
|
|
JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
|
|
|
|
JS::Rooted<JSObject*> scriptObject(cx, mBoundElement->GetWrapper());
|
|
|
|
if (scope && scriptObject) {
|
|
|
|
// XXX Stay in sync! What if a layered binding has an
|
|
|
|
// <interface>?!
|
|
|
|
// XXXbz what does that comment mean, really? It seems to date
|
|
|
|
// back to when there was such a thing as an <interface>, whever
|
|
|
|
// that was...
|
|
|
|
|
|
|
|
// Find the right prototype.
|
|
|
|
JSAutoCompartment ac(cx, scriptObject);
|
|
|
|
|
|
|
|
JS::Rooted<JSObject*> base(cx, scriptObject);
|
|
|
|
JS::Rooted<JSObject*> proto(cx);
|
|
|
|
for ( ; true; base = proto) { // Will break out on null proto
|
2013-07-31 20:20:33 +04:00
|
|
|
if (!JS_GetPrototype(cx, base, &proto)) {
|
2013-07-11 19:58:28 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!proto) {
|
2013-04-05 17:21:01 +04:00
|
|
|
break;
|
|
|
|
}
|
2007-10-20 08:22:43 +04:00
|
|
|
|
2013-09-11 16:49:05 +04:00
|
|
|
const JSClass* clazz = ::JS_GetClass(proto);
|
2013-07-11 19:58:28 +04:00
|
|
|
if (!clazz ||
|
|
|
|
(~clazz->flags &
|
|
|
|
(JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS)) ||
|
|
|
|
JSCLASS_RESERVED_SLOTS(clazz) != 1 ||
|
|
|
|
clazz->finalize != XBLFinalize) {
|
|
|
|
// Clearly not the right class
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<nsXBLDocumentInfo> docInfo =
|
|
|
|
static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(proto));
|
|
|
|
if (!docInfo) {
|
|
|
|
// Not the proto we seek
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS::Value protoBinding = ::JS_GetReservedSlot(proto, 0);
|
2007-10-25 02:13:00 +04:00
|
|
|
|
2013-07-11 19:58:28 +04:00
|
|
|
if (JSVAL_TO_PRIVATE(protoBinding) != mPrototypeBinding) {
|
|
|
|
// Not the right binding
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alright! This is the right prototype. Pull it out of the
|
|
|
|
// proto chain.
|
|
|
|
JS::Rooted<JSObject*> grandProto(cx);
|
2013-07-31 20:20:33 +04:00
|
|
|
if (!JS_GetPrototype(cx, proto, &grandProto)) {
|
2013-07-11 19:58:28 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
::JS_SetPrototype(cx, base, grandProto);
|
|
|
|
break;
|
2000-05-27 12:20:04 +04:00
|
|
|
}
|
2013-07-11 19:58:28 +04:00
|
|
|
|
|
|
|
mPrototypeBinding->UndefineFields(cx, scriptObject);
|
|
|
|
|
|
|
|
// Don't remove the reference from the document to the
|
|
|
|
// wrapper here since it'll be removed by the element
|
|
|
|
// itself when that's taken out of the document.
|
2000-05-04 08:25:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 17:21:01 +04:00
|
|
|
}
|
|
|
|
|
2013-07-11 19:58:28 +04:00
|
|
|
// Remove our event handlers
|
|
|
|
UnhookEventHandlers();
|
|
|
|
|
2013-04-05 17:21:01 +04:00
|
|
|
{
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2007-10-20 08:22:43 +04:00
|
|
|
|
2013-04-05 17:21:01 +04:00
|
|
|
// Then do our ancestors. This reverses the construction order, so that at
|
|
|
|
// all times things are consistent as far as everyone is concerned.
|
|
|
|
if (mNextBinding) {
|
|
|
|
mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
|
|
|
|
}
|
2001-03-07 04:46:13 +03:00
|
|
|
|
2013-04-05 17:21:01 +04:00
|
|
|
// Update the anonymous content.
|
|
|
|
// XXXbz why not only for style bindings?
|
2013-05-02 02:50:08 +04:00
|
|
|
if (mContent) {
|
|
|
|
nsXBLBinding::UninstallAnonymousContent(aOldDocument, mContent);
|
2013-04-05 17:21:01 +04:00
|
|
|
}
|
2009-11-18 18:14:14 +03:00
|
|
|
|
2013-05-02 02:50:08 +04:00
|
|
|
// Now that we've unbound our anonymous content from the tree and updated
|
|
|
|
// its binding parent, update the insertion parent for content inserted
|
|
|
|
// into our <children> elements.
|
|
|
|
if (mDefaultInsertionPoint) {
|
2013-07-17 20:05:06 +04:00
|
|
|
UpdateInsertionParent(mDefaultInsertionPoint, mBoundElement);
|
2004-10-24 21:30:47 +04:00
|
|
|
}
|
2013-05-02 02:50:08 +04:00
|
|
|
|
|
|
|
for (size_t i = 0; i < mInsertionPoints.Length(); ++i) {
|
2013-07-17 20:05:06 +04:00
|
|
|
UpdateInsertionParent(mInsertionPoints[i], mBoundElement);
|
2013-05-02 02:50:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now that our inserted children no longer think they're inserted
|
|
|
|
// anywhere, make sure our internal state reflects that as well.
|
|
|
|
ClearInsertionPoints();
|
2000-03-31 14:27:12 +04:00
|
|
|
}
|
2000-08-12 10:28:02 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2005-02-26 01:07:01 +03:00
|
|
|
nsXBLBinding::InheritsStyle() const
|
2000-08-12 10:28:02 +04:00
|
|
|
{
|
2000-09-28 00:23:49 +04:00
|
|
|
// XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
|
|
|
|
// Most derived binding with anonymous content determines style inheritance for now.
|
|
|
|
|
|
|
|
// XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
|
2005-02-26 01:07:01 +03:00
|
|
|
if (mContent)
|
|
|
|
return mPrototypeBinding->InheritsStyle();
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2000-09-28 00:23:49 +04:00
|
|
|
if (mNextBinding)
|
2005-02-26 01:07:01 +03:00
|
|
|
return mNextBinding->InheritsStyle();
|
2000-08-24 13:21:27 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2000-08-12 10:28:02 +04:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2004-01-08 01:30:53 +03:00
|
|
|
nsXBLBinding::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData)
|
2000-04-27 06:08:35 +04:00
|
|
|
{
|
2005-02-26 01:07:01 +03:00
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->WalkRules(aFunc, aData);
|
2000-08-12 10:28:02 +04:00
|
|
|
|
2004-07-28 11:08:41 +04:00
|
|
|
nsIStyleRuleProcessor *rules = mPrototypeBinding->GetRuleProcessor();
|
2000-09-08 14:01:18 +04:00
|
|
|
if (rules)
|
2004-07-28 11:08:41 +04:00
|
|
|
(*aFunc)(rules, aData);
|
2000-04-27 06:08:35 +04:00
|
|
|
}
|
|
|
|
|
2000-05-27 12:20:04 +04:00
|
|
|
// Internal helper methods ////////////////////////////////////////////////////////////////
|
2000-03-31 07:13:43 +04:00
|
|
|
|
2002-06-22 00:55:17 +04:00
|
|
|
// static
|
|
|
|
nsresult
|
2014-03-19 20:35:45 +04:00
|
|
|
nsXBLBinding::DoInitJSClass(JSContext *cx,
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::Handle<JSObject*> obj,
|
2002-06-22 00:55:17 +04:00
|
|
|
const nsAFlatCString& aClassName,
|
2007-09-28 17:45:01 +04:00
|
|
|
nsXBLPrototypeBinding* aProtoBinding,
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::MutableHandle<JSObject*> aClassObject,
|
|
|
|
bool* aNew)
|
2000-03-31 07:13:43 +04:00
|
|
|
{
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 20:46:42 +04:00
|
|
|
// First ensure our JS class is initialized.
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString className(aClassName);
|
2012-12-12 19:10:02 +04:00
|
|
|
nsAutoCString xblKey(aClassName);
|
2010-09-23 04:34:20 +04:00
|
|
|
|
2014-03-19 20:35:45 +04:00
|
|
|
// Note that, now that NAC reflectors are created in the XBL scope, the
|
|
|
|
// reflector is not necessarily same-compartment with the document. So we'll
|
|
|
|
// end up creating a separate instance of the oddly-named XBL class object
|
|
|
|
// and defining it as a property on the XBL scope's global. This works fine,
|
|
|
|
// but we need to make sure never to assume that the the reflector and
|
|
|
|
// prototype are same-compartment with the bound document.
|
|
|
|
JS::RootedObject global(cx, js::GetGlobalForObjectCrossCompartment(obj));
|
2012-08-22 05:42:53 +04:00
|
|
|
JSAutoCompartment ac(cx, global);
|
2013-04-05 17:21:01 +04:00
|
|
|
|
|
|
|
JS::Rooted<JSObject*> parent_proto(cx, nullptr);
|
2012-12-12 19:10:02 +04:00
|
|
|
nsXBLJSClass* c = nullptr;
|
2004-09-14 17:33:54 +04:00
|
|
|
if (obj) {
|
|
|
|
// Retrieve the current prototype of obj.
|
2013-07-31 20:20:33 +04:00
|
|
|
if (!JS_GetPrototype(cx, obj, &parent_proto)) {
|
2012-09-04 03:42:17 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2004-09-14 17:33:54 +04:00
|
|
|
if (parent_proto) {
|
|
|
|
// We need to create a unique classname based on aClassName and
|
2012-12-12 19:10:02 +04:00
|
|
|
// id. Append a space (an invalid URI character) to ensure that
|
2004-09-14 17:33:54 +04:00
|
|
|
// we don't have accidental collisions with the case when parent_proto is
|
|
|
|
// null and aClassName ends in some bizarre numbers (yeah, it's unlikely).
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::Rooted<jsid> parent_proto_id(cx);
|
2014-02-21 01:38:57 +04:00
|
|
|
if (!::JS_GetObjectId(cx, parent_proto, &parent_proto_id)) {
|
2004-09-14 17:33:54 +04:00
|
|
|
// Probably OOM
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2004-01-06 02:19:58 +03:00
|
|
|
|
2004-09-14 17:33:54 +04:00
|
|
|
// One space, maybe "0x", at most 16 chars (on a 64-bit system) of long,
|
|
|
|
// and a null-terminator (which PR_snprintf ensures is there even if the
|
|
|
|
// string representation of what we're printing does not fit in the buffer
|
|
|
|
// provided).
|
|
|
|
char buf[20];
|
2012-12-12 19:10:02 +04:00
|
|
|
if (sizeof(jsid) == 4) {
|
2013-04-05 17:21:01 +04:00
|
|
|
PR_snprintf(buf, sizeof(buf), " %lx", parent_proto_id.get());
|
2012-12-12 19:10:02 +04:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(sizeof(jsid) == 8);
|
2013-04-05 17:21:01 +04:00
|
|
|
PR_snprintf(buf, sizeof(buf), " %llx", parent_proto_id.get());
|
2012-12-12 19:10:02 +04:00
|
|
|
}
|
|
|
|
xblKey.Append(buf);
|
|
|
|
|
2013-09-11 16:49:04 +04:00
|
|
|
c = nsXBLService::getClass(xblKey);
|
2012-12-12 19:10:02 +04:00
|
|
|
if (c) {
|
|
|
|
className.Assign(c->name);
|
|
|
|
} else {
|
|
|
|
char buf[20];
|
|
|
|
PR_snprintf(buf, sizeof(buf), " %llx", nsXBLJSClass::NewId());
|
|
|
|
className.Append(buf);
|
|
|
|
}
|
2004-09-14 17:33:54 +04:00
|
|
|
}
|
2004-01-06 02:19:58 +03:00
|
|
|
}
|
|
|
|
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::Rooted<JSObject*> proto(cx);
|
|
|
|
JS::Rooted<JS::Value> val(cx);
|
|
|
|
|
2013-08-02 16:15:39 +04:00
|
|
|
if (!::JS_LookupPropertyWithFlags(cx, global, className.get(), 0, &val))
|
2013-04-05 17:21:01 +04:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
if (val.isObject()) {
|
|
|
|
*aNew = false;
|
|
|
|
proto = &val.toObject();
|
|
|
|
} else {
|
2000-05-27 12:20:04 +04:00
|
|
|
// We need to initialize the class.
|
2013-02-08 18:24:20 +04:00
|
|
|
*aNew = true;
|
Landing the XPCDOM_20010329_BRANCH branch, changes mostly done by jband@netscape.com and jst@netscape.com, also some changes done by shaver@mozilla.org, peterv@netscape.com and markh@activestate.com. r= and sr= by vidur@netscape.com, jband@netscape.com, jst@netscpae.com, danm@netscape.com, hyatt@netscape.com, shaver@mozilla.org, dbradley@netscape.com, rpotts@netscape.com.
2001-05-08 20:46:42 +04:00
|
|
|
|
2012-12-12 19:10:02 +04:00
|
|
|
if (!c) {
|
2014-03-19 01:25:39 +04:00
|
|
|
c = nsXBLService::getClass(xblKey);
|
2012-12-12 19:10:02 +04:00
|
|
|
}
|
|
|
|
if (c) {
|
2013-08-22 10:34:44 +04:00
|
|
|
// If c is on the LRU list, remove it now!
|
|
|
|
if (c->isInList()) {
|
|
|
|
c->remove();
|
2000-07-01 06:36:18 +04:00
|
|
|
nsXBLService::gClassLRUListLength--;
|
|
|
|
}
|
|
|
|
} else {
|
2013-08-22 10:34:44 +04:00
|
|
|
if (nsXBLService::gClassLRUList->isEmpty()) {
|
2000-07-01 06:36:18 +04:00
|
|
|
// We need to create a struct for this class.
|
2012-12-12 19:10:02 +04:00
|
|
|
c = new nsXBLJSClass(className, xblKey);
|
2000-07-01 06:36:18 +04:00
|
|
|
} else {
|
|
|
|
// Pull the least recently used class struct off the list.
|
2013-08-22 10:34:44 +04:00
|
|
|
c = nsXBLService::gClassLRUList->popFirst();
|
2000-07-01 06:36:18 +04:00
|
|
|
nsXBLService::gClassLRUListLength--;
|
|
|
|
|
|
|
|
// Remove any mapping from the old name to the class struct.
|
2014-03-19 01:25:39 +04:00
|
|
|
nsXBLService::gClassTable->Remove(c->Key());
|
2000-07-01 06:36:18 +04:00
|
|
|
|
|
|
|
// Change the class name and we're done.
|
2000-08-19 21:07:46 +04:00
|
|
|
nsMemory::Free((void*) c->name);
|
2004-01-06 02:19:58 +03:00
|
|
|
c->name = ToNewCString(className);
|
2012-12-12 19:10:02 +04:00
|
|
|
c->SetKey(xblKey);
|
2000-07-01 06:36:18 +04:00
|
|
|
}
|
2000-05-27 12:20:04 +04:00
|
|
|
|
|
|
|
// Add c to our table.
|
2014-03-19 01:25:39 +04:00
|
|
|
nsXBLService::gClassTable->Put(xblKey, c);
|
2000-05-27 12:20:04 +04:00
|
|
|
}
|
2002-06-22 00:55:17 +04:00
|
|
|
|
|
|
|
// The prototype holds a strong reference to its class struct.
|
|
|
|
c->Hold();
|
2000-07-01 06:36:18 +04:00
|
|
|
|
|
|
|
// Make a new object prototyped by parent_proto and parented by global.
|
2002-06-22 00:55:17 +04:00
|
|
|
proto = ::JS_InitClass(cx, // context
|
2000-07-01 06:36:18 +04:00
|
|
|
global, // global object
|
2014-03-19 01:25:39 +04:00
|
|
|
parent_proto, // parent proto
|
2000-07-01 06:36:18 +04:00
|
|
|
c, // JSClass
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr, // JSNative ctor
|
2000-07-01 06:36:18 +04:00
|
|
|
0, // ctor args
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr, // proto props
|
|
|
|
nullptr, // proto funcs
|
|
|
|
nullptr, // ctor props (static)
|
|
|
|
nullptr); // ctor funcs (static)
|
2000-07-01 06:36:18 +04:00
|
|
|
if (!proto) {
|
2002-06-22 00:55:17 +04:00
|
|
|
// This will happen if we're OOM or if the security manager
|
|
|
|
// denies defining the new class...
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
nsXBLService::gClassTable->Remove(xblKey);
|
2002-06-22 00:55:17 +04:00
|
|
|
|
|
|
|
c->Drop();
|
|
|
|
|
2000-07-01 06:36:18 +04:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2000-03-31 07:13:43 +04:00
|
|
|
}
|
|
|
|
|
2007-09-28 17:45:01 +04:00
|
|
|
// Keep this proto binding alive while we're alive. Do this first so that
|
|
|
|
// we can guarantee that in XBLFinalize this will be non-null.
|
2010-09-15 23:40:11 +04:00
|
|
|
// Note that we can't just store aProtoBinding in the private and
|
|
|
|
// addref/release the nsXBLDocumentInfo through it, because cycle
|
|
|
|
// collection doesn't seem to work right if the private is not an
|
|
|
|
// nsISupports.
|
2010-07-15 05:53:11 +04:00
|
|
|
nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
|
2012-02-06 00:07:23 +04:00
|
|
|
::JS_SetPrivate(proto, docInfo);
|
2007-09-28 17:45:01 +04:00
|
|
|
NS_ADDREF(docInfo);
|
|
|
|
|
2012-02-06 00:07:23 +04:00
|
|
|
::JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
|
2000-03-31 07:13:43 +04:00
|
|
|
}
|
|
|
|
|
2013-04-05 17:21:01 +04:00
|
|
|
aClassObject.set(proto);
|
2013-02-08 18:24:20 +04:00
|
|
|
|
2004-09-14 17:33:54 +04:00
|
|
|
if (obj) {
|
|
|
|
// Set the prototype of our object to be the new class.
|
|
|
|
if (!::JS_SetPrototype(cx, obj, proto)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2002-06-22 00:55:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2000-05-19 08:48:43 +04:00
|
|
|
nsXBLBinding::AllowScripts()
|
|
|
|
{
|
2013-12-17 20:46:33 +04:00
|
|
|
return mBoundElement && mPrototypeBinding->GetAllowScripts();
|
2000-05-19 08:48:43 +04:00
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
nsXBLBinding*
|
|
|
|
nsXBLBinding::RootBinding()
|
2000-06-02 12:13:29 +04:00
|
|
|
{
|
|
|
|
if (mNextBinding)
|
2005-02-26 01:07:01 +03:00
|
|
|
return mNextBinding->RootBinding();
|
2000-06-02 12:13:29 +04:00
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
return this;
|
2000-06-02 12:13:29 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2013-04-05 17:21:03 +04:00
|
|
|
nsXBLBinding::ResolveAllFields(JSContext *cx, JS::Handle<JSObject*> obj) const
|
2007-09-28 17:45:01 +04:00
|
|
|
{
|
|
|
|
if (!mPrototypeBinding->ResolveAllFields(cx, obj)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2007-09-28 17:45:01 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mNextBinding) {
|
|
|
|
return mNextBinding->ResolveAllFields(cx, obj);
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2007-09-28 17:45:01 +04:00
|
|
|
}
|
|
|
|
|
2013-02-08 18:24:21 +04:00
|
|
|
bool
|
2013-11-11 12:04:41 +04:00
|
|
|
nsXBLBinding::LookupMember(JSContext* aCx, JS::Handle<jsid> aId,
|
2013-08-12 15:09:14 +04:00
|
|
|
JS::MutableHandle<JSPropertyDescriptor> aDesc)
|
2013-02-08 18:24:21 +04:00
|
|
|
{
|
|
|
|
// We should never enter this function with a pre-filled property descriptor.
|
2013-08-12 15:09:14 +04:00
|
|
|
MOZ_ASSERT(!aDesc.object());
|
2013-02-08 18:24:21 +04:00
|
|
|
|
|
|
|
// Get the string as an nsString before doing anything, so we can make
|
|
|
|
// convenient comparisons during our search.
|
|
|
|
if (!JSID_IS_STRING(aId)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
nsDependentJSString name(aId);
|
|
|
|
|
|
|
|
// We have a weak reference to our bound element, so make sure it's alive.
|
|
|
|
if (!mBoundElement || !mBoundElement->GetWrapper()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-13 22:16:19 +04:00
|
|
|
// Get the scope of mBoundElement and the associated XBL scope. We should only
|
|
|
|
// be calling into this machinery if we're running in a separate XBL scope.
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::Rooted<JSObject*> boundScope(aCx,
|
|
|
|
js::GetGlobalForObjectCrossCompartment(mBoundElement->GetWrapper()));
|
|
|
|
JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope));
|
2013-04-05 23:04:09 +04:00
|
|
|
NS_ENSURE_TRUE(xblScope, false);
|
2013-02-13 22:16:19 +04:00
|
|
|
MOZ_ASSERT(boundScope != xblScope);
|
2013-02-08 18:24:21 +04:00
|
|
|
|
2013-02-13 22:16:19 +04:00
|
|
|
// Enter the xbl scope and invoke the internal version.
|
2013-02-08 18:24:21 +04:00
|
|
|
{
|
2013-02-13 22:16:19 +04:00
|
|
|
JSAutoCompartment ac(aCx, xblScope);
|
2013-11-11 12:04:41 +04:00
|
|
|
JS::Rooted<jsid> id(aCx, aId);
|
2013-02-08 18:24:21 +04:00
|
|
|
if (!JS_WrapId(aCx, id.address()) ||
|
2013-02-13 22:16:19 +04:00
|
|
|
!LookupMemberInternal(aCx, name, id, aDesc, xblScope))
|
2013-02-08 18:24:21 +04:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap into the caller's scope.
|
|
|
|
return JS_WrapPropertyDescriptor(aCx, aDesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsXBLBinding::LookupMemberInternal(JSContext* aCx, nsString& aName,
|
2013-11-11 12:04:41 +04:00
|
|
|
JS::Handle<jsid> aNameAsId,
|
2013-08-12 15:09:14 +04:00
|
|
|
JS::MutableHandle<JSPropertyDescriptor> aDesc,
|
2013-04-05 17:21:01 +04:00
|
|
|
JS::Handle<JSObject*> aXBLScope)
|
2013-02-08 18:24:21 +04:00
|
|
|
{
|
|
|
|
// First, see if we have a JSClass. If we don't, it means that this binding
|
|
|
|
// doesn't have a class object, and thus doesn't have any members. Skip it.
|
|
|
|
if (!mJSClass) {
|
|
|
|
if (!mNextBinding) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId,
|
2013-02-13 22:16:19 +04:00
|
|
|
aDesc, aXBLScope);
|
2013-02-08 18:24:21 +04:00
|
|
|
}
|
|
|
|
|
2013-02-13 22:16:19 +04:00
|
|
|
// Find our class object. It's in a protected scope and permanent just in case,
|
|
|
|
// so should be there no matter what.
|
2013-11-11 12:04:41 +04:00
|
|
|
JS::Rooted<JS::Value> classObject(aCx);
|
2013-07-26 13:00:38 +04:00
|
|
|
if (!JS_GetProperty(aCx, aXBLScope, mJSClass->name, &classObject)) {
|
2013-02-08 18:24:21 +04:00
|
|
|
return false;
|
|
|
|
}
|
2013-07-17 20:05:03 +04:00
|
|
|
|
|
|
|
// The bound element may have been adoped by a document and have a different
|
|
|
|
// wrapper (and different xbl scope) than when the binding was applied, in
|
|
|
|
// this case getting the class object will fail. Behave as if the class
|
|
|
|
// object did not exist.
|
|
|
|
if (classObject.isUndefined()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-08 18:24:21 +04:00
|
|
|
MOZ_ASSERT(classObject.isObject());
|
|
|
|
|
|
|
|
// Look for the property on this binding. If it's not there, try the next
|
|
|
|
// binding on the chain.
|
|
|
|
nsXBLProtoImpl* impl = mPrototypeBinding->GetImplementation();
|
2014-03-17 20:17:58 +04:00
|
|
|
JS::Rooted<JSObject*> object(aCx, &classObject.toObject());
|
|
|
|
if (impl && !impl->LookupMember(aCx, aName, aNameAsId, aDesc, object)) {
|
2013-02-08 18:24:21 +04:00
|
|
|
return false;
|
|
|
|
}
|
2013-08-12 15:09:14 +04:00
|
|
|
if (aDesc.object() || !mNextBinding) {
|
2013-02-08 18:24:21 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mNextBinding->LookupMemberInternal(aCx, aName, aNameAsId, aDesc,
|
2013-02-13 22:16:19 +04:00
|
|
|
aXBLScope);
|
2013-02-08 18:24:21 +04:00
|
|
|
}
|
|
|
|
|
2013-02-08 18:24:22 +04:00
|
|
|
bool
|
|
|
|
nsXBLBinding::HasField(nsString& aName)
|
|
|
|
{
|
|
|
|
// See if this binding has such a field.
|
|
|
|
return mPrototypeBinding->FindField(aName) ||
|
|
|
|
(mNextBinding && mNextBinding->HasField(aName));
|
|
|
|
}
|
|
|
|
|
2005-02-26 01:07:01 +03:00
|
|
|
void
|
2000-08-14 08:04:18 +04:00
|
|
|
nsXBLBinding::MarkForDeath()
|
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
mMarkedForDeath = true;
|
2000-09-28 00:23:49 +04:00
|
|
|
ExecuteDetachedHandler();
|
2000-08-14 08:04:18 +04:00
|
|
|
}
|
2000-06-02 12:13:29 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2005-02-26 01:07:01 +03:00
|
|
|
nsXBLBinding::ImplementsInterface(REFNSIID aIID) const
|
2000-12-07 13:11:21 +03:00
|
|
|
{
|
2005-02-26 01:07:01 +03:00
|
|
|
return mPrototypeBinding->ImplementsInterface(aIID) ||
|
|
|
|
(mNextBinding && mNextBinding->ImplementsInterface(aIID));
|
2000-12-07 13:11:21 +03:00
|
|
|
}
|