Bug 1593119 - Remove dom/xbl and the MOZ_XBL build option r=bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D51338

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Brian Grinstead 2019-11-07 00:35:32 +00:00
parent 8e592888cb
commit d981495450
96 changed files with 1 additions and 13058 deletions

View File

@ -236,7 +236,6 @@ module.exports = {
"dom/websocket/**",
"dom/workers/**",
"dom/worklet/**",
"dom/xbl/**",
"dom/xml/**",
"dom/xslt/**",
"dom/xul/**",

View File

@ -525,9 +525,6 @@ LOCAL_INCLUDES += [
'/xpcom/ds',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
if CONFIG['MOZ_WEBRTC']:
LOCAL_INCLUDES += [
'/netwerk/sctp/datachannel',

View File

@ -93,9 +93,6 @@ LOCAL_INCLUDES += [
'/media/webrtc/trunk/',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
LOCAL_INCLUDES += ['/third_party/msgpack/include']
DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True

View File

@ -253,9 +253,6 @@ LOCAL_INCLUDES += [
'/netwerk/base',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:

View File

@ -108,11 +108,6 @@ DIRS += [
'l10n',
]
if CONFIG['MOZ_XBL']:
DIRS += ['xbl']
else:
EXPORTS += ['xbl/stub/nsXBLBinding.h']
if CONFIG['OS_ARCH'] == 'WINNT':
DIRS += ['plugins/ipc/hangui']

View File

@ -20,9 +20,6 @@ LOCAL_INCLUDES += [
'/dom/xul',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
FINAL_LIBRARY = 'xul'

View File

@ -259,8 +259,5 @@ LOCAL_INCLUDES += [
'/layout/xul',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

View File

@ -1,177 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/dom/XBLChildrenElement.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/NodeListBinding.h"
#include "nsAttrValueOrString.h"
#include "nsCharSeparatedTokenizer.h"
namespace mozilla {
namespace dom {
XBLChildrenElement::~XBLChildrenElement() {}
NS_IMPL_ELEMENT_CLONE(XBLChildrenElement)
nsresult XBLChildrenElement::BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) {
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::includes) {
mIncludes.Clear();
if (aValue) {
nsCharSeparatedTokenizer tok(
aValue->String(), '|',
nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
while (tok.hasMoreTokens()) {
mIncludes.AppendElement(NS_Atomize(tok.nextToken()));
}
}
}
}
return nsXMLElement::BeforeSetAttr(aNamespaceID, aName, aValue, aNotify);
}
void XBLChildrenElement::DoRemoveDefaultContent(bool aNotify) {
// Default content is going away, need to tell layout about it first.
MOZ_ASSERT(HasChildren(), "Why bothering?");
MOZ_ASSERT(GetParentElement());
// We don't want to do this from frame construction while setting up the
// binding initially.
if (aNotify) {
Element* parent = GetParentElement();
if (Document* doc = parent->GetComposedDoc()) {
if (PresShell* presShell = doc->GetPresShell()) {
presShell->DestroyFramesForAndRestyle(parent);
}
}
}
for (nsIContent* child = static_cast<nsINode*>(this)->GetFirstChild(); child;
child = child->GetNextSibling()) {
MOZ_ASSERT(!child->GetPrimaryFrame());
MOZ_ASSERT(!child->IsElement() || !child->AsElement()->HasServoData());
child->SetXBLInsertionPoint(nullptr);
}
}
} // namespace dom
} // namespace mozilla
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList)
NS_INTERFACE_TABLE_HEAD(nsAnonymousContentList)
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(nsAnonymousContentList, nsINodeList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsAnonymousContentList)
NS_INTERFACE_MAP_END
uint32_t nsAnonymousContentList::Length() {
if (!mParent) {
return 0;
}
uint32_t count = 0;
for (nsIContent* child = mParent->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child);
if (point->HasInsertedChildren()) {
count += point->InsertedChildrenLength();
} else {
count += point->GetChildCount();
}
} else {
++count;
}
}
return count;
}
nsIContent* nsAnonymousContentList::Item(uint32_t aIndex) {
if (!mParent) {
return nullptr;
}
uint32_t remIndex = aIndex;
for (nsIContent* child = mParent->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child);
if (point->HasInsertedChildren()) {
if (remIndex < point->InsertedChildrenLength()) {
return point->InsertedChild(remIndex);
}
remIndex -= point->InsertedChildrenLength();
} else {
if (remIndex < point->GetChildCount()) {
return point->GetChildAt_Deprecated(remIndex);
}
remIndex -= point->GetChildCount();
}
} else {
if (remIndex == 0) {
return child;
}
--remIndex;
}
}
return nullptr;
}
int32_t nsAnonymousContentList::IndexOf(nsIContent* aContent) {
NS_ASSERTION(
!aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL),
"Looking for insertion point");
if (!mParent) {
return -1;
}
int32_t index = 0;
for (nsIContent* child = mParent->GetFirstChild(); child;
child = child->GetNextSibling()) {
if (child->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
XBLChildrenElement* point = static_cast<XBLChildrenElement*>(child);
if (point->HasInsertedChildren()) {
int32_t insIndex = point->IndexOfInsertedChild(aContent);
if (insIndex != -1) {
return index + insIndex;
}
index += point->InsertedChildrenLength();
} else {
int32_t insIndex = point->ComputeIndexOf(aContent);
if (insIndex != -1) {
return index + insIndex;
}
index += point->GetChildCount();
}
} else {
if (child == aContent) {
return index;
}
++index;
}
}
return -1;
}
JSObject* nsAnonymousContentList::WrapObject(
JSContext* cx, JS::Handle<JSObject*> aGivenProto) {
return mozilla::dom::NodeList_Binding::Wrap(cx, this, aGivenProto);
}

View File

@ -1,155 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLChildrenElement_h___
#define nsXBLChildrenElement_h___
#include "nsINodeList.h"
#include "nsBindingManager.h"
#include "mozilla/dom/nsXMLElement.h"
class nsAnonymousContentList;
namespace mozilla {
namespace dom {
class XBLChildrenElement : public nsXMLElement {
public:
explicit XBLChildrenElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: nsXMLElement(std::move(aNodeInfo)) {}
// nsISupports
NS_INLINE_DECL_REFCOUNTING_INHERITED(XBLChildrenElement, nsXMLElement)
// nsINode interface methods
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
void AppendInsertedChild(nsIContent* aChild, bool aNotify) {
// Appending an inserted child causes the inserted
// children to be projected instead of default content.
MaybeRemoveDefaultContent(aNotify);
mInsertedChildren.AppendElement(aChild);
aChild->SetXBLInsertionPoint(this);
}
void InsertInsertedChildAt(nsIContent* aChild, uint32_t aIndex) {
// Inserting an inserted child causes the inserted
// children to be projected instead of default content.
MaybeRemoveDefaultContent(true);
mInsertedChildren.InsertElementAt(aIndex, aChild);
aChild->SetXBLInsertionPoint(this);
}
void RemoveInsertedChild(nsIContent* aChild) {
// Can't use this assertion as we cheat for dynamic insertions and
// only insert in the innermost insertion point.
// NS_ASSERTION(mInsertedChildren.Contains(aChild),
// "Removing child that's not there");
mInsertedChildren.RemoveElement(aChild);
// After removing the inserted child, default content
// may be projected into this insertion point.
//
// FIXME: Layout should be told about this before clearing
// mInsertedChildren, this leaves stale styles and frames in the frame tree.
MaybeSetupDefaultContent();
}
void ClearInsertedChildren() {
for (auto* child : mInsertedChildren) {
if (child->GetXBLInsertionPoint() == this) {
child->SetXBLInsertionPoint(nullptr);
}
}
mInsertedChildren.Clear();
// After clearing inserted children, default content
// will be projected into this insertion point.
//
// FIXME: Layout should be told about this before clearing
// mInsertedChildren, this leaves stale styles and frames in the frame tree.
MaybeSetupDefaultContent();
}
void MaybeSetupDefaultContent() {
if (!HasInsertedChildren()) {
for (nsIContent* child = static_cast<nsINode*>(this)->GetFirstChild();
child; child = child->GetNextSibling()) {
child->SetXBLInsertionPoint(this);
}
}
}
void MaybeRemoveDefaultContent(bool aNotify) {
if (!HasInsertedChildren() && HasChildren()) {
DoRemoveDefaultContent(aNotify);
}
}
uint32_t InsertedChildrenLength() { return mInsertedChildren.Length(); }
bool HasInsertedChildren() { return !mInsertedChildren.IsEmpty(); }
int32_t IndexOfInsertedChild(nsIContent* aChild) {
return mInsertedChildren.IndexOf(aChild);
}
bool Includes(nsIContent* aChild) {
NS_ASSERTION(!mIncludes.IsEmpty(),
"Shouldn't check for includes on default insertion point");
return mIncludes.Contains(aChild->NodeInfo()->NameAtom());
}
bool IsDefaultInsertion() { return mIncludes.IsEmpty(); }
nsIContent* InsertedChild(uint32_t aIndex) {
return mInsertedChildren[aIndex];
}
protected:
~XBLChildrenElement();
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) override;
void DoRemoveDefaultContent(bool aNotify);
private:
nsTArray<nsIContent*> mInsertedChildren; // WEAK
nsTArray<RefPtr<nsAtom> > mIncludes;
};
} // namespace dom
} // namespace mozilla
class nsAnonymousContentList final : public nsINodeList {
public:
explicit nsAnonymousContentList(nsIContent* aParent) : mParent(aParent) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsAnonymousContentList)
// nsINodeList interface
virtual int32_t IndexOf(nsIContent* aContent) override;
virtual nsINode* GetParentObject() override { return mParent; }
virtual nsIContent* Item(uint32_t aIndex) override;
uint32_t Length() override;
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override;
bool IsListFor(nsIContent* aContent) { return mParent == aContent; }
private:
virtual ~nsAnonymousContentList() {}
nsCOMPtr<nsIContent> mParent;
};
#endif // nsXBLChildrenElement_h___

View File

@ -1,54 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
with Files("**"):
BUG_COMPONENT = ("Core", "XBL")
EXPORTS += [
'nsBindingManager.h',
'nsXBLBinding.h',
'nsXBLPrototypeHandler.h',
'nsXBLService.h',
]
EXPORTS.mozilla.dom += [
'XBLChildrenElement.h',
]
UNIFIED_SOURCES += [
'nsBindingManager.cpp',
'nsXBLBinding.cpp',
'nsXBLContentSink.cpp',
'nsXBLDocumentInfo.cpp',
'nsXBLEventHandler.cpp',
'nsXBLProtoImpl.cpp',
'nsXBLProtoImplField.cpp',
'nsXBLProtoImplMethod.cpp',
'nsXBLProtoImplProperty.cpp',
'nsXBLPrototypeBinding.cpp',
'nsXBLPrototypeHandler.cpp',
'nsXBLSerialize.cpp',
'nsXBLService.cpp',
'XBLChildrenElement.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
'/dom/html',
'/dom/xml',
'/dom/xul',
'/layout/style',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

View File

@ -1,876 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsBindingManager.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsXBLService.h"
#include "nsIInputStream.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsString.h"
#include "plstr.h"
#include "nsIContent.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
#include "nsContentUtils.h"
#include "nsIXMLContentSink.h"
#include "nsContentCID.h"
#include "mozilla/dom/XMLDocument.h"
#include "nsIStreamListener.h"
#include "ChildIterator.h"
#include "nsITimer.h"
#include "nsXBLBinding.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLDocumentInfo.h"
#include "mozilla/dom/XBLChildrenElement.h"
#ifdef MOZ_XUL
# include "nsXULPrototypeCache.h"
#endif
#include "nsIWeakReference.h"
#include "nsWrapperCacheInlines.h"
#include "nsIXPConnect.h"
#include "nsDOMCID.h"
#include "nsIScriptGlobalObject.h"
#include "nsTHashtable.h"
#include "nsIScriptContext.h"
#include "xpcpublic.h"
#include "js/Wrapper.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/NodeListBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/Unused.h"
using namespace mozilla;
using namespace mozilla::dom;
// Implement our nsISupports methods
NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
tmp->mDestroyed = true;
if (tmp->mBoundContentSet) tmp->mBoundContentSet->Clear();
if (tmp->mDocumentTable) tmp->mDocumentTable->Clear();
if (tmp->mLoadingDocTable) tmp->mLoadingDocTable->Clear();
if (tmp->mWrapperTable) {
tmp->mWrapperTable->Clear();
tmp->mWrapperTable = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttachedStack)
if (tmp->mProcessAttachedQueueEvent) {
tmp->mProcessAttachedQueueEvent->Revoke();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
// The hashes keyed on nsIContent are traversed from the nsIContent itself.
if (tmp->mDocumentTable) {
for (auto iter = tmp->mDocumentTable->Iter(); !iter.Done(); iter.Next()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocumentTable value");
cb.NoteXPCOMChild(iter.UserData());
}
}
if (tmp->mLoadingDocTable) {
for (auto iter = tmp->mLoadingDocTable->Iter(); !iter.Done(); iter.Next()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mLoadingDocTable value");
cb.NoteXPCOMChild(iter.UserData());
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack)
// No need to traverse mProcessAttachedQueueEvent, since it'll just
// fire at some point or become revoke and drop its ref to us.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBindingManager)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBindingManager)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBindingManager)
// Constructors/Destructors
nsBindingManager::nsBindingManager(Document* aDocument)
: mProcessingAttachedStack(false),
mDestroyed(false),
mAttachedStackSizeOnOutermost(0),
mDocument(aDocument) {}
nsBindingManager::~nsBindingManager(void) { mDestroyed = true; }
nsXBLBinding* nsBindingManager::GetBindingWithContent(
const nsIContent* aContent) {
nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr;
return binding ? binding->GetBindingWithContent() : nullptr;
}
void nsBindingManager::AddBoundContent(nsIContent* aContent) {
if (!mBoundContentSet) {
mBoundContentSet = new nsTHashtable<nsRefPtrHashKey<nsIContent>>;
}
mBoundContentSet->PutEntry(aContent);
}
void nsBindingManager::RemoveBoundContent(nsIContent* aContent) {
if (mBoundContentSet) {
mBoundContentSet->RemoveEntry(aContent);
}
// The death of the bindings means the death of the JS wrapper.
SetWrappedJS(aContent, nullptr);
}
nsIXPConnectWrappedJS* nsBindingManager::GetWrappedJS(nsIContent* aContent) {
if (!mWrapperTable) {
return nullptr;
}
if (!aContent || !aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
return nullptr;
}
return mWrapperTable->GetWeak(aContent);
}
nsresult nsBindingManager::SetWrappedJS(nsIContent* aContent,
nsIXPConnectWrappedJS* aWrappedJS) {
if (mDestroyed) {
return NS_OK;
}
if (aWrappedJS) {
// lazily create the table, but only when adding elements
if (!mWrapperTable) {
mWrapperTable = new WrapperHashtable();
}
aContent->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
NS_ASSERTION(aContent, "key must be non-null");
if (!aContent) return NS_ERROR_INVALID_ARG;
mWrapperTable->Put(aContent, aWrappedJS);
return NS_OK;
}
// no value, so remove the key from the table
if (mWrapperTable) {
mWrapperTable->Remove(aContent);
}
return NS_OK;
}
void nsBindingManager::RemovedFromDocumentInternal(
nsIContent* aContent, Document* aOldDocument,
DestructorHandling aDestructorHandling) {
MOZ_ASSERT(aOldDocument != nullptr, "no old document");
RefPtr<nsXBLBinding> binding = aContent->GetXBLBinding();
if (binding) {
// The binding manager may have been destroyed before a runnable
// has had a chance to reach this point. If so, we bail out on calling
// BindingDetached (which may invoke a XBL destructor) and
// ChangeDocument, but we still want to clear out the binding
// and insertion parent that may hold references.
if (!mDestroyed && aDestructorHandling == eRunDtor) {
binding->PrototypeBinding()->BindingDetached(binding->GetBoundElement());
binding->ChangeDocument(aOldDocument, nullptr);
}
aContent->AsElement()->SetXBLBinding(nullptr, this);
}
// Clear out insertion point and content lists.
aContent->SetXBLInsertionPoint(nullptr);
}
nsINodeList* nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent) {
nsXBLBinding* binding = GetBindingWithContent(aContent);
return binding ? binding->GetAnonymousNodeList() : nullptr;
}
nsresult nsBindingManager::ClearBinding(Element* aElement) {
// Hold a ref to the binding so it won't die when we remove it from our table
RefPtr<nsXBLBinding> binding = aElement ? aElement->GetXBLBinding() : nullptr;
if (!binding) {
return NS_OK;
}
// For now we can only handle removing a binding if it's the only one
NS_ENSURE_FALSE(binding->GetBaseBinding(), NS_ERROR_FAILURE);
// Hold strong ref in case removing the binding tries to close the
// window or something.
// XXXbz should that be ownerdoc? Wouldn't we need a ref to the
// currentdoc too? What's the one that should be passed to
// ChangeDocument?
nsCOMPtr<Document> doc = aElement->OwnerDoc();
// Destroy the frames here before the UnbindFromTree happens.
if (PresShell* presShell = doc->GetPresShell()) {
presShell->DestroyFramesForAndRestyle(aElement);
}
// Finally remove the binding...
// XXXbz this doesn't remove the implementation! Should fix! Until
// then we need the explicit UnhookEventHandlers here.
binding->UnhookEventHandlers();
binding->ChangeDocument(doc, nullptr);
aElement->SetXBLBinding(nullptr, this);
binding->MarkForDeath();
// ...and recreate its frames. We need to do this since the frames may have
// been removed and style may have changed due to the removal of the
// anonymous children.
// XXXbz this should be using the current doc (if any), not the owner doc.
// get the shell again, just in case it changed
PresShell* presShell = doc->GetPresShell();
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
presShell->PostRecreateFramesFor(aElement);
return NS_OK;
}
void nsBindingManager::RemoveFromAttachedQueue(nsXBLBinding* aBinding) {
// Don't remove items here as that could mess up an executing
// ProcessAttachedQueue. Instead, null the entry in the queue.
size_t index = mAttachedStack.IndexOf(aBinding);
if (index != nsBindingList::NoIndex) {
mAttachedStack[index] = nullptr;
}
}
nsresult nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding) {
mAttachedStack.AppendElement(aBinding);
// If we're in the middle of processing our queue already, don't
// bother posting the event.
if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) {
PostProcessAttachedQueueEvent();
}
// Make sure that flushes will flush out the new items as needed.
if (PresShell* presShell = mDocument->GetPresShell()) {
presShell->SetNeedStyleFlush();
}
return NS_OK;
}
void nsBindingManager::PostProcessAttachedQueueEvent() {
MOZ_ASSERT(NS_IsMainThread());
if (!mDocument) {
return;
}
mProcessAttachedQueueEvent =
NewRunnableMethod("nsBindingManager::DoProcessAttachedQueue", this,
&nsBindingManager::DoProcessAttachedQueue);
nsresult rv = mDocument->EventTargetFor(TaskCategory::Other)
->Dispatch(do_AddRef(mProcessAttachedQueueEvent));
if (NS_SUCCEEDED(rv)) {
mDocument->BlockOnload();
}
}
// static
void nsBindingManager::PostPAQEventCallback(nsITimer* aTimer, void* aClosure) {
RefPtr<nsBindingManager> mgr = already_AddRefed<nsBindingManager>(
static_cast<nsBindingManager*>(aClosure));
mgr->PostProcessAttachedQueueEvent();
NS_RELEASE(aTimer);
}
void nsBindingManager::DoProcessAttachedQueue() {
if (!mProcessingAttachedStack) {
ProcessAttachedQueue();
NS_ASSERTION(mAttachedStack.Length() == 0,
"Shouldn't have pending bindings!");
mProcessAttachedQueueEvent = nullptr;
} else {
// Someone's doing event processing from inside a constructor.
// They're evil, but we'll fight back! Just poll on them being
// done and repost the attached queue event.
//
// But don't poll in a tight loop -- otherwise we keep the Gecko
// event loop non-empty and trigger bug 1021240 on OS X.
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsITimer> timer;
rv = NS_NewTimerWithFuncCallback(
getter_AddRefs(timer), PostPAQEventCallback, this, 100,
nsITimer::TYPE_ONE_SHOT, "nsBindingManager::DoProcessAttachedQueue");
if (NS_SUCCEEDED(rv)) {
NS_ADDREF_THIS();
// We drop our reference to the timer here, since the timer callback is
// responsible for releasing the object.
Unused << timer.forget().take();
}
}
// No matter what, unblock onload for the event that's fired.
if (mDocument) {
// Hold a strong reference while calling UnblockOnload since that might
// run script.
nsCOMPtr<Document> doc = mDocument;
doc->UnblockOnload(true);
}
}
void nsBindingManager::ProcessAttachedQueueInternal(uint32_t aSkipSize) {
mProcessingAttachedStack = true;
// Excute constructors. Do this from high index to low
while (mAttachedStack.Length() > aSkipSize) {
uint32_t lastItem = mAttachedStack.Length() - 1;
RefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem);
mAttachedStack.RemoveElementAt(lastItem);
if (binding) {
binding->ExecuteAttachedHandler();
}
}
// If NodeWillBeDestroyed has run we don't want to clobber
// mProcessingAttachedStack set there.
if (mDocument) {
mProcessingAttachedStack = false;
}
NS_ASSERTION(mAttachedStack.Length() == aSkipSize, "How did we get here?");
mAttachedStack.Compact();
}
// Keep bindings and bound elements alive while executing detached handlers.
void nsBindingManager::ExecuteDetachedHandlers() {
// Walk our hashtable of bindings.
if (!mBoundContentSet) {
return;
}
nsCOMArray<nsIContent> boundElements;
nsBindingList bindings;
for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
nsXBLBinding* binding = iter.Get()->GetKey()->GetXBLBinding();
if (binding && bindings.AppendElement(binding)) {
if (!boundElements.AppendObject(binding->GetBoundElement())) {
bindings.RemoveLastElement();
}
}
}
uint32_t i, count = bindings.Length();
for (i = 0; i < count; ++i) {
bindings[i]->ExecuteDetachedHandler();
}
}
nsresult nsBindingManager::PutXBLDocumentInfo(
nsXBLDocumentInfo* aDocumentInfo) {
MOZ_ASSERT(aDocumentInfo, "Must have a non-null documentinfo!");
if (!mDocumentTable) {
mDocumentTable = new nsRefPtrHashtable<nsURIHashKey, nsXBLDocumentInfo>();
}
mDocumentTable->Put(aDocumentInfo->DocumentURI(), aDocumentInfo);
return NS_OK;
}
void nsBindingManager::RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo) {
if (mDocumentTable) {
mDocumentTable->Remove(aDocumentInfo->DocumentURI());
}
}
nsXBLDocumentInfo* nsBindingManager::GetXBLDocumentInfo(nsIURI* aURL) {
if (!mDocumentTable) return nullptr;
return mDocumentTable->GetWeak(aURL);
}
nsresult nsBindingManager::PutLoadingDocListener(nsIURI* aURL,
nsIStreamListener* aListener) {
MOZ_ASSERT(aListener, "Must have a non-null listener!");
if (!mLoadingDocTable) {
mLoadingDocTable =
new nsInterfaceHashtable<nsURIHashKey, nsIStreamListener>();
}
mLoadingDocTable->Put(aURL, aListener);
return NS_OK;
}
nsIStreamListener* nsBindingManager::GetLoadingDocListener(nsIURI* aURL) {
if (!mLoadingDocTable) return nullptr;
return mLoadingDocTable->GetWeak(aURL);
}
void nsBindingManager::RemoveLoadingDocListener(nsIURI* aURL) {
if (mLoadingDocTable) {
mLoadingDocTable->Remove(aURL);
}
}
// Used below to protect from recurring in QI calls through XPConnect.
struct AntiRecursionData {
nsIContent* element;
REFNSIID iid;
AntiRecursionData* next;
AntiRecursionData(nsIContent* aElement, REFNSIID aIID,
AntiRecursionData* aNext)
: element(aElement), iid(aIID), next(aNext) {}
};
nsresult nsBindingManager::GetBindingImplementation(nsIContent* aContent,
REFNSIID aIID,
void** aResult) {
*aResult = nullptr;
nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr;
if (binding) {
// The binding should not be asked for nsISupports
NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)),
"Asking a binding for nsISupports");
if (binding->ImplementsInterface(aIID)) {
nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = GetWrappedJS(aContent);
if (wrappedJS) {
// Protect from recurring in QI calls through XPConnect.
// This can happen when a second binding is being resolved.
// At that point a wrappedJS exists, but it doesn't yet know about
// the iid we are asking for. So, without this protection,
// AggregatedQueryInterface would end up recurring back into itself
// through this code.
//
// With this protection, when we detect the recursion we return
// NS_NOINTERFACE in the inner call. The outer call will then fall
// through (see below) and build a new chained wrappedJS for the iid.
//
// We're careful to not assume that only one direct nesting can occur
// because there is a call into JS in the middle and we can't assume
// that this code won't be reached by some more complex nesting path.
//
// NOTE: We *assume* this is single threaded, so we can use a
// static linked list to do the check.
static AntiRecursionData* list = nullptr;
for (AntiRecursionData* p = list; p; p = p->next) {
if (p->element == aContent && p->iid.Equals(aIID)) {
*aResult = nullptr;
return NS_NOINTERFACE;
}
}
AntiRecursionData item(aContent, aIID, list);
list = &item;
nsresult rv = wrappedJS->AggregatedQueryInterface(aIID, aResult);
list = item.next;
if (*aResult) return rv;
// No result was found, so this must be another XBL interface.
// Fall through to create a new wrapper.
}
// We have never made a wrapper for this implementation.
// Create an XPC wrapper for the script object and hand it back.
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
nsIXPConnect* xpConnect = nsContentUtils::XPConnect();
JS::Rooted<JSObject*> jsobj(cx, aContent->GetWrapper());
NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE);
// If we're using an XBL scope, we need to use the Xray view to the bound
// content in order to view the full array of methods defined in the
// binding, some of which may not be exposed on the prototype of
// untrusted content. We don't need to consider add-on scopes here
// because they're chrome-only and no Xrays are involved.
//
// If there's no separate XBL scope, or if the reflector itself lives in
// the XBL scope, we'll end up with the global of the reflector.
JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, jsobj));
NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
JSAutoRealm ar(cx, xblScope);
bool ok = JS_WrapObject(cx, &jsobj);
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj));
nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx, jsobj,
aIID, aResult);
if (NS_FAILED(rv)) return rv;
// We successfully created a wrapper. We will own this wrapper for as
// long as the binding remains alive. At the time the binding is cleared
// out of the bindingManager, we will remove the wrapper from the
// bindingManager as well.
nsISupports* supp = static_cast<nsISupports*>(*aResult);
wrappedJS = do_QueryInterface(supp);
SetWrappedJS(aContent, wrappedJS);
return rv;
}
}
*aResult = nullptr;
return NS_NOINTERFACE;
}
static void InsertAppendedContent(XBLChildrenElement* aPoint,
nsIContent* aFirstNewContent) {
int32_t insertionIndex;
if (nsIContent* prevSibling = aFirstNewContent->GetPreviousSibling()) {
// If we have a previous sibling, then it must already be in aPoint. Find
// it and insert after it.
insertionIndex = aPoint->IndexOfInsertedChild(prevSibling);
MOZ_ASSERT(insertionIndex != -1);
// Our insertion index is one after our previous sibling's index.
++insertionIndex;
} else {
// Otherwise, we append.
// TODO This is wrong for nested insertion points. In that case, we need to
// keep track of the right index to insert into.
insertionIndex = aPoint->InsertedChildrenLength();
}
// Do the inserting.
for (nsIContent* currentChild = aFirstNewContent; currentChild;
currentChild = currentChild->GetNextSibling()) {
aPoint->InsertInsertedChildAt(currentChild, insertionIndex++);
}
}
void nsBindingManager::ContentAppended(nsIContent* aFirstNewContent) {
// Try to find insertion points for all the new kids.
XBLChildrenElement* point = nullptr;
nsIContent* container = aFirstNewContent->GetParent();
nsIContent* parent = container;
// Handle appending of default content.
if (parent && parent->IsActiveChildrenElement()) {
XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
if (childrenEl->HasInsertedChildren()) {
// Appending default content that isn't being used. Ignore.
return;
}
childrenEl->MaybeSetupDefaultContent();
parent = childrenEl->GetParent();
}
bool first = true;
do {
nsXBLBinding* binding = GetBindingWithContent(parent);
if (!binding) {
break;
}
if (binding->HasFilteredInsertionPoints()) {
// There are filtered insertion points involved, handle each child
// separately.
// We could optimize this in the case when we've nested a few levels
// deep already, without hitting bindings that have filtered insertion
// points.
for (nsIContent* currentChild = aFirstNewContent; currentChild;
currentChild = currentChild->GetNextSibling()) {
HandleChildInsertion(container, currentChild, true);
}
return;
}
point = binding->GetDefaultInsertionPoint();
if (!point) {
break;
}
// Even though we're in ContentAppended, nested insertion points force us
// to deal with this append as an insertion except in the outermost
// binding.
if (first) {
first = false;
for (nsIContent* child = aFirstNewContent; child;
child = child->GetNextSibling()) {
point->AppendInsertedChild(child, true);
}
} else {
InsertAppendedContent(point, aFirstNewContent);
}
nsIContent* newParent = point->GetParent();
if (newParent == parent) {
break;
}
parent = newParent;
} while (parent);
}
void nsBindingManager::ContentInserted(nsIContent* aChild) {
HandleChildInsertion(aChild->GetParent(), aChild, false);
}
void nsBindingManager::ContentRemoved(nsIContent* aChild,
nsIContent* aPreviousSibling) {
aChild->SetXBLInsertionPoint(nullptr);
XBLChildrenElement* point = nullptr;
nsIContent* parent = aChild->GetParent();
// Handle appending of default content.
if (parent && parent->IsActiveChildrenElement()) {
XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
if (childrenEl->HasInsertedChildren()) {
// Removing default content that isn't being used. Ignore.
return;
}
parent = childrenEl->GetParent();
}
do {
nsXBLBinding* binding = GetBindingWithContent(parent);
if (!binding) {
// If aChild is XBL content, it might have <xbl:children> elements
// somewhere under it. We need to inform those elements that they're no
// longer in the tree so they can tell their distributed children that
// they're no longer distributed under them.
// XXX This is wrong. We need to do far more work to update the parent
// binding's list of insertion points and to get the new insertion parent
// for the newly-distributed children correct.
if (aChild->GetBindingParent()) {
ClearInsertionPointsRecursively(aChild);
}
return;
}
point = binding->FindInsertionPointFor(aChild);
if (!point) {
break;
}
point->RemoveInsertedChild(aChild);
nsIContent* newParent = point->GetParent();
if (newParent == parent) {
break;
}
parent = newParent;
} while (parent);
}
void nsBindingManager::ClearInsertionPointsRecursively(nsIContent* aContent) {
if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildren();
}
for (nsIContent* child = aContent->GetFirstChild(); child;
child = child->GetNextSibling()) {
ClearInsertionPointsRecursively(child);
}
}
void nsBindingManager::DropDocumentReference() {
mDestroyed = true;
// Make sure to not run any more XBL constructors
mProcessingAttachedStack = true;
if (mProcessAttachedQueueEvent) {
mProcessAttachedQueueEvent->Revoke();
}
if (mBoundContentSet) {
mBoundContentSet->Clear();
}
mDocument = nullptr;
}
void nsBindingManager::Traverse(nsIContent* aContent,
nsCycleCollectionTraversalCallback& cb) {
if (!aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
!aContent->IsElement()) {
// Don't traverse if content is not in this binding manager.
// We also don't traverse non-elements because there should not
// be bindings (checking the flag alone is not sufficient because
// the flag is also set on children of insertion points that may be
// non-elements).
return;
}
if (mBoundContentSet && mBoundContentSet->Contains(aContent)) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "[via binding manager] mBoundContentSet entry");
cb.NoteXPCOMChild(aContent);
}
nsIXPConnectWrappedJS* value = GetWrappedJS(aContent);
if (value) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "[via binding manager] mWrapperTable key");
cb.NoteXPCOMChild(aContent);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "[via binding manager] mWrapperTable value");
cb.NoteXPCOMChild(value);
}
}
void nsBindingManager::HandleChildInsertion(nsIContent* aContainer,
nsIContent* aChild, bool aAppend) {
MOZ_ASSERT(aChild, "Must have child");
XBLChildrenElement* point = nullptr;
nsIContent* parent = aContainer;
// Handle insertion of default content.
if (parent && parent->IsActiveChildrenElement()) {
XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
if (childrenEl->HasInsertedChildren()) {
// Inserting default content that isn't being used. Ignore.
return;
}
childrenEl->MaybeSetupDefaultContent();
parent = childrenEl->GetParent();
}
while (parent) {
nsXBLBinding* binding = GetBindingWithContent(parent);
if (!binding) {
break;
}
point = binding->FindInsertionPointFor(aChild);
if (!point) {
break;
}
// Insert the child into the proper insertion point.
// TODO If there were multiple insertion points, this approximation can be
// wrong. We need to re-run the distribution algorithm. In the meantime,
// this should work well enough.
uint32_t index = aAppend ? point->InsertedChildrenLength() : 0;
for (nsIContent* currentSibling = aChild->GetPreviousSibling();
currentSibling;
currentSibling = currentSibling->GetPreviousSibling()) {
// If we find one of our previous siblings in the insertion point, the
// index following it is the correct insertion point. Otherwise, we guess
// based on whether we're appending or inserting.
int32_t pointIndex = point->IndexOfInsertedChild(currentSibling);
if (pointIndex != -1) {
index = pointIndex + 1;
break;
}
}
point->InsertInsertedChildAt(aChild, index);
nsIContent* newParent = point->GetParent();
if (newParent == parent) {
break;
}
parent = newParent;
}
}
nsIContent* nsBindingManager::FindNestedSingleInsertionPoint(
nsIContent* aContainer, bool* aMulti) {
*aMulti = false;
nsIContent* parent = aContainer;
if (aContainer->IsActiveChildrenElement()) {
if (static_cast<XBLChildrenElement*>(aContainer)->HasInsertedChildren()) {
return nullptr;
}
parent = aContainer->GetParent();
}
while (parent) {
nsXBLBinding* binding = GetBindingWithContent(parent);
if (!binding) {
break;
}
if (binding->HasFilteredInsertionPoints()) {
*aMulti = true;
return nullptr;
}
XBLChildrenElement* point = binding->GetDefaultInsertionPoint();
if (!point) {
return nullptr;
}
nsIContent* newParent = point->GetParent();
if (newParent == parent) {
break;
}
parent = newParent;
}
return parent;
}
size_t nsBindingManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
#define SHALLOW_SIZE_INCLUDING(field_) \
n += field_ ? field_->ShallowSizeOfIncludingThis(aMallocSizeOf) : 0;
SHALLOW_SIZE_INCLUDING(mBoundContentSet);
SHALLOW_SIZE_INCLUDING(mWrapperTable);
SHALLOW_SIZE_INCLUDING(mLoadingDocTable);
#undef SHALLOW_SIZE_INCLUDING
n += mAttachedStack.ShallowSizeOfExcludingThis(aMallocSizeOf);
if (mDocumentTable) {
n += mDocumentTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
#ifdef MOZ_XUL
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
#endif
for (auto iter = mDocumentTable->Iter(); !iter.Done(); iter.Next()) {
nsXBLDocumentInfo* docInfo = iter.UserData();
#ifdef MOZ_XUL
nsXBLDocumentInfo* cachedInfo = cache->GetXBLDocumentInfo(iter.Key());
if (cachedInfo == docInfo) {
// If this binding has been cached, skip it since it can be
// reused by other documents.
continue;
}
#endif
n += docInfo->SizeOfIncludingThis(aMallocSizeOf);
}
}
return n;
}

View File

@ -1,204 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsBindingManager_h_
#define nsBindingManager_h_
#include "nsAutoPtr.h"
#include "nsIContent.h"
#include "nsStubMutationObserver.h"
#include "nsHashKeys.h"
#include "nsInterfaceHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsURIHashKey.h"
#include "nsCycleCollectionParticipant.h"
#include "nsXBLBinding.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "mozilla/MediaFeatureChange.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/EventStates.h"
struct ElementDependentRuleProcessorData;
class nsIXPConnectWrappedJS;
class nsAtom;
class nsIURI;
class nsXBLDocumentInfo;
class nsIStreamListener;
class nsXBLBinding;
typedef nsTArray<RefPtr<nsXBLBinding> > nsBindingList;
class nsIPrincipal;
class nsITimer;
class nsBindingManager final : public nsStubMutationObserver {
~nsBindingManager();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
explicit nsBindingManager(mozilla::dom::Document* aDocument);
nsXBLBinding* GetBindingWithContent(const nsIContent* aContent);
void AddBoundContent(nsIContent* aContent);
void RemoveBoundContent(nsIContent* aContent);
/**
* Notify the binding manager that an element
* has been removed from its document,
* so that it can update any bindings or
* nsIAnonymousContentCreator-created anonymous
* content that may depend on the document.
* @param aContent the element that's being moved
* @param aOldDocument the old document in which the
* content resided.
* @param aDestructorHandling whether or not to run the possible XBL
* destructor.
*/
enum DestructorHandling { eRunDtor, eDoNotRunDtor };
void RemovedFromDocument(nsIContent* aContent,
mozilla::dom::Document* aOldDocument,
DestructorHandling aDestructorHandling) {
if (aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
RemovedFromDocumentInternal(aContent, aOldDocument, aDestructorHandling);
}
}
void RemovedFromDocumentInternal(nsIContent* aContent,
mozilla::dom::Document* aOldDocument,
DestructorHandling aDestructorHandling);
/**
* Return the nodelist of "anonymous" kids for this node. This might
* actually include some of the nodes actual DOM kids, if there are
* <children> tags directly as kids of <content>. This will only end up
* returning a non-null list for nodes which have a binding attached.
*/
nsINodeList* GetAnonymousNodesFor(nsIContent* aContent);
nsresult ClearBinding(mozilla::dom::Element* aElement);
nsresult AddToAttachedQueue(nsXBLBinding* aBinding);
void RemoveFromAttachedQueue(nsXBLBinding* aBinding);
void ProcessAttachedQueue(uint32_t aSkipSize = 0) {
if (mProcessingAttachedStack || mAttachedStack.Length() <= aSkipSize) {
return;
}
ProcessAttachedQueueInternal(aSkipSize);
}
private:
void ProcessAttachedQueueInternal(uint32_t aSkipSize);
public:
void ExecuteDetachedHandlers();
nsresult PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
nsXBLDocumentInfo* GetXBLDocumentInfo(nsIURI* aURI);
void RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo);
nsresult PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener);
nsIStreamListener* GetLoadingDocListener(nsIURI* aURL);
void RemoveLoadingDocListener(nsIURI* aURL);
nsresult GetBindingImplementation(nsIContent* aContent, REFNSIID aIID,
void** aResult);
void Traverse(nsIContent* aContent, nsCycleCollectionTraversalCallback& cb);
NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
// Notify the binding manager when an outermost update begins and
// ends. The end method can execute script.
void BeginOutermostUpdate() {
mAttachedStackSizeOnOutermost = mAttachedStack.Length();
}
void EndOutermostUpdate() {
if (!mProcessingAttachedStack) {
ProcessAttachedQueue(mAttachedStackSizeOnOutermost);
mAttachedStackSizeOnOutermost = 0;
}
}
// When removing an insertion point or a parent of one, clear the insertion
// points and their insertion parents.
void ClearInsertionPointsRecursively(nsIContent* aContent);
// Called when the document is going away
void DropDocumentReference();
nsIContent* FindNestedSingleInsertionPoint(nsIContent* aContainer,
bool* aMulti);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
protected:
nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
// Called by ContentAppended and ContentInserted to handle a single child
// insertion. aChild must not be null. aContainer may be null.
// aAppend is true if this child is being appended, not inserted.
void HandleChildInsertion(nsIContent* aContainer, nsIContent* aChild,
bool aAppend);
// Same as ProcessAttachedQueue, but also nulls out
// mProcessAttachedQueueEvent
void DoProcessAttachedQueue();
// Post an event to process the attached queue.
void PostProcessAttachedQueueEvent();
// Call PostProcessAttachedQueueEvent() on a timer.
static void PostPAQEventCallback(nsITimer* aTimer, void* aClosure);
// MEMBER VARIABLES
// A set of nsIContent that currently have a binding installed.
nsAutoPtr<nsTHashtable<nsRefPtrHashKey<nsIContent> > > mBoundContentSet;
// A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect
// wrapper for JS objects). For XBL bindings that implement XPIDL
// interfaces, and that get referred to from C++, this table caches
// the XPConnect wrapper for the binding. By caching it, I control
// its lifetime, and I prevent a re-wrap of the same script object
// (in the case where multiple bindings in an XBL inheritance chain
// both implement an XPIDL interface).
typedef nsInterfaceHashtable<nsISupportsHashKey, nsIXPConnectWrappedJS>
WrapperHashtable;
nsAutoPtr<WrapperHashtable> mWrapperTable;
// A mapping from a URL (a string) to nsXBLDocumentInfo*. This table
// is the cache of all binding documents that have been loaded by a
// given bound document.
nsAutoPtr<nsRefPtrHashtable<nsURIHashKey, nsXBLDocumentInfo> > mDocumentTable;
// A mapping from a URL (a string) to a nsIStreamListener. This
// table is the currently loading binding docs. If they're in this
// table, they have not yet finished loading.
nsAutoPtr<nsInterfaceHashtable<nsURIHashKey, nsIStreamListener> >
mLoadingDocTable;
// A queue of binding attached event handlers that are awaiting execution.
nsBindingList mAttachedStack;
bool mProcessingAttachedStack;
bool mDestroyed;
uint32_t mAttachedStackSizeOnOutermost;
// Our posted event to process the attached queue, if any
friend class nsRunnableMethod<nsBindingManager>;
RefPtr<nsRunnableMethod<nsBindingManager> > mProcessAttachedQueueEvent;
// Our document. This is a weak ref; the document owns us
mozilla::dom::Document* mDocument;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLBinding_h_
#define nsXBLBinding_h_
#include "nsXBLService.h"
#include "nsCOMPtr.h"
#include "nsINodeList.h"
#include "nsClassHashtable.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupportsImpl.h"
#include "js/TypeDecls.h"
class nsXBLPrototypeBinding;
class nsIContent;
class nsAtom;
struct RawServoAuthorStyles;
namespace mozilla {
namespace dom {
class Document;
class XBLChildrenElement;
} // namespace dom
} // namespace mozilla
class nsAnonymousContentList;
// *********************************************************************/
// The XBLBinding class
class nsXBLBinding final {
public:
explicit nsXBLBinding(nsXBLPrototypeBinding* aProtoBinding);
/**
* XBLBindings are refcounted. They are held onto in 3 ways:
* 1. The binding manager's binding table holds onto all bindings that are
* currently attached to a content node.
* 2. Bindings hold onto their base binding. This is important since
* the base binding itself may not be attached to anything.
* 3. The binding manager holds an additional reference to bindings
* which are queued to fire their constructors.
*/
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsXBLBinding)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
nsXBLPrototypeBinding* PrototypeBinding() const { return mPrototypeBinding; }
nsIContent* GetAnonymousContent() { return mContent.get(); }
nsXBLBinding* GetBindingWithContent();
nsXBLBinding* GetBaseBinding() const { return mNextBinding; }
void SetBaseBinding(nsXBLBinding* aBinding);
mozilla::dom::Element* GetBoundElement() { return mBoundElement; }
void SetBoundElement(mozilla::dom::Element* aElement);
/*
* Does a lookup for a method or attribute provided by one of the bindings'
* prototype implementation. If found, |desc| will be set up appropriately,
* and wrapped into cx->compartment.
*
* May only be called when XBL code is being run in a separate scope, because
* otherwise we don't have untainted data with which to do a proper lookup.
*/
bool LookupMember(JSContext* aCx, JS::Handle<jsid> aId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc);
/*
* Determines whether the binding has a field with the given name.
*/
bool HasField(nsString& aName);
protected:
~nsXBLBinding();
/*
* Internal version. Requires that aCx is in appropriate xbl scope.
*/
bool LookupMemberInternal(JSContext* aCx, nsString& aName,
JS::Handle<jsid> aNameAsId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc,
JS::Handle<JSObject*> aXBLScope);
public:
void MarkForDeath();
bool MarkedForDeath() const { return mMarkedForDeath; }
bool ImplementsInterface(REFNSIID aIID) const;
void GenerateAnonymousContent();
void BindAnonymousContent(nsIContent* aAnonParent, nsIContent* aElement);
static void UnbindAnonymousContent(mozilla::dom::Document* aDocument,
nsIContent* aAnonParent,
bool aNullParent = true);
void InstallEventHandlers();
nsresult InstallImplementation();
void ExecuteAttachedHandler();
void ExecuteDetachedHandler();
void UnhookEventHandlers();
nsXBLBinding* RootBinding();
// Resolve all the fields for this binding and all ancestor bindings on the
// object |obj|. False return means a JS exception was set.
bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const;
void AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID,
bool aRemoveFlag, bool aNotify);
void ChangeDocument(mozilla::dom::Document* aOldDocument,
mozilla::dom::Document* aNewDocument);
const RawServoAuthorStyles* GetServoStyles() const;
static nsresult DoInitJSClass(JSContext* cx, JS::Handle<JSObject*> obj,
const nsString& aClassName,
nsXBLPrototypeBinding* aProtoBinding,
JS::MutableHandle<JSObject*> aClassObject,
bool* aNew);
bool AllowScripts();
mozilla::dom::XBLChildrenElement* FindInsertionPointFor(nsIContent* aChild);
bool HasFilteredInsertionPoints() { return !mInsertionPoints.IsEmpty(); }
mozilla::dom::XBLChildrenElement* GetDefaultInsertionPoint() {
return mDefaultInsertionPoint;
}
// Removes all inserted node from <xbl:children> insertion points under us.
void ClearInsertionPoints();
// Returns a live node list that iterates over the anonymous nodes generated
// by this binding.
nsAnonymousContentList* GetAnonymousNodeList();
nsIURI* GetSourceDocURI();
// MEMBER VARIABLES
protected:
bool mMarkedForDeath;
nsXBLPrototypeBinding*
mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
nsCOMPtr<nsIContent>
mContent; // Strong. Our anonymous content stays around with us.
RefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the
// base class bindings.
mozilla::dom::Element*
mBoundElement; // [WEAK] We have a reference, but we don't own it.
// The <xbl:children> elements that we found in our <xbl:content> when we
// processed this binding. The default insertion point has no includes
// attribute and all other insertion points must have at least one includes
// attribute. These points must be up-to-date with respect to their parent's
// children, even if their parent has another binding attached to it,
// preventing us from rendering their contents directly.
RefPtr<mozilla::dom::XBLChildrenElement> mDefaultInsertionPoint;
nsTArray<RefPtr<mozilla::dom::XBLChildrenElement> > mInsertionPoints;
RefPtr<nsAnonymousContentList> mAnonymousContentList;
mozilla::dom::XBLChildrenElement* FindInsertionPointForInternal(
nsIContent* aChild);
};
#endif // nsXBLBinding_h_

View File

@ -1,802 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/ArrayUtils.h"
#include "nsXBLContentSink.h"
#include "mozilla/dom/Document.h"
#include "nsBindingManager.h"
#include "nsGkAtoms.h"
#include "nsNameSpaceManager.h"
#include "nsIURI.h"
#include "nsTextFragment.h"
#ifdef MOZ_XUL
# include "nsXULElement.h"
#endif
#include "nsXBLProtoImplProperty.h"
#include "nsXBLProtoImplMethod.h"
#include "nsXBLProtoImplField.h"
#include "nsXBLPrototypeBinding.h"
#include "nsContentUtils.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
#include "nsNodeInfoManager.h"
#include "nsIPrincipal.h"
#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::dom;
nsresult NS_NewXBLContentSink(nsIXMLContentSink** aResult, Document* aDoc,
nsIURI* aURI, nsISupports* aContainer) {
NS_ENSURE_ARG_POINTER(aResult);
RefPtr<nsXBLContentSink> it = new nsXBLContentSink();
nsresult rv = it->Init(aDoc, aURI, aContainer);
NS_ENSURE_SUCCESS(rv, rv);
it.forget(aResult);
return NS_OK;
}
nsXBLContentSink::nsXBLContentSink()
: mState(eXBL_InDocument),
mSecondaryState(eXBL_None),
mDocInfo(nullptr),
mIsChromeOrResource(false),
mFoundFirstBinding(false),
mBinding(nullptr),
mHandler(nullptr),
mImplementation(nullptr),
mImplMember(nullptr),
mImplField(nullptr),
mProperty(nullptr),
mMethod(nullptr),
mField(nullptr) {
mPrettyPrintXML = false;
}
nsXBLContentSink::~nsXBLContentSink() {}
nsresult nsXBLContentSink::Init(Document* aDoc, nsIURI* aURI,
nsISupports* aContainer) {
nsresult rv;
rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nullptr);
return rv;
}
void nsXBLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) {}
nsresult nsXBLContentSink::FlushText(bool aReleaseTextNode) {
if (mTextLength != 0) {
const nsAString& text = Substring(mText, mText + mTextLength);
if (mState == eXBL_InHandlers) {
NS_ASSERTION(mBinding, "Must have binding here");
// Get the text and add it to the event handler.
if (mSecondaryState == eXBL_InHandler) mHandler->AppendHandlerText(text);
mTextLength = 0;
return NS_OK;
} else if (mState == eXBL_InImplementation) {
NS_ASSERTION(mBinding, "Must have binding here");
if (mSecondaryState == eXBL_InConstructor ||
mSecondaryState == eXBL_InDestructor) {
// Construct a method for the constructor/destructor.
nsXBLProtoImplMethod* method;
if (mSecondaryState == eXBL_InConstructor)
method = mBinding->GetConstructor();
else
method = mBinding->GetDestructor();
// Get the text and add it to the constructor/destructor.
method->AppendBodyText(text);
} else if (mSecondaryState == eXBL_InGetter ||
mSecondaryState == eXBL_InSetter) {
// Get the text and add it to the getter/setter
if (mSecondaryState == eXBL_InGetter)
mProperty->AppendGetterText(text);
else
mProperty->AppendSetterText(text);
} else if (mSecondaryState == eXBL_InBody) {
// Get the text and add it to the method
if (mMethod) mMethod->AppendBodyText(text);
} else if (mSecondaryState == eXBL_InField) {
// Get the text and add it to the method
if (mField) mField->AppendFieldText(text);
}
mTextLength = 0;
return NS_OK;
}
nsIContent* content = GetCurrentContent();
if (content && (content->NodeInfo()->NamespaceEquals(kNameSpaceID_XBL) ||
(content->IsXULElement() &&
!content->IsAnyOfXULElements(nsGkAtoms::label,
nsGkAtoms::description)))) {
bool isWS = true;
if (mTextLength > 0) {
const char16_t* cp = mText;
const char16_t* end = mText + mTextLength;
while (cp < end) {
char16_t ch = *cp++;
if (!dom::IsSpaceCharacter(ch)) {
isWS = false;
break;
}
}
}
if (isWS && mTextLength > 0) {
mTextLength = 0;
// Make sure to drop the textnode, if any
return nsXMLContentSink::FlushText(aReleaseTextNode);
}
}
}
return nsXMLContentSink::FlushText(aReleaseTextNode);
}
NS_IMETHODIMP
nsXBLContentSink::ReportError(const char16_t* aErrorText,
const char16_t* aSourceText,
nsIScriptError* aError, bool* _retval) {
MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
// XXX FIXME This function overrides and calls on
// nsXMLContentSink::ReportError, and probably should die. See bug 347826.
// XXX We should make sure the binding has no effect, but that it also
// gets destroyed properly without leaking. Perhaps we should even
// ensure that the content that was bound is displayed with no
// binding.
#ifdef DEBUG
// Report the error to stderr.
fprintf(stderr, "\n%s\n%s\n\n", NS_LossyConvertUTF16toASCII(aErrorText).get(),
NS_LossyConvertUTF16toASCII(aSourceText).get());
#endif
// Most of what this does won't be too useful, but whatever...
// nsXMLContentSink::ReportError will handle the console logging.
return nsXMLContentSink::ReportError(aErrorText, aSourceText, aError,
_retval);
}
nsresult nsXBLContentSink::ReportUnexpectedElement(nsAtom* aElementName,
uint32_t aLineNumber) {
// XXX we should really somehow stop the parse and drop the binding
// instead of just letting the XML sink build the content model like
// we do...
mState = eXBL_Error;
AutoTArray<nsString, 1> params;
aElementName->ToString(*params.AppendElement());
return nsContentUtils::ReportToConsole(
nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"),
mDocument, nsContentUtils::eXBL_PROPERTIES, "UnexpectedElement", params,
nullptr, EmptyString() /* source line */, aLineNumber);
}
void nsXBLContentSink::AddMember(nsXBLProtoImplMember* aMember) {
// Add this member to our chain.
if (mImplMember)
mImplMember->SetNext(
aMember); // Already have a chain. Just append to the end.
else
mImplementation->SetMemberList(
aMember); // We're the first member in the chain.
mImplMember = aMember; // Adjust our pointer to point to the new last member
// in the chain.
}
void nsXBLContentSink::AddField(nsXBLProtoImplField* aField) {
// Add this field to our chain.
if (mImplField)
mImplField->SetNext(
aField); // Already have a chain. Just append to the end.
else
mImplementation->SetFieldList(
aField); // We're the first member in the chain.
mImplField = aField; // Adjust our pointer to point to the new last field in
// the chain.
}
NS_IMETHODIMP
nsXBLContentSink::HandleStartElement(const char16_t* aName,
const char16_t** aAtts,
uint32_t aAttsCount, uint32_t aLineNumber,
uint32_t aColumnNumber) {
nsresult rv = nsXMLContentSink::HandleStartElement(
aName, aAtts, aAttsCount, aLineNumber, aColumnNumber);
if (NS_FAILED(rv)) return rv;
if (mState == eXBL_InBinding && !mBinding) {
rv = ConstructBinding(aLineNumber);
if (NS_FAILED(rv)) return rv;
// mBinding may still be null, if the binding had no id. If so,
// we'll deal with that later in the sink.
}
return rv;
}
NS_IMETHODIMP
nsXBLContentSink::HandleEndElement(const char16_t* aName) {
FlushText();
if (mState != eXBL_InDocument) {
int32_t nameSpaceID;
RefPtr<nsAtom> prefix, localName;
nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID == kNameSpaceID_XBL) {
if (mState == eXBL_Error) {
// Check whether we've opened this tag before; we may not have if
// it was a real XBL tag before the error occurred.
if (!GetCurrentContent()->NodeInfo()->Equals(localName, nameSpaceID)) {
// OK, this tag was never opened as far as the XML sink is
// concerned. Just drop the HandleEndElement
return NS_OK;
}
} else if (mState == eXBL_InHandlers) {
if (localName == nsGkAtoms::handlers) {
mState = eXBL_InBinding;
mHandler = nullptr;
} else if (localName == nsGkAtoms::handler)
mSecondaryState = eXBL_None;
return NS_OK;
} else if (mState == eXBL_InImplementation) {
if (localName == nsGkAtoms::implementation)
mState = eXBL_InBinding;
else if (localName == nsGkAtoms::property) {
mSecondaryState = eXBL_None;
mProperty = nullptr;
} else if (localName == nsGkAtoms::method) {
mSecondaryState = eXBL_None;
mMethod = nullptr;
} else if (localName == nsGkAtoms::field) {
mSecondaryState = eXBL_None;
mField = nullptr;
} else if (localName == nsGkAtoms::constructor ||
localName == nsGkAtoms::destructor)
mSecondaryState = eXBL_None;
else if (localName == nsGkAtoms::getter ||
localName == nsGkAtoms::setter)
mSecondaryState = eXBL_InProperty;
else if (localName == nsGkAtoms::parameter ||
localName == nsGkAtoms::body)
mSecondaryState = eXBL_InMethod;
return NS_OK;
} else if (mState == eXBL_InBindings &&
localName == nsGkAtoms::bindings) {
mState = eXBL_InDocument;
}
nsresult rv = nsXMLContentSink::HandleEndElement(aName);
if (NS_FAILED(rv)) return rv;
if (mState == eXBL_InBinding && localName == nsGkAtoms::binding) {
mState = eXBL_InBindings;
if (mBinding) { // See comment in HandleStartElement()
mBinding->Initialize();
mBinding = nullptr; // Clear our current binding ref.
}
}
return NS_OK;
}
}
return nsXMLContentSink::HandleEndElement(aName);
}
NS_IMETHODIMP
nsXBLContentSink::HandleCDataSection(const char16_t* aData, uint32_t aLength) {
if (mState == eXBL_InHandlers || mState == eXBL_InImplementation)
return AddText(aData, aLength);
return nsXMLContentSink::HandleCDataSection(aData, aLength);
}
#define ENSURE_XBL_STATE(_cond) \
PR_BEGIN_MACRO \
if (!(_cond)) { \
ReportUnexpectedElement(aTagName, aLineNumber); \
return true; \
} \
PR_END_MACRO
bool nsXBLContentSink::OnOpenContainer(const char16_t** aAtts,
uint32_t aAttsCount,
int32_t aNameSpaceID, nsAtom* aTagName,
uint32_t aLineNumber) {
if (mState == eXBL_Error) {
return true;
}
if (aNameSpaceID != kNameSpaceID_XBL) {
// Construct non-XBL nodes
return true;
}
bool ret = true;
if (aTagName == nsGkAtoms::bindings) {
ENSURE_XBL_STATE(mState == eXBL_InDocument);
NS_ASSERTION(mDocument, "Must have a document!");
RefPtr<nsXBLDocumentInfo> info = new nsXBLDocumentInfo(mDocument);
// We keep a weak ref. We're creating a cycle between doc/binding
// manager/doc info.
mDocInfo = info;
if (!mDocInfo) {
mState = eXBL_Error;
return true;
}
mDocument->BindingManager()->PutXBLDocumentInfo(mDocInfo);
nsIURI* uri = mDocument->GetDocumentURI();
mIsChromeOrResource = uri->SchemeIs("chrome") || uri->SchemeIs("resource");
mState = eXBL_InBindings;
} else if (aTagName == nsGkAtoms::binding) {
ENSURE_XBL_STATE(mState == eXBL_InBindings);
mState = eXBL_InBinding;
} else if (aTagName == nsGkAtoms::handlers) {
ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
mState = eXBL_InHandlers;
ret = false;
} else if (aTagName == nsGkAtoms::handler) {
ENSURE_XBL_STATE(mState == eXBL_InHandlers);
mSecondaryState = eXBL_InHandler;
ConstructHandler(aAtts, aLineNumber);
ret = false;
} else if (aTagName == nsGkAtoms::implementation) {
ENSURE_XBL_STATE(mState == eXBL_InBinding && mBinding);
mState = eXBL_InImplementation;
ConstructImplementation(aAtts);
// Note that this mState will cause us to return false, so no need
// to set ret to false.
} else if (aTagName == nsGkAtoms::constructor) {
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
mSecondaryState == eXBL_None);
NS_ASSERTION(mBinding, "Must have binding here");
mSecondaryState = eXBL_InConstructor;
nsAutoString name;
if (!mCurrentBindingID.IsEmpty()) {
name.Assign(mCurrentBindingID);
name.AppendLiteral("_XBL_Constructor");
} else {
name.AppendLiteral("XBL_Constructor");
}
nsXBLProtoImplAnonymousMethod* newMethod =
new nsXBLProtoImplAnonymousMethod(name.get());
newMethod->SetLineNumber(aLineNumber);
mBinding->SetConstructor(newMethod);
AddMember(newMethod);
} else if (aTagName == nsGkAtoms::destructor) {
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
mSecondaryState == eXBL_None);
NS_ASSERTION(mBinding, "Must have binding here");
mSecondaryState = eXBL_InDestructor;
nsAutoString name;
if (!mCurrentBindingID.IsEmpty()) {
name.Assign(mCurrentBindingID);
name.AppendLiteral("_XBL_Destructor");
} else {
name.AppendLiteral("XBL_Destructor");
}
nsXBLProtoImplAnonymousMethod* newMethod =
new nsXBLProtoImplAnonymousMethod(name.get());
newMethod->SetLineNumber(aLineNumber);
mBinding->SetDestructor(newMethod);
AddMember(newMethod);
} else if (aTagName == nsGkAtoms::field) {
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
mSecondaryState == eXBL_None);
NS_ASSERTION(mBinding, "Must have binding here");
mSecondaryState = eXBL_InField;
ConstructField(aAtts, aLineNumber);
} else if (aTagName == nsGkAtoms::property) {
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
mSecondaryState == eXBL_None);
NS_ASSERTION(mBinding, "Must have binding here");
mSecondaryState = eXBL_InProperty;
ConstructProperty(aAtts, aLineNumber);
} else if (aTagName == nsGkAtoms::getter) {
ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
mProperty->SetGetterLineNumber(aLineNumber);
mSecondaryState = eXBL_InGetter;
} else if (aTagName == nsGkAtoms::setter) {
ENSURE_XBL_STATE(mSecondaryState == eXBL_InProperty && mProperty);
NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
mProperty->SetSetterLineNumber(aLineNumber);
mSecondaryState = eXBL_InSetter;
} else if (aTagName == nsGkAtoms::method) {
ENSURE_XBL_STATE(mState == eXBL_InImplementation &&
mSecondaryState == eXBL_None);
NS_ASSERTION(mBinding, "Must have binding here");
mSecondaryState = eXBL_InMethod;
ConstructMethod(aAtts);
} else if (aTagName == nsGkAtoms::parameter) {
ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
ConstructParameter(aAtts);
} else if (aTagName == nsGkAtoms::body) {
ENSURE_XBL_STATE(mSecondaryState == eXBL_InMethod && mMethod);
NS_ASSERTION(mState == eXBL_InImplementation, "Unexpected state");
// stash away the line number
mMethod->SetLineNumber(aLineNumber);
mSecondaryState = eXBL_InBody;
}
return ret && mState != eXBL_InImplementation;
}
#undef ENSURE_XBL_STATE
nsresult nsXBLContentSink::ConstructBinding(uint32_t aLineNumber) {
// This is only called from HandleStartElement, so it'd better be an element.
RefPtr<Element> binding = GetCurrentContent()->AsElement();
binding->GetAttr(kNameSpaceID_None, nsGkAtoms::id, mCurrentBindingID);
NS_ConvertUTF16toUTF8 cid(mCurrentBindingID);
nsresult rv = NS_OK;
// Don't create a binding with no id. nsXBLPrototypeBinding::Read also
// performs this check.
if (!cid.IsEmpty()) {
mBinding = new nsXBLPrototypeBinding();
rv = mBinding->Init(cid, mDocInfo, binding, !mFoundFirstBinding);
if (NS_SUCCEEDED(rv) &&
NS_SUCCEEDED(mDocInfo->SetPrototypeBinding(cid, mBinding))) {
if (!mFoundFirstBinding) {
mFoundFirstBinding = true;
mDocInfo->SetFirstPrototypeBinding(mBinding);
}
binding->UnsetAttr(kNameSpaceID_None, nsGkAtoms::id, false);
} else {
delete mBinding;
mBinding = nullptr;
}
} else {
nsContentUtils::ReportToConsole(
nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"),
nullptr, nsContentUtils::eXBL_PROPERTIES, "MissingIdAttr",
nsTArray<nsString>(), mDocumentURI, EmptyString(), aLineNumber);
}
return rv;
}
static bool FindValue(const char16_t** aAtts, nsAtom* aAtom,
const char16_t** aResult) {
RefPtr<nsAtom> prefix, localName;
for (; *aAtts; aAtts += 2) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
// Is this attribute one of the ones we care about?
if (nameSpaceID == kNameSpaceID_None && localName == aAtom) {
*aResult = aAtts[1];
return true;
}
}
return false;
}
void nsXBLContentSink::ConstructHandler(const char16_t** aAtts,
uint32_t aLineNumber) {
const char16_t* event = nullptr;
const char16_t* modifiers = nullptr;
const char16_t* button = nullptr;
const char16_t* clickcount = nullptr;
const char16_t* keycode = nullptr;
const char16_t* charcode = nullptr;
const char16_t* phase = nullptr;
const char16_t* command = nullptr;
const char16_t* action = nullptr;
const char16_t* group = nullptr;
const char16_t* preventdefault = nullptr;
const char16_t* allowuntrusted = nullptr;
RefPtr<nsAtom> prefix, localName;
for (; *aAtts; aAtts += 2) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID != kNameSpaceID_None) {
continue;
}
// Is this attribute one of the ones we care about?
if (localName == nsGkAtoms::event)
event = aAtts[1];
else if (localName == nsGkAtoms::modifiers)
modifiers = aAtts[1];
else if (localName == nsGkAtoms::button)
button = aAtts[1];
else if (localName == nsGkAtoms::clickcount)
clickcount = aAtts[1];
else if (localName == nsGkAtoms::keycode)
keycode = aAtts[1];
else if (localName == nsGkAtoms::key || localName == nsGkAtoms::charcode)
charcode = aAtts[1];
else if (localName == nsGkAtoms::phase)
phase = aAtts[1];
else if (localName == nsGkAtoms::command)
command = aAtts[1];
else if (localName == nsGkAtoms::action)
action = aAtts[1];
else if (localName == nsGkAtoms::group)
group = aAtts[1];
else if (localName == nsGkAtoms::preventdefault)
preventdefault = aAtts[1];
else if (localName == nsGkAtoms::allowuntrusted)
allowuntrusted = aAtts[1];
}
if (command && !mIsChromeOrResource) {
// Make sure the XBL doc is chrome or resource if we have a command
// shorthand syntax.
mState = eXBL_Error;
nsContentUtils::ReportToConsole(
nsIScriptError::errorFlag, NS_LITERAL_CSTRING("XBL Content Sink"),
mDocument, nsContentUtils::eXBL_PROPERTIES, "CommandNotInChrome",
nsTArray<nsString>(), nullptr, EmptyString() /* source line */,
aLineNumber);
return; // Don't even make this handler.
}
// All of our pointers are now filled in. Construct our handler with all of
// these parameters.
nsXBLPrototypeHandler* newHandler;
newHandler = new nsXBLPrototypeHandler(
event, phase, action, command, keycode, charcode, modifiers, button,
clickcount, group, preventdefault, allowuntrusted, mBinding, aLineNumber);
// Add this handler to our chain of handlers.
if (mHandler) {
// Already have a chain. Just append to the end.
mHandler->SetNextHandler(newHandler);
} else {
// We're the first handler in the chain.
mBinding->SetPrototypeHandlers(newHandler);
}
// Adjust our mHandler pointer to point to the new last handler in the
// chain.
mHandler = newHandler;
}
void nsXBLContentSink::ConstructImplementation(const char16_t** aAtts) {
mImplementation = nullptr;
mImplMember = nullptr;
mImplField = nullptr;
if (!mBinding) return;
const char16_t* name = nullptr;
RefPtr<nsAtom> prefix, localName;
for (; *aAtts; aAtts += 2) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID != kNameSpaceID_None) {
continue;
}
// Is this attribute one of the ones we care about?
if (localName == nsGkAtoms::name) {
name = aAtts[1];
} else if (localName == nsGkAtoms::implements) {
// Only allow implementation of interfaces via XBL if the principal of
// our XBL document is the system principal.
if (nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal())) {
mBinding->ConstructInterfaceTable(nsDependentString(aAtts[1]));
}
}
}
NS_NewXBLProtoImpl(mBinding, name, &mImplementation);
}
void nsXBLContentSink::ConstructField(const char16_t** aAtts,
uint32_t aLineNumber) {
const char16_t* name = nullptr;
const char16_t* readonly = nullptr;
RefPtr<nsAtom> prefix, localName;
for (; *aAtts; aAtts += 2) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID != kNameSpaceID_None) {
continue;
}
// Is this attribute one of the ones we care about?
if (localName == nsGkAtoms::name) {
name = aAtts[1];
} else if (localName == nsGkAtoms::readonly) {
readonly = aAtts[1];
}
}
if (name) {
// All of our pointers are now filled in. Construct our field with all of
// these parameters.
mField = new nsXBLProtoImplField(name, readonly);
mField->SetLineNumber(aLineNumber);
AddField(mField);
}
}
void nsXBLContentSink::ConstructProperty(const char16_t** aAtts,
uint32_t aLineNumber) {
const char16_t* name = nullptr;
const char16_t* readonly = nullptr;
const char16_t* onget = nullptr;
const char16_t* onset = nullptr;
bool exposeToUntrustedContent = false;
RefPtr<nsAtom> prefix, localName;
for (; *aAtts; aAtts += 2) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID != kNameSpaceID_None) {
continue;
}
// Is this attribute one of the ones we care about?
if (localName == nsGkAtoms::name) {
name = aAtts[1];
} else if (localName == nsGkAtoms::readonly) {
readonly = aAtts[1];
} else if (localName == nsGkAtoms::onget) {
onget = aAtts[1];
} else if (localName == nsGkAtoms::onset) {
onset = aAtts[1];
} else if (localName == nsGkAtoms::exposeToUntrustedContent &&
nsDependentString(aAtts[1]).EqualsLiteral("true")) {
exposeToUntrustedContent = true;
}
}
if (name) {
// All of our pointers are now filled in. Construct our property with all of
// these parameters.
mProperty =
new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber);
if (exposeToUntrustedContent) {
mProperty->SetExposeToUntrustedContent(true);
}
AddMember(mProperty);
}
}
void nsXBLContentSink::ConstructMethod(const char16_t** aAtts) {
mMethod = nullptr;
const char16_t* name = nullptr;
const char16_t* expose = nullptr;
if (FindValue(aAtts, nsGkAtoms::name, &name)) {
mMethod = new nsXBLProtoImplMethod(name);
if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) &&
nsDependentString(expose).EqualsLiteral("true")) {
mMethod->SetExposeToUntrustedContent(true);
}
}
if (mMethod) {
AddMember(mMethod);
}
}
void nsXBLContentSink::ConstructParameter(const char16_t** aAtts) {
if (!mMethod) return;
const char16_t* name = nullptr;
if (FindValue(aAtts, nsGkAtoms::name, &name)) {
mMethod->AddParameter(nsDependentString(name));
}
}
nsresult nsXBLContentSink::CreateElement(
const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
uint32_t aColumnNumber, nsIContent** aResult, bool* aAppendContent,
FromParser aFromParser) {
#ifdef MOZ_XUL
if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
#endif
return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
aLineNumber, aColumnNumber, aResult,
aAppendContent, aFromParser);
#ifdef MOZ_XUL
}
// Note that this needs to match the code in
// nsXBLPrototypeBinding::ReadContentNode.
*aAppendContent = true;
RefPtr<nsXULPrototypeElement> prototype =
new nsXULPrototypeElement(aNodeInfo);
AddAttributesToXULPrototype(aAtts, aAttsCount, prototype);
Element* result;
nsresult rv = nsXULElement::CreateFromPrototype(prototype, mDocument, false,
false, &result);
*aResult = result;
return rv;
#endif
}
nsresult nsXBLContentSink::AddAttributes(const char16_t** aAtts,
Element* aElement) {
if (aElement->IsXULElement())
return NS_OK; // Nothing to do, since the proto already has the attrs.
return nsXMLContentSink::AddAttributes(aAtts, aElement);
}
#ifdef MOZ_XUL
nsresult nsXBLContentSink::AddAttributesToXULPrototype(
const char16_t** aAtts, uint32_t aAttsCount,
nsXULPrototypeElement* aElement) {
// Add tag attributes to the element
nsresult rv;
// Create storage for the attributes
nsXULPrototypeAttribute* attrs = nullptr;
if (aAttsCount > 0) {
attrs = aElement->mAttributes.AppendElements(aAttsCount);
}
// Copy the attributes into the prototype
RefPtr<nsAtom> prefix, localName;
uint32_t i;
for (i = 0; i < aAttsCount; ++i) {
int32_t nameSpaceID;
nsContentUtils::SplitExpatName(aAtts[i * 2], getter_AddRefs(prefix),
getter_AddRefs(localName), &nameSpaceID);
if (nameSpaceID == kNameSpaceID_None) {
attrs[i].mName.SetTo(localName);
} else {
RefPtr<NodeInfo> ni;
ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
nsINode::ATTRIBUTE_NODE);
attrs[i].mName.SetTo(ni);
}
rv = aElement->SetAttrAt(i, nsDependentString(aAtts[i * 2 + 1]),
mDocumentURI);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
#endif

View File

@ -1,145 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLContentSink_h__
#define nsXBLContentSink_h__
#include "mozilla/Attributes.h"
#include "nsXMLContentSink.h"
#include "nsXBLDocumentInfo.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLProtoImpl.h"
#include "nsLayoutCID.h"
/*
* Enum that describes the primary state of the parsing process
*/
typedef enum {
eXBL_InDocument, /* outside any bindings */
eXBL_InBindings, /* Inside a <bindings> element */
eXBL_InBinding, /* Inside a <binding> */
eXBL_InImplementation, /* Inside a <implementation> */
eXBL_InHandlers, /* Inside a <handlers> */
eXBL_Error /* An error has occurred. Suspend binding construction */
} XBLPrimaryState;
/*
* Enum that describes our substate (typically when parsing something
* like <handlers> or <implementation>).
*/
typedef enum {
eXBL_None,
eXBL_InHandler,
eXBL_InMethod,
eXBL_InProperty,
eXBL_InField,
eXBL_InBody,
eXBL_InGetter,
eXBL_InSetter,
eXBL_InConstructor,
eXBL_InDestructor
} XBLSecondaryState;
class nsXULPrototypeElement;
class nsXBLProtoImplMember;
class nsXBLProtoImplProperty;
class nsXBLProtoImplMethod;
class nsXBLProtoImplField;
class nsXBLPrototypeBinding;
// The XBL content sink overrides the XML content sink to
// builds its own lightweight data structures for the <resources>,
// <handlers>, <implementation>, and
class nsXBLContentSink : public nsXMLContentSink {
public:
nsXBLContentSink();
~nsXBLContentSink();
nsresult Init(mozilla::dom::Document* aDoc, nsIURI* aURL,
nsISupports* aContainer);
// nsIContentSink overrides
NS_IMETHOD HandleStartElement(const char16_t* aName, const char16_t** aAtts,
uint32_t aAttsCount, uint32_t aLineNumber,
uint32_t aColumnNumber) override;
NS_IMETHOD HandleEndElement(const char16_t* aName) override;
NS_IMETHOD HandleCDataSection(const char16_t* aData,
uint32_t aLength) override;
protected:
// nsXMLContentSink overrides
virtual void MaybeStartLayout(bool aIgnorePendingSheets) override;
bool OnOpenContainer(const char16_t** aAtts, uint32_t aAttsCount,
int32_t aNameSpaceID, nsAtom* aTagName,
uint32_t aLineNumber) override;
bool NotifyForDocElement() override { return false; }
nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
mozilla::dom::NodeInfo* aNodeInfo,
uint32_t aLineNumber, uint32_t aColumnNumber,
nsIContent** aResult, bool* aAppendContent,
mozilla::dom::FromParser aFromParser) override;
nsresult AddAttributes(const char16_t** aAtts,
mozilla::dom::Element* aElement) override;
#ifdef MOZ_XUL
nsresult AddAttributesToXULPrototype(const char16_t** aAtts,
uint32_t aAttsCount,
nsXULPrototypeElement* aElement);
#endif
// Our own helpers for constructing XBL prototype objects.
nsresult ConstructBinding(uint32_t aLineNumber);
void ConstructHandler(const char16_t** aAtts, uint32_t aLineNumber);
void ConstructImplementation(const char16_t** aAtts);
void ConstructProperty(const char16_t** aAtts, uint32_t aLineNumber);
void ConstructMethod(const char16_t** aAtts);
void ConstructParameter(const char16_t** aAtts);
void ConstructField(const char16_t** aAtts, uint32_t aLineNumber);
// nsXMLContentSink overrides
nsresult FlushText(bool aReleaseTextNode = true) override;
// nsIExpatSink overrides
NS_IMETHOD ReportError(const char16_t* aErrorText,
const char16_t* aSourceText, nsIScriptError* aError,
bool* _retval) override;
protected:
nsresult ReportUnexpectedElement(nsAtom* aElementName, uint32_t aLineNumber);
void AddMember(nsXBLProtoImplMember* aMember);
void AddField(nsXBLProtoImplField* aField);
XBLPrimaryState mState;
XBLSecondaryState mSecondaryState;
nsXBLDocumentInfo* mDocInfo;
bool mIsChromeOrResource; // For bug #45989
bool mFoundFirstBinding;
nsString mCurrentBindingID;
nsXBLPrototypeBinding* mBinding;
nsXBLPrototypeHandler*
mHandler; // current handler, owned by its PrototypeBinding
nsXBLProtoImpl* mImplementation;
nsXBLProtoImplMember* mImplMember;
nsXBLProtoImplField* mImplField;
nsXBLProtoImplProperty* mProperty;
nsXBLProtoImplMethod* mMethod;
nsXBLProtoImplField* mField;
};
nsresult NS_NewXBLContentSink(nsIXMLContentSink** aResult,
mozilla::dom::Document* aDoc, nsIURI* aURL,
nsISupports* aContainer);
#endif // nsXBLContentSink_h__

View File

@ -1,311 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/DebugOnly.h"
#include "nsXBLDocumentInfo.h"
#include "mozilla/dom/Document.h"
#include "nsXBLPrototypeBinding.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "nsIURI.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
#include "nsIChromeRegistry.h"
#include "nsIPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsIScriptSecurityManager.h"
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
#include "nsWindowSizes.h"
#include "mozilla/Services.h"
#include "xpcpublic.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h"
#include "nsCCUncollectableMarker.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/URL.h"
using namespace mozilla;
using namespace mozilla::scache;
using namespace mozilla::dom;
static const char kXBLCachePrefix[] = "xblcache";
/* Implementation file */
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLDocumentInfo)
if (tmp->mBindingTable) {
for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done();
iter.Next()) {
iter.UserData()->Unlink();
}
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXBLDocumentInfo)
if (tmp->mDocument && nsCCUncollectableMarker::InGeneration(
cb, tmp->mDocument->GetMarkedCCGeneration())) {
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
if (tmp->mBindingTable) {
for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done();
iter.Next()) {
iter.UserData()->Traverse(cb);
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXBLDocumentInfo)
if (tmp->mBindingTable) {
for (auto iter = tmp->mBindingTable->ConstIter(); !iter.Done();
iter.Next()) {
iter.UserData()->Trace(aCallbacks, aClosure);
}
}
NS_IMPL_CYCLE_COLLECTION_TRACE_END
static void UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName,
void* aClosure) {
JS::ExposeObjectToActiveJS(&aPtr.as<JSObject>());
}
void nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration) {
if (mDocument) {
mDocument->MarkUncollectableForCCGeneration(aGeneration);
}
// Unmark any JS we hold
if (mBindingTable) {
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
}
}
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLDocumentInfo)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLDocumentInfo)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLDocumentInfo)
nsXBLDocumentInfo::nsXBLDocumentInfo(Document* aDocument)
: mDocument(aDocument),
mScriptAccess(true),
mIsChrome(false),
mFirstBinding(nullptr) {
nsIURI* uri = aDocument->GetDocumentURI();
if (IsChromeURI(uri)) {
// Cache whether or not this chrome XBL can execute scripts.
nsCOMPtr<nsIXULChromeRegistry> reg =
mozilla::services::GetXULChromeRegistryService();
if (reg) {
bool allow = true;
reg->AllowScriptsForPackage(uri, &allow);
mScriptAccess = allow;
}
mIsChrome = true;
} else {
// If this binding isn't running with system principal, then it's running
// from a remote-XUL whitelisted domain. This is already a not-really-
// supported configuration (among other things, we don't use XBL scopes in
// that configuration for compatibility reasons). But we should still at
// least make an effort to prevent binding code from running if content
// script is disabled or if the source domain is blacklisted (since the
// source domain for remote XBL must always be the same as the source domain
// of the bound content).
//
// If we just ask the binding document if script is enabled, it will
// discover that it has no inner window, and return false. So instead, we
// short-circuit the normal compartment-managed script-disabling machinery,
// and query the policy for the URI directly.
bool allow;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
nsresult rv = ssm->PolicyAllowsScript(uri, &allow);
mScriptAccess = NS_SUCCEEDED(rv) && allow;
}
}
nsXBLDocumentInfo::~nsXBLDocumentInfo() { mozilla::DropJSObjects(this); }
nsXBLPrototypeBinding* nsXBLDocumentInfo::GetPrototypeBinding(
const nsACString& aRef) {
if (!mBindingTable) return nullptr;
if (aRef.IsEmpty()) {
// Return our first binding
return mFirstBinding;
}
return mBindingTable->Get(aRef);
}
nsresult nsXBLDocumentInfo::SetPrototypeBinding(
const nsACString& aRef, nsXBLPrototypeBinding* aBinding) {
if (!mBindingTable) {
mBindingTable =
new nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>();
mozilla::HoldJSObjects(this);
}
NS_ENSURE_STATE(!mBindingTable->Get(aRef));
mBindingTable->Put(aRef, aBinding);
return NS_OK;
}
void nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef) {
if (mBindingTable) {
nsAutoPtr<nsXBLPrototypeBinding> bindingToRemove;
mBindingTable->Remove(aRef, &bindingToRemove);
// We do not want to destroy the binding, so just forget it.
bindingToRemove.forget();
}
}
// static
nsresult nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI,
nsXBLDocumentInfo** aDocInfo,
Document* aBoundDocument) {
*aDocInfo = nullptr;
nsAutoCString spec(kXBLCachePrefix);
nsresult rv = PathifyURI(aURI, spec);
NS_ENSURE_SUCCESS(rv, rv);
StartupCache* startupCache = StartupCache::GetSingleton();
if (!startupCache) {
return NS_ERROR_FAILURE;
}
const char* buf;
uint32_t len;
rv = startupCache->GetBuffer(spec.get(), &buf, &len);
// GetBuffer will fail if the binding is not in the cache.
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIObjectInputStream> stream;
rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
// The file compatibility.ini stores the build id. This is checked in
// nsAppRunner.cpp and will delete the cache if a different build is
// present. However, we check that the version matches here to be safe.
uint32_t version;
rv = stream->Read32(&version);
NS_ENSURE_SUCCESS(rv, rv);
if (version != XBLBinding_Serialize_Version) {
// The version that exists is different than expected, likely created with a
// different build, so invalidate the cache.
startupCache->InvalidateCache();
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIPrincipal> principal;
nsContentUtils::GetSecurityManager()->GetSystemPrincipal(
getter_AddRefs(principal));
nsCOMPtr<Document> doc;
rv = NS_NewXBLDocument(getter_AddRefs(doc), aURI, nullptr, principal);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsXBLDocumentInfo> docInfo = new nsXBLDocumentInfo(doc);
while (1) {
uint8_t flags;
nsresult rv = stream->Read8(&flags);
NS_ENSURE_SUCCESS(rv, rv);
if (flags == XBLBinding_Serialize_NoMoreBindings) break;
rv = nsXBLPrototypeBinding::ReadNewBinding(stream, docInfo, doc, flags);
if (NS_FAILED(rv)) {
return rv;
}
}
docInfo.forget(aDocInfo);
return NS_OK;
}
nsresult nsXBLDocumentInfo::WritePrototypeBindings() {
// Only write out bindings with the system principal
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal()))
return NS_OK;
nsAutoCString spec(kXBLCachePrefix);
nsresult rv = PathifyURI(DocumentURI(), spec);
NS_ENSURE_SUCCESS(rv, rv);
StartupCache* startupCache = StartupCache::GetSingleton();
if (!startupCache) {
return rv;
}
nsCOMPtr<nsIObjectOutputStream> stream;
nsCOMPtr<nsIStorageStream> storageStream;
rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(stream),
getter_AddRefs(storageStream), true);
NS_ENSURE_SUCCESS(rv, rv);
rv = stream->Write32(XBLBinding_Serialize_Version);
NS_ENSURE_SUCCESS(rv, rv);
if (mBindingTable) {
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->Write(stream);
}
}
// write a end marker at the end
rv = stream->Write8(XBLBinding_Serialize_NoMoreBindings);
NS_ENSURE_SUCCESS(rv, rv);
stream->Close();
NS_ENSURE_SUCCESS(rv, rv);
uint32_t len;
UniquePtr<char[]> buf;
rv = NewBufferFromStorageStream(storageStream, &buf, &len);
NS_ENSURE_SUCCESS(rv, rv);
return startupCache->PutBuffer(spec.get(), std::move(buf), len);
}
void nsXBLDocumentInfo::SetFirstPrototypeBinding(
nsXBLPrototypeBinding* aBinding) {
mFirstBinding = aBinding;
}
#ifdef DEBUG
void AssertInCompilationScope() {
AutoJSContext cx;
MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
}
#endif
size_t nsXBLDocumentInfo::SizeOfIncludingThis(
MallocSizeOf aMallocSizeOf) const {
size_t n = aMallocSizeOf(this);
if (mDocument) {
SizeOfState state(aMallocSizeOf);
nsWindowSizes windowSizes(state);
mDocument->DocAddSizeOfIncludingThis(windowSizes);
n += windowSizes.getTotalSize();
}
if (mBindingTable) {
n += mBindingTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
nsXBLPrototypeBinding* binding = iter.UserData();
n += binding->SizeOfIncludingThis(aMallocSizeOf);
}
}
return n;
}

View File

@ -1,75 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLDocumentInfo_h__
#define nsXBLDocumentInfo_h__
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
#include "mozilla/dom/Document.h"
#include "nsCycleCollectionParticipant.h"
class nsXBLPrototypeBinding;
class nsXBLDocumentInfo final : public nsSupportsWeakReference {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
explicit nsXBLDocumentInfo(mozilla::dom::Document* aDocument);
mozilla::dom::Document* GetDocument() const { return mDocument; }
bool GetScriptAccess() const { return mScriptAccess; }
nsIURI* DocumentURI() { return mDocument->GetDocumentURI(); }
nsXBLPrototypeBinding* GetPrototypeBinding(const nsACString& aRef);
nsresult SetPrototypeBinding(const nsACString& aRef,
nsXBLPrototypeBinding* aBinding);
// This removes the binding without deleting it
void RemovePrototypeBinding(const nsACString& aRef);
nsresult WritePrototypeBindings();
void SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding);
bool IsChrome() { return mIsChrome; }
void MarkInCCGeneration(uint32_t aGeneration);
static nsresult ReadPrototypeBindings(nsIURI* aURI,
nsXBLDocumentInfo** aDocInfo,
mozilla::dom::Document* aBoundDocument);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsXBLDocumentInfo)
private:
virtual ~nsXBLDocumentInfo();
RefPtr<mozilla::dom::Document> mDocument;
bool mScriptAccess;
bool mIsChrome;
// the binding table owns each nsXBLPrototypeBinding
nsAutoPtr<nsClassHashtable<nsCStringHashKey, nsXBLPrototypeBinding>>
mBindingTable;
// non-owning pointer to the first binding in the table
nsXBLPrototypeBinding* mFirstBinding;
};
#ifdef DEBUG
void AssertInCompilationScope();
#else
inline void AssertInCompilationScope() {}
#endif
#endif

View File

@ -1,161 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsCOMPtr.h"
#include "nsAtom.h"
#include "nsIDOMEventListener.h"
#include "nsXBLPrototypeHandler.h"
#include "nsContentUtils.h"
#include "mozilla/dom/Event.h" // for Event
#include "mozilla/dom/EventBinding.h" // for Event
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/KeyboardEvent.h"
#include "mozilla/TextEvents.h"
using namespace mozilla;
using namespace mozilla::dom;
nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler)
: mProtoHandler(aHandler) {}
nsXBLEventHandler::~nsXBLEventHandler() {}
NS_IMPL_ISUPPORTS(nsXBLEventHandler, nsIDOMEventListener)
NS_IMETHODIMP
nsXBLEventHandler::HandleEvent(Event* aEvent) {
if (!mProtoHandler) return NS_ERROR_FAILURE;
uint8_t phase = mProtoHandler->GetPhase();
if (phase == NS_PHASE_TARGET) {
if (aEvent->EventPhase() != Event_Binding::AT_TARGET) {
return NS_OK;
}
}
if (!EventMatched(aEvent)) return NS_OK;
RefPtr<EventTarget> currentTarget = aEvent->GetCurrentTarget();
mProtoHandler->ExecuteHandler(currentTarget, aEvent);
return NS_OK;
}
nsXBLMouseEventHandler::nsXBLMouseEventHandler(nsXBLPrototypeHandler* aHandler)
: nsXBLEventHandler(aHandler) {}
nsXBLMouseEventHandler::~nsXBLMouseEventHandler() {}
bool nsXBLMouseEventHandler::EventMatched(Event* aEvent) {
MouseEvent* mouse = aEvent->AsMouseEvent();
return mouse && mProtoHandler->MouseEventMatched(mouse);
}
nsXBLKeyEventHandler::nsXBLKeyEventHandler(nsAtom* aEventType, uint8_t aPhase,
uint8_t aType)
: mEventType(aEventType),
mPhase(aPhase),
mType(aType),
mIsBoundToChrome(false) {}
nsXBLKeyEventHandler::~nsXBLKeyEventHandler() {}
NS_IMPL_ISUPPORTS(nsXBLKeyEventHandler, nsIDOMEventListener)
bool nsXBLKeyEventHandler::ExecuteMatchedHandlers(
KeyboardEvent* aKeyEvent, uint32_t aCharCode,
const IgnoreModifierState& aIgnoreModifierState) {
WidgetEvent* event = aKeyEvent->WidgetEventPtr();
nsCOMPtr<EventTarget> target = aKeyEvent->GetCurrentTarget();
bool executed = false;
for (uint32_t i = 0; i < mProtoHandlers.Length(); ++i) {
nsXBLPrototypeHandler* handler = mProtoHandlers[i];
bool hasAllowUntrustedAttr = handler->HasAllowUntrustedAttr();
if ((event->IsTrusted() ||
(hasAllowUntrustedAttr && handler->AllowUntrustedEvents()) ||
(!hasAllowUntrustedAttr && !mIsBoundToChrome)) &&
handler->KeyEventMatched(aKeyEvent, aCharCode, aIgnoreModifierState)) {
handler->ExecuteHandler(target, aKeyEvent);
executed = true;
}
}
#ifdef XP_WIN
// Windows native applications ignore Windows-Logo key state when checking
// shortcut keys even if the key is pressed. Therefore, if there is no
// shortcut key which exactly matches current modifier state, we should
// retry to look for a shortcut key without the Windows-Logo key press.
if (!executed && !aIgnoreModifierState.mOS) {
WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
if (keyEvent && keyEvent->IsOS()) {
IgnoreModifierState ignoreModifierState(aIgnoreModifierState);
ignoreModifierState.mOS = true;
return ExecuteMatchedHandlers(aKeyEvent, aCharCode, ignoreModifierState);
}
}
#endif
return executed;
}
NS_IMETHODIMP
nsXBLKeyEventHandler::HandleEvent(Event* aEvent) {
uint32_t count = mProtoHandlers.Length();
if (count == 0) return NS_ERROR_FAILURE;
if (mPhase == NS_PHASE_TARGET) {
if (aEvent->EventPhase() != Event_Binding::AT_TARGET) {
return NS_OK;
}
}
RefPtr<KeyboardEvent> key = aEvent->AsKeyboardEvent();
if (!key) {
return NS_OK;
}
WidgetKeyboardEvent* nativeKeyboardEvent =
aEvent->WidgetEventPtr()->AsKeyboardEvent();
MOZ_ASSERT(nativeKeyboardEvent);
AutoShortcutKeyCandidateArray shortcutKeys;
nativeKeyboardEvent->GetShortcutKeyCandidates(shortcutKeys);
if (shortcutKeys.IsEmpty()) {
ExecuteMatchedHandlers(key, 0, IgnoreModifierState());
return NS_OK;
}
for (uint32_t i = 0; i < shortcutKeys.Length(); ++i) {
IgnoreModifierState ignoreModifierState;
ignoreModifierState.mShift = shortcutKeys[i].mIgnoreShift;
if (ExecuteMatchedHandlers(key, shortcutKeys[i].mCharCode,
ignoreModifierState)) {
return NS_OK;
}
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////
already_AddRefed<nsXBLEventHandler> NS_NewXBLEventHandler(
nsXBLPrototypeHandler* aHandler, nsAtom* aEventType) {
RefPtr<nsXBLEventHandler> handler;
switch (nsContentUtils::GetEventClassID(nsDependentAtomString(aEventType))) {
case eDragEventClass:
case eMouseEventClass:
case eMouseScrollEventClass:
case eWheelEventClass:
case eSimpleGestureEventClass:
handler = new nsXBLMouseEventHandler(aHandler);
break;
default:
handler = new nsXBLEventHandler(aHandler);
break;
}
return handler.forget();
}

View File

@ -1,99 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLEventHandler_h__
#define nsXBLEventHandler_h__
#include "mozilla/Attributes.h"
#include "nsCOMPtr.h"
#include "nsIDOMEventListener.h"
#include "nsTArray.h"
class nsAtom;
class nsXBLPrototypeHandler;
namespace mozilla {
struct IgnoreModifierState;
namespace dom {
class Event;
class KeyboardEvent;
} // namespace dom
} // namespace mozilla
class nsXBLEventHandler : public nsIDOMEventListener {
public:
explicit nsXBLEventHandler(nsXBLPrototypeHandler* aHandler);
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
protected:
virtual ~nsXBLEventHandler();
nsXBLPrototypeHandler* mProtoHandler;
private:
nsXBLEventHandler();
virtual bool EventMatched(mozilla::dom::Event* aEvent) { return true; }
};
class nsXBLMouseEventHandler : public nsXBLEventHandler {
public:
explicit nsXBLMouseEventHandler(nsXBLPrototypeHandler* aHandler);
virtual ~nsXBLMouseEventHandler();
private:
bool EventMatched(mozilla::dom::Event* aEvent) override;
};
class nsXBLKeyEventHandler : public nsIDOMEventListener {
typedef mozilla::IgnoreModifierState IgnoreModifierState;
public:
nsXBLKeyEventHandler(nsAtom* aEventType, uint8_t aPhase, uint8_t aType);
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
void AddProtoHandler(nsXBLPrototypeHandler* aProtoHandler) {
mProtoHandlers.AppendElement(aProtoHandler);
}
bool Matches(nsAtom* aEventType, uint8_t aPhase, uint8_t aType) const {
return (mEventType == aEventType && mPhase == aPhase && mType == aType);
}
void GetEventName(nsAString& aString) const { mEventType->ToString(aString); }
uint8_t GetPhase() const { return mPhase; }
uint8_t GetType() const { return mType; }
void SetIsBoundToChrome(bool aIsBoundToChrome) {
mIsBoundToChrome = aIsBoundToChrome;
}
private:
nsXBLKeyEventHandler();
virtual ~nsXBLKeyEventHandler();
MOZ_CAN_RUN_SCRIPT
bool ExecuteMatchedHandlers(mozilla::dom::KeyboardEvent* aEvent,
uint32_t aCharCode,
const IgnoreModifierState& aIgnoreModifierState);
nsTArray<nsXBLPrototypeHandler*> mProtoHandlers;
RefPtr<nsAtom> mEventType;
uint8_t mPhase;
uint8_t mType;
bool mIsBoundToChrome;
};
already_AddRefed<nsXBLEventHandler> NS_NewXBLEventHandler(
nsXBLPrototypeHandler* aHandler, nsAtom* aEventType);
#endif

View File

@ -1,144 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLMaybeCompiled_h__
#define nsXBLMaybeCompiled_h__
#include "js/RootingAPI.h"
/*
* A union containing either a pointer representing uncompiled source or a
* JSObject* representing the compiled result. The class is templated on the
* source object type.
*
* The purpose of abstracting this as a separate class is to allow it to be
* wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
* pointer, when present.
*
* No implementation of rootKind() is provided, which prevents
* Root<nsXBLMaybeCompiled<UncompiledT>> from being used.
*/
template <class UncompiledT>
class nsXBLMaybeCompiled {
public:
nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {}
explicit nsXBLMaybeCompiled(UncompiledT* uncompiled)
: mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {}
explicit nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {}
bool IsCompiled() const { return !(mUncompiled & BIT_UNCOMPILED); }
UncompiledT* GetUncompiled() const {
MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled");
uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED;
return reinterpret_cast<UncompiledT*>(unmasked);
}
JSObject* GetJSFunction() const {
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
if (mCompiled) {
JS::ExposeObjectToActiveJS(mCompiled);
}
return mCompiled;
}
// This is appropriate for use in tracing methods, etc.
JSObject* GetJSFunctionPreserveColor() const {
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
private:
JSObject*& UnsafeGetJSFunction() {
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
enum { BIT_UNCOMPILED = 1 << 0 };
union {
// An pointer that represents the function before being compiled, with
// BIT_UNCOMPILED set.
uintptr_t mUncompiled;
// The JS object for the compiled result.
JSObject* mCompiled;
};
friend struct js::BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>;
};
namespace js {
template <class UncompiledT>
struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>> {
typedef struct BarrierMethods<JSObject*> Base;
static void postWriteBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp,
nsXBLMaybeCompiled<UncompiledT> prev,
nsXBLMaybeCompiled<UncompiledT> next) {
if (next.IsCompiled()) {
Base::postWriteBarrier(
&functionp->UnsafeGetJSFunction(),
prev.IsCompiled() ? prev.UnsafeGetJSFunction() : nullptr,
next.UnsafeGetJSFunction());
} else if (prev.IsCompiled()) {
Base::postWriteBarrier(&prev.UnsafeGetJSFunction(),
prev.UnsafeGetJSFunction(), nullptr);
}
}
static void exposeToJS(nsXBLMaybeCompiled<UncompiledT> fun) {
if (fun.IsCompiled()) {
JS::ExposeObjectToActiveJS(fun.UnsafeGetJSFunction());
}
}
};
template <class T>
struct IsHeapConstructibleType<
nsXBLMaybeCompiled<T>> { // Yes, this is the exception to the rule. Sorry.
static constexpr bool value = true;
};
template <class UncompiledT, class Wrapper>
class HeapBase<nsXBLMaybeCompiled<UncompiledT>, Wrapper> {
const Wrapper& wrapper() const { return *static_cast<const Wrapper*>(this); }
Wrapper& wrapper() { return *static_cast<Wrapper*>(this); }
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
return wrapper().address();
}
nsXBLMaybeCompiled<UncompiledT>* extract() { return wrapper().unsafeGet(); }
public:
bool IsCompiled() const { return extract()->IsCompiled(); }
UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
JSObject* GetJSFunctionPreserveColor() const {
return extract()->GetJSFunctionPreserveColor();
}
void SetUncompiled(UncompiledT* source) {
wrapper() = nsXBLMaybeCompiled<UncompiledT>(source);
}
void SetJSFunction(JSObject* function) {
wrapper() = nsXBLMaybeCompiled<UncompiledT>(function);
}
JS::Heap<JSObject*>& AsHeapObject() {
MOZ_ASSERT(extract()->IsCompiled());
return *reinterpret_cast<JS::Heap<JSObject*>*>(this);
}
};
} /* namespace js */
#endif // nsXBLMaybeCompiled_h__

View File

@ -1,503 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/DebugOnly.h"
#include "nsXBLProtoImpl.h"
#include "nsIContent.h"
#include "mozilla/dom/Document.h"
#include "nsContentUtils.h"
#include "nsIXPConnect.h"
#include "nsIServiceManager.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLProtoImplProperty.h"
#include "nsIURI.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/XULElementBinding.h"
#include "xpcpublic.h"
#include "js/CharacterEncoding.h"
using namespace mozilla;
using namespace mozilla::dom;
using js::AssertSameCompartment;
nsresult nsXBLProtoImpl::InstallImplementation(
nsXBLPrototypeBinding* aPrototypeBinding, nsXBLBinding* aBinding) {
// This function is called to install a concrete implementation on a bound
// element using this prototype implementation as a guide. The prototype
// implementation is compiled lazily, so for the first bound element that
// needs a concrete implementation, we also build the prototype
// implementation.
if (!mMembers &&
!mFields) // Constructor and destructor also live in mMembers
return NS_OK; // Nothing to do, so let's not waste time.
// If the way this gets the script context changes, fix
// nsXBLProtoImplAnonymousMethod::Execute
Document* document = aBinding->GetBoundElement()->OwnerDoc();
// This sometimes gets called when we have no outer window and if we don't
// catch this, we get leaks during crashtests and reftests.
if (NS_WARN_IF(!document->GetWindow())) {
return NS_OK;
}
// |propertyHolder| (below) can be an existing object, so in theory we might
// hit something that could end up running script. We never want that to
// happen here, so we use an AutoJSAPI instead of an AutoEntryScript.
dom::AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(document->GetScopeObject()))) {
return NS_OK;
}
JSContext* cx = jsapi.cx();
// InitTarget objects gives us back the JS object that represents the bound
// element and the class object in the bound document that represents the
// concrete version of this implementation. This function also has the side
// effect of building up the prototype implementation if it has not been built
// already.
JS::Rooted<JSObject*> targetClassObject(cx, nullptr);
bool targetObjectIsNew = false;
nsresult rv =
InitTargetObjects(aPrototypeBinding, aBinding->GetBoundElement(),
&targetClassObject, &targetObjectIsNew);
NS_ENSURE_SUCCESS(rv, rv); // kick out if we were unable to properly
// intialize our target objects
MOZ_ASSERT(targetClassObject);
// If the prototype already existed, we don't need to install anything. return
// early.
if (!targetObjectIsNew) return NS_OK;
// We want to define the canonical set of members in a safe place. If we're
// using a separate XBL scope, we want to define them there first (so that
// they'll be available for Xray lookups, among other things), and then copy
// the properties to the content-side prototype as needed. We don't need to
// bother about the field accessors here, since we don't use/support those
// for in-content bindings.
// First, start by entering the realm of the XBL scope. This may or may
// not be the same realm as globalObject.
JS::Rooted<JSObject*> globalObject(
cx, JS::GetNonCCWObjectGlobal(targetClassObject));
JS::Rooted<JSObject*> scopeObject(cx,
xpc::GetXBLScopeOrGlobal(cx, globalObject));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
MOZ_ASSERT(JS_IsGlobalObject(scopeObject));
JSAutoRealm ar(cx, scopeObject);
// Determine the appropriate property holder.
//
// Note: If |targetIsNew| is false, we'll early-return above. However, that
// only tells us if the content-side object is new, which may be the case even
// if we've already set up the binding on the XBL side. For example, if we
// apply a binding #foo to a <span> when we've already applied it to a <div>,
// we'll end up with a different content prototype, but we'll already have a
// property holder called |foo| in the XBL scope. Check for that to avoid
// wasteful and weird property holder duplication.
const nsString& className = aPrototypeBinding->ClassName();
const char16_t* classNameChars = className.get();
const size_t classNameLen = className.Length();
JS::Rooted<JSObject*> propertyHolder(cx);
JS::Rooted<JS::PropertyDescriptor> existingHolder(cx);
if (scopeObject != globalObject &&
!JS_GetOwnUCPropertyDescriptor(cx, scopeObject, classNameChars,
classNameLen, &existingHolder)) {
return NS_ERROR_FAILURE;
}
bool propertyHolderIsNew =
!existingHolder.object() || !existingHolder.value().isObject();
if (!propertyHolderIsNew) {
propertyHolder = &existingHolder.value().toObject();
} else if (scopeObject != globalObject) {
// This is just a property holder, so it doesn't need any special JSClass.
propertyHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
NS_ENSURE_TRUE(propertyHolder, NS_ERROR_OUT_OF_MEMORY);
// Define it as a property on the scopeObject, using the same name used on
// the content side.
bool ok =
JS_DefineUCProperty(cx, scopeObject, classNameChars, classNameLen,
propertyHolder, JSPROP_PERMANENT | JSPROP_READONLY);
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
} else {
propertyHolder = targetClassObject;
}
// Walk our member list and install each one in turn on the XBL scope object.
if (propertyHolderIsNew) {
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext())
curr->InstallMember(cx, propertyHolder);
}
// Now, if we're using a separate XBL scope, enter the compartment of the
// bound node and copy exposable properties to the prototype there. This
// rewraps them appropriately, which should result in cross-compartment
// function wrappers.
if (propertyHolder != targetClassObject) {
AssertSameCompartment(propertyHolder, scopeObject);
AssertSameCompartment(targetClassObject, globalObject);
bool inContentXBLScope = xpc::IsInContentXBLScope(scopeObject);
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
if (!inContentXBLScope || curr->ShouldExposeToUntrustedContent()) {
JS::Rooted<jsid> id(cx);
JS::TwoByteChars chars(curr->GetName(), NS_strlen(curr->GetName()));
bool ok = JS_CharsToId(cx, chars, &id);
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
bool found;
ok = JS_HasPropertyById(cx, propertyHolder, id, &found);
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
if (!found) {
// Some members don't install anything in InstallMember (e.g.,
// nsXBLProtoImplAnonymousMethod). We need to skip copying in
// those cases.
continue;
}
ok = JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
}
}
}
// From here on out, work in the scope of the bound element.
JSAutoRealm ar2(cx, targetClassObject);
// Install all of our field accessors.
for (nsXBLProtoImplField* curr = mFields; curr; curr = curr->GetNext())
curr->InstallAccessors(cx, targetClassObject);
return NS_OK;
}
nsresult nsXBLProtoImpl::InitTargetObjects(
nsXBLPrototypeBinding* aBinding, nsIContent* aBoundElement,
JS::MutableHandle<JSObject*> aTargetClassObject, bool* aTargetIsNew) {
nsresult rv = NS_OK;
if (!mPrecompiledMemberHolder) {
rv = CompilePrototypeMembers(
aBinding); // This is the first time we've ever installed this binding
// on an element. We need to go ahead and compile all
// methods and properties on a class in our prototype
// binding.
if (NS_FAILED(rv)) return rv;
MOZ_ASSERT(mPrecompiledMemberHolder);
}
Document* ownerDoc = aBoundElement->OwnerDoc();
nsIGlobalObject* sgo;
if (!(sgo = ownerDoc->GetScopeObject())) {
return NS_ERROR_UNEXPECTED;
}
// Because our prototype implementation has a class, we need to build up a
// corresponding class for the concrete implementation in the bound document.
AutoJSContext cx;
JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
JS::Rooted<JS::Value> v(cx);
JSAutoRealm ar(cx, global);
// Make sure the interface object is created before the prototype object
// so that XULElement is hidden from content. See bug 909340.
bool defineOnGlobal = dom::XULElement_Binding::ConstructorEnabled(cx, global);
dom::XULElement_Binding::GetConstructorObjectHandle(cx, defineOnGlobal);
rv = nsContentUtils::WrapNative(cx, aBoundElement, &v,
/* aAllowWrapping = */ false);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSObject*> value(cx, &v.toObject());
// We passed aAllowWrapping = false to nsContentUtils::WrapNative so we
// should not have a wrapper.
MOZ_ASSERT(!js::IsWrapper(value));
JSAutoRealm ar2(cx, value);
// All of the above code was just obtaining the bound element's script object
// and its immediate concrete base class. We need to alter the object so that
// our concrete class is interposed between the object and its base class. We
// become the new base class of the object, and the object's old base class
// becomes the new class' base class.
rv = aBinding->InitClass(mClassName, cx, value, aTargetClassObject,
aTargetIsNew);
if (NS_FAILED(rv)) {
return rv;
}
aBoundElement->PreserveWrapper(aBoundElement);
return rv;
}
nsresult nsXBLProtoImpl::CompilePrototypeMembers(
nsXBLPrototypeBinding* aBinding) {
// We want to pre-compile our implementation's members against a "prototype
// context". Then when we actually bind the prototype to a real xbl instance,
// we'll clone the pre-compiled JS into the real instance's context.
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(xpc::CompilationScope()))) return NS_ERROR_FAILURE;
JSContext* cx = jsapi.cx();
mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
if (!mPrecompiledMemberHolder) return NS_ERROR_OUT_OF_MEMORY;
// Now that we have a class object installed, we walk our member list and
// compile each of our properties and methods in turn.
JS::Rooted<JSObject*> rootedHolder(cx, mPrecompiledMemberHolder);
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
nsresult rv = curr->CompileMember(jsapi, mClassName, rootedHolder);
if (NS_FAILED(rv)) {
DestroyMembers();
return rv;
}
}
return NS_OK;
}
bool nsXBLProtoImpl::LookupMember(
JSContext* aCx, nsString& aName, JS::Handle<jsid> aNameAsId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc,
JS::Handle<JSObject*> aClassObject) {
for (nsXBLProtoImplMember* m = mMembers; m; m = m->GetNext()) {
if (aName.Equals(m->GetName())) {
return JS_GetPropertyDescriptorById(aCx, aClassObject, aNameAsId, aDesc);
}
}
return true;
}
void nsXBLProtoImpl::Trace(const TraceCallbacks& aCallbacks, void* aClosure) {
// If we don't have a class object then we either didn't compile members
// or we only have fields, in both cases there are no cycles through our
// members.
if (!mPrecompiledMemberHolder) {
return;
}
nsXBLProtoImplMember* member;
for (member = mMembers; member; member = member->GetNext()) {
member->Trace(aCallbacks, aClosure);
}
}
void nsXBLProtoImpl::UnlinkJSObjects() {
if (mPrecompiledMemberHolder) {
DestroyMembers();
}
}
nsXBLProtoImplField* nsXBLProtoImpl::FindField(
const nsString& aFieldName) const {
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
if (aFieldName.Equals(f->GetName())) {
return f;
}
}
return nullptr;
}
bool nsXBLProtoImpl::ResolveAllFields(JSContext* cx,
JS::Handle<JSObject*> obj) const {
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
nsDependentString name(f->GetName());
bool dummy;
if (!::JS_HasUCProperty(cx, obj, name.get(), name.Length(), &dummy)) {
return false;
}
}
return true;
}
void nsXBLProtoImpl::UndefineFields(JSContext* cx,
JS::Handle<JSObject*> obj) const {
for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
nsDependentString name(f->GetName());
const char16_t* s = name.get();
bool hasProp;
if (::JS_AlreadyHasOwnUCProperty(cx, obj, s, name.Length(), &hasProp) &&
hasProp) {
JS::ObjectOpResult ignored;
::JS_DeleteUCProperty(cx, obj, s, name.Length(), ignored);
}
}
}
void nsXBLProtoImpl::DestroyMembers() {
MOZ_ASSERT(mPrecompiledMemberHolder);
delete mMembers;
mMembers = nullptr;
mConstructor = nullptr;
mDestructor = nullptr;
}
nsresult nsXBLProtoImpl::Read(nsIObjectInputStream* aStream,
nsXBLPrototypeBinding* aBinding) {
AssertInCompilationScope();
AutoJSContext cx;
// Set up a class object first so that deserialization is possible
mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
if (!mPrecompiledMemberHolder) return NS_ERROR_OUT_OF_MEMORY;
nsXBLProtoImplField* previousField = nullptr;
nsXBLProtoImplMember* previousMember = nullptr;
do {
XBLBindingSerializeDetails type;
nsresult rv = aStream->Read8(&type);
NS_ENSURE_SUCCESS(rv, rv);
if (type == XBLBinding_Serialize_NoMoreItems) break;
switch (type & XBLBinding_Serialize_Mask) {
case XBLBinding_Serialize_Field: {
nsXBLProtoImplField* field =
new nsXBLProtoImplField(type & XBLBinding_Serialize_ReadOnly);
rv = field->Read(aStream);
if (NS_FAILED(rv)) {
delete field;
return rv;
}
if (previousField) {
previousField->SetNext(field);
} else {
mFields = field;
}
previousField = field;
break;
}
case XBLBinding_Serialize_GetterProperty:
case XBLBinding_Serialize_SetterProperty:
case XBLBinding_Serialize_GetterSetterProperty: {
nsAutoString name;
nsresult rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
nsXBLProtoImplProperty* prop = new nsXBLProtoImplProperty(
name.get(), type & XBLBinding_Serialize_ReadOnly);
rv = prop->Read(aStream, type & XBLBinding_Serialize_Mask);
if (NS_FAILED(rv)) {
delete prop;
return rv;
}
previousMember = AddMember(prop, previousMember);
break;
}
case XBLBinding_Serialize_Method: {
nsAutoString name;
rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
nsXBLProtoImplMethod* method = new nsXBLProtoImplMethod(name.get());
rv = method->Read(aStream);
if (NS_FAILED(rv)) {
delete method;
return rv;
}
previousMember = AddMember(method, previousMember);
break;
}
case XBLBinding_Serialize_Constructor: {
nsAutoString name;
rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
mConstructor = new nsXBLProtoImplAnonymousMethod(name.get());
rv = mConstructor->Read(aStream);
if (NS_FAILED(rv)) {
delete mConstructor;
mConstructor = nullptr;
return rv;
}
previousMember = AddMember(mConstructor, previousMember);
break;
}
case XBLBinding_Serialize_Destructor: {
nsAutoString name;
rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
mDestructor = new nsXBLProtoImplAnonymousMethod(name.get());
rv = mDestructor->Read(aStream);
if (NS_FAILED(rv)) {
delete mDestructor;
mDestructor = nullptr;
return rv;
}
previousMember = AddMember(mDestructor, previousMember);
break;
}
default:
NS_ERROR("Unexpected binding member type");
break;
}
} while (1);
return NS_OK;
}
nsresult nsXBLProtoImpl::Write(nsIObjectOutputStream* aStream,
nsXBLPrototypeBinding* aBinding) {
nsresult rv;
if (!mPrecompiledMemberHolder) {
rv = CompilePrototypeMembers(aBinding);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aStream->WriteUtf8Z(mClassName.get());
NS_ENSURE_SUCCESS(rv, rv);
for (nsXBLProtoImplField* curr = mFields; curr; curr = curr->GetNext()) {
rv = curr->Write(aStream);
NS_ENSURE_SUCCESS(rv, rv);
}
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
if (curr == mConstructor) {
rv = mConstructor->Write(aStream, XBLBinding_Serialize_Constructor);
} else if (curr == mDestructor) {
rv = mDestructor->Write(aStream, XBLBinding_Serialize_Destructor);
} else {
rv = curr->Write(aStream);
}
NS_ENSURE_SUCCESS(rv, rv);
}
return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
}
void NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
const char16_t* aClassName, nsXBLProtoImpl** aResult) {
nsXBLProtoImpl* impl = new nsXBLProtoImpl();
if (aClassName) {
impl->mClassName = aClassName;
} else {
nsCString spec;
nsresult rv = aBinding->BindingURI()->GetSpec(spec);
// XXX: should handle this better
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
impl->mClassName = NS_ConvertUTF8toUTF16(spec);
}
aBinding->SetImplementation(impl);
*aResult = impl;
}

View File

@ -1,117 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLProtoImpl_h__
#define nsXBLProtoImpl_h__
#include "nsMemory.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLProtoImplField.h"
#include "nsXBLBinding.h"
class nsXBLPrototypeBinding;
class nsXBLProtoImplAnonymousMethod;
class nsXBLProtoImpl final {
public:
nsXBLProtoImpl()
: mPrecompiledMemberHolder(nullptr),
mMembers(nullptr),
mFields(nullptr),
mConstructor(nullptr),
mDestructor(nullptr) {
MOZ_COUNT_CTOR(nsXBLProtoImpl);
}
~nsXBLProtoImpl() {
MOZ_COUNT_DTOR(nsXBLProtoImpl);
// Note: the constructor and destructor are in mMembers, so we'll
// clean them up automatically.
delete mMembers;
delete mFields;
}
nsresult InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
nsXBLBinding* aBinding);
private:
nsresult InitTargetObjects(nsXBLPrototypeBinding* aBinding,
nsIContent* aBoundElement,
JS::MutableHandle<JSObject*> aTargetClassObject,
bool* aTargetIsNew);
public:
nsresult CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding);
bool LookupMember(JSContext* aCx, nsString& aName, JS::Handle<jsid> aNameAsId,
JS::MutableHandle<JS::PropertyDescriptor> aDesc,
JS::Handle<JSObject*> aClassObject);
void SetMemberList(nsXBLProtoImplMember* aMemberList) {
delete mMembers;
mMembers = aMemberList;
}
void SetFieldList(nsXBLProtoImplField* aFieldList) {
delete mFields;
mFields = aFieldList;
}
void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
void UnlinkJSObjects();
nsXBLProtoImplField* FindField(const nsString& aFieldName) const;
// Resolve all the fields for this implementation on the object |obj| False
// return means a JS exception was set.
bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const;
// Undefine all our fields from object |obj| (which should be a
// JSObject for a bound element).
void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const;
bool CompiledMembers() const { return mPrecompiledMemberHolder != nullptr; }
nsresult Read(nsIObjectInputStream* aStream, nsXBLPrototypeBinding* aBinding);
nsresult Write(nsIObjectOutputStream* aStream,
nsXBLPrototypeBinding* aBinding);
protected:
// used by Read to add each member
nsXBLProtoImplMember* AddMember(nsXBLProtoImplMember* aMember,
nsXBLProtoImplMember* aPreviousMember) {
if (aPreviousMember)
aPreviousMember->SetNext(aMember);
else
mMembers = aMember;
return aMember;
}
void DestroyMembers();
public:
nsString mClassName; // The name of the class.
protected:
JSObject*
mPrecompiledMemberHolder; // The class object for the binding. We'll use
// this to pre-compile properties and methods
// for the binding.
nsXBLProtoImplMember* mMembers; // The members of an implementation are
// chained in this singly-linked list.
nsXBLProtoImplField* mFields; // Our fields
public:
nsXBLProtoImplAnonymousMethod* mConstructor; // Our class constructor.
nsXBLProtoImplAnonymousMethod* mDestructor; // Our class destructor.
};
void NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
const char16_t* aClassName, nsXBLProtoImpl** aResult);
#endif // nsXBLProtoImpl_h__

View File

@ -1,484 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsAtom.h"
#include "nsIContent.h"
#include "nsString.h"
#include "nsJSUtils.h"
#include "jsapi.h"
#include "js/CharacterEncoding.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
#include "nsXBLProtoImplField.h"
#include "nsIScriptContext.h"
#include "nsIURI.h"
#include "nsXBLSerialize.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsGlobalWindow.h"
#include "xpcpublic.h"
#include "WrapperFactory.h"
using namespace mozilla;
using namespace mozilla::dom;
nsXBLProtoImplField::nsXBLProtoImplField(const char16_t* aName,
const char16_t* aReadOnly)
: mNext(nullptr), mFieldText(nullptr), mFieldTextLength(0), mLineNumber(0) {
MOZ_COUNT_CTOR(nsXBLProtoImplField);
mName = NS_xstrdup(aName); // XXXbz make more sense to use a stringbuffer?
mJSAttributes = JSPROP_ENUMERATE;
if (aReadOnly) {
nsAutoString readOnly;
readOnly.Assign(aReadOnly);
if (readOnly.LowerCaseEqualsLiteral("true"))
mJSAttributes |= JSPROP_READONLY;
}
}
nsXBLProtoImplField::nsXBLProtoImplField(const bool aIsReadOnly)
: mNext(nullptr),
mName(nullptr),
mFieldText(nullptr),
mFieldTextLength(0),
mLineNumber(0) {
MOZ_COUNT_CTOR(nsXBLProtoImplField);
mJSAttributes = JSPROP_ENUMERATE;
if (aIsReadOnly) mJSAttributes |= JSPROP_READONLY;
}
nsXBLProtoImplField::~nsXBLProtoImplField() {
MOZ_COUNT_DTOR(nsXBLProtoImplField);
if (mFieldText) free(mFieldText);
free(mName);
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLProtoImplField, this, mNext);
}
void nsXBLProtoImplField::AppendFieldText(const nsAString& aText) {
if (mFieldText) {
nsDependentString fieldTextStr(mFieldText, mFieldTextLength);
nsAutoString newFieldText = fieldTextStr + aText;
char16_t* temp = mFieldText;
mFieldText = ToNewUnicode(newFieldText);
mFieldTextLength = newFieldText.Length();
free(temp);
} else {
mFieldText = ToNewUnicode(aText);
mFieldTextLength = aText.Length();
}
}
// XBL fields are represented on elements inheriting that field a bit trickily.
// When setting up the XBL prototype object, we install accessors for the fields
// on the prototype object. Those accessors, when used, will then (via
// InstallXBLField below) reify a property for the field onto the actual
// XBL-backed element.
//
// The accessor property is a plain old property backed by a getter function and
// a setter function. These properties are backed by the FieldGetter and
// FieldSetter natives; they're created by InstallAccessors. The precise field
// to be reified is identified using two extra slots on the getter/setter
// functions. XBLPROTO_SLOT stores the XBL prototype object that provides the
// field. FIELD_SLOT stores the name of the field, i.e. its JavaScript property
// name.
//
// This two-step field installation process -- creating an accessor on the
// prototype, then have that reify an own property on the actual element -- is
// admittedly convoluted. Better would be for XBL-backed elements to be proxies
// that could resolve fields onto themselves. But given that XBL bindings are
// associated with elements mutably -- you can add/remove/change -moz-binding
// whenever you want, alas -- doing so would require all elements to be proxies,
// which isn't performant now. So we do this two-step instead.
static const uint32_t XBLPROTO_SLOT = 0;
static const uint32_t FIELD_SLOT = 1;
bool ValueHasISupportsPrivate(JS::Handle<JS::Value> v) {
if (!v.isObject()) {
return false;
}
const DOMJSClass* domClass = GetDOMClass(&v.toObject());
if (domClass) {
return domClass->mDOMObjectIsISupports;
}
const JSClass* clasp = ::JS_GetClass(&v.toObject());
const uint32_t HAS_PRIVATE_NSISUPPORTS =
JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS;
return (clasp->flags & HAS_PRIVATE_NSISUPPORTS) == HAS_PRIVATE_NSISUPPORTS;
}
#ifdef DEBUG
static bool ValueHasISupportsPrivate(JSContext* cx, const JS::Value& aVal) {
JS::Rooted<JS::Value> v(cx, aVal);
return ValueHasISupportsPrivate(v);
}
#endif
// Define a shadowing property on |this| for the XBL field defined by the
// contents of the callee's reserved slots. If the property was defined,
// *installed will be true, and idp will be set to the property name that was
// defined.
static bool InstallXBLField(JSContext* cx, JS::Handle<JSObject*> callee,
JS::Handle<JSObject*> thisObj,
JS::MutableHandle<jsid> idp, bool* installed) {
*installed = false;
// First ensure |this| is a reasonable XBL bound node.
//
// FieldAccessorGuard already determined whether |thisObj| was acceptable as
// |this| in terms of not throwing a TypeError. Assert this for good measure.
MOZ_ASSERT(ValueHasISupportsPrivate(cx, JS::ObjectValue(*thisObj)));
// But there are some cases where we must accept |thisObj| but not install a
// property on it, or otherwise touch it. Hence this split of |this|-vetting
// duties.
//
// OK to use ReflectorToISupportsStatic, because we only care about nodes
// here.
nsCOMPtr<nsISupports> native = xpc::ReflectorToISupportsStatic(thisObj);
if (!native) {
// Looks like whatever |thisObj| is it's not our nsIContent. It might well
// be the proto our binding installed, however, where the private is the
// nsXBLDocumentInfo, so just baul out quietly. Do NOT throw an exception
// here.
//
// We could make this stricter by checking the class maybe, but whatever.
return true;
}
nsCOMPtr<nsIContent> xblNode = do_QueryInterface(native);
if (!xblNode) {
xpc::Throw(cx, NS_ERROR_UNEXPECTED);
return false;
}
// Now that |this| is okay, actually install the field.
// Because of the possibility (due to XBL binding inheritance, because each
// XBL binding lives in its own global object) that |this| might be in a
// different realm from the callee (not to mention that this method can
// be called with an arbitrary |this| regardless of how insane XBL is), and
// because in this method we've entered |this|'s realm (see in
// Field[GS]etter where we attempt a cross-realm call), we must enter
// the callee's realm to access its reserved slots.
nsXBLPrototypeBinding* protoBinding;
nsAutoJSString fieldName;
{
JSAutoRealm ar(cx, callee);
JS::Rooted<JSObject*> xblProto(cx);
xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
JS::Rooted<JS::Value> name(
cx, js::GetFunctionNativeReserved(callee, FIELD_SLOT));
if (!fieldName.init(cx, name.toString())) {
return false;
}
MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp));
// If a separate XBL scope is being used, the callee is not same-realm
// with the xbl prototype, and the object is a cross-compartment wrapper.
xblProto = js::UncheckedUnwrap(xblProto);
JSAutoRealm ar2(cx, xblProto);
JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0);
protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate());
MOZ_ASSERT(protoBinding);
}
nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
MOZ_ASSERT(field);
nsresult rv = field->InstallField(thisObj, *protoBinding, installed);
if (NS_SUCCEEDED(rv)) {
return true;
}
if (!::JS_IsExceptionPending(cx)) {
xpc::Throw(cx, rv);
}
return false;
}
bool FieldGetterImpl(JSContext* cx, const JS::CallArgs& args) {
JS::Handle<JS::Value> thisv = args.thisv();
MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
// We should be in the realm of |this|. If we got here via nativeCall,
// |this| is not same-compartment with |callee|, and it's possible via
// asymmetric security semantics that |args.calleev()| is actually a security
// wrapper. In this case, we know we want to do an unsafe unwrap, and
// InstallXBLField knows how to handle cross-compartment pointers.
bool installed = false;
JS::Rooted<JSObject*> callee(cx,
js::UncheckedUnwrap(&args.calleev().toObject()));
JS::Rooted<jsid> id(cx);
if (!InstallXBLField(cx, callee, thisObj, &id, &installed)) {
return false;
}
if (!installed) {
args.rval().setUndefined();
return true;
}
return JS_GetPropertyById(cx, thisObj, id, args.rval());
}
static bool FieldGetter(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldGetterImpl>(
cx, args);
}
bool FieldSetterImpl(JSContext* cx, const JS::CallArgs& args) {
JS::Handle<JS::Value> thisv = args.thisv();
MOZ_ASSERT(ValueHasISupportsPrivate(thisv));
JS::Rooted<JSObject*> thisObj(cx, &thisv.toObject());
// We should be in the realm of |this|. If we got here via nativeCall,
// |this| is not same-compartment with |callee|, and it's possible via
// asymmetric security semantics that |args.calleev()| is actually a security
// wrapper. In this case, we know we want to do an unsafe unwrap, and
// InstallXBLField knows how to handle cross-compartment pointers.
bool installed = false;
JS::Rooted<JSObject*> callee(cx,
js::UncheckedUnwrap(&args.calleev().toObject()));
JS::Rooted<jsid> id(cx);
if (!InstallXBLField(cx, callee, thisObj, &id, &installed)) {
return false;
}
if (installed) {
if (!::JS_SetPropertyById(cx, thisObj, id, args.get(0))) {
return false;
}
}
args.rval().setUndefined();
return true;
}
static bool FieldSetter(JSContext* cx, unsigned argc, JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
return JS::CallNonGenericMethod<ValueHasISupportsPrivate, FieldSetterImpl>(
cx, args);
}
nsresult nsXBLProtoImplField::InstallAccessors(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) {
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
JS::Rooted<JSObject*> globalObject(
aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
JS::Rooted<JSObject*> scopeObject(
aCx, xpc::GetXBLScopeOrGlobal(aCx, globalObject));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
// Don't install it if the field is empty; see also InstallField which also
// must implement the not-empty requirement.
if (IsEmpty()) {
return NS_OK;
}
// Install a getter/setter pair which will resolve the field onto the actual
// object, when invoked.
// Get the field name as an id.
JS::Rooted<jsid> id(aCx);
JS::TwoByteChars chars(mName, NS_strlen(mName));
if (!JS_CharsToId(aCx, chars, &id)) return NS_ERROR_OUT_OF_MEMORY;
// Properties/Methods have historically taken precendence over fields. We
// install members first, so just bounce here if the property is already
// defined.
bool found = false;
if (!JS_AlreadyHasOwnPropertyById(aCx, aTargetClassObject, id, &found))
return NS_ERROR_FAILURE;
if (found) return NS_OK;
// FieldGetter and FieldSetter need to run in the XBL scope so that they can
// see through any SOWs on their targets.
// First, enter the XBL scope, and compile the functions there.
JSAutoRealm ar(aCx, scopeObject);
JS::Rooted<JS::Value> wrappedClassObj(aCx,
JS::ObjectValue(*aTargetClassObject));
if (!JS_WrapValue(aCx, &wrappedClassObj)) return NS_ERROR_OUT_OF_MEMORY;
JS::Rooted<JSObject*> get(
aCx, JS_GetFunctionObject(
js::NewFunctionByIdWithReserved(aCx, FieldGetter, 0, 0, id)));
if (!get) {
return NS_ERROR_OUT_OF_MEMORY;
}
js::SetFunctionNativeReserved(get, XBLPROTO_SLOT, wrappedClassObj);
js::SetFunctionNativeReserved(get, FIELD_SLOT,
JS::StringValue(JSID_TO_STRING(id)));
JS::Rooted<JSObject*> set(
aCx, JS_GetFunctionObject(
js::NewFunctionByIdWithReserved(aCx, FieldSetter, 1, 0, id)));
if (!set) {
return NS_ERROR_OUT_OF_MEMORY;
}
js::SetFunctionNativeReserved(set, XBLPROTO_SLOT, wrappedClassObj);
js::SetFunctionNativeReserved(set, FIELD_SLOT,
JS::StringValue(JSID_TO_STRING(id)));
// Now, re-enter the class object's scope, wrap the getters/setters, and
// define them there.
JSAutoRealm ar2(aCx, aTargetClassObject);
if (!JS_WrapObject(aCx, &get) || !JS_WrapObject(aCx, &set)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, get, set,
AccessorAttributes())) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult nsXBLProtoImplField::InstallField(
JS::Handle<JSObject*> aBoundNode,
const nsXBLPrototypeBinding& aProtoBinding, bool* aDidInstall) const {
MOZ_ASSERT(aBoundNode,
"uh-oh, bound node should NOT be null or bad things will happen");
*aDidInstall = false;
// Empty fields are treated as not actually present.
if (IsEmpty()) {
return NS_OK;
}
nsAutoMicroTask mt;
nsAutoCString uriSpec;
nsresult rv = aProtoBinding.DocURI()->GetSpec(uriSpec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsIGlobalObject* globalObject = xpc::WindowGlobalOrNull(aBoundNode);
if (!globalObject) {
return NS_OK;
}
// We are going to run script via EvaluateString, so we need a script entry
// point, but as this is XBL related it does not appear in the HTML spec.
// We need an actual JSContext to do GetXBLScopeOrGlobal, and it needs to
// be in the realm of globalObject. But we want our XBL execution scope
// to be our entry global.
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return NS_ERROR_UNEXPECTED;
}
MOZ_ASSERT(!::JS_IsExceptionPending(jsapi.cx()),
"Shouldn't get here when an exception is pending!");
// Note: the UNWRAP_OBJECT may mutate boundNode; don't use it after that call.
JS::Rooted<JSObject*> boundNode(jsapi.cx(), aBoundNode);
Element* boundElement = nullptr;
rv = UNWRAP_OBJECT(Element, &boundNode, boundElement);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// First, enter the xbl scope, build the element's scope chain, and use
// that as the scope chain for the evaluation.
JS::Rooted<JSObject*> scopeObject(
jsapi.cx(), xpc::GetXBLScopeOrGlobal(jsapi.cx(), aBoundNode));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
AutoEntryScript aes(scopeObject, "XBL <field> initialization", true);
JSContext* cx = aes.cx();
JS::Rooted<JS::Value> result(cx);
JS::CompileOptions options(cx);
options.setFileAndLine(uriSpec.get(), mLineNumber);
JS::RootedVector<JSObject*> scopeChain(cx);
if (!nsJSUtils::GetScopeChainForXBL(cx, boundElement, aProtoBinding,
&scopeChain)) {
return NS_ERROR_OUT_OF_MEMORY;
}
rv = NS_OK;
{
nsJSUtils::ExecutionContext exec(cx, scopeObject);
exec.SetScopeChain(scopeChain);
exec.Compile(options, nsDependentString(mFieldText, mFieldTextLength));
rv = exec.ExecScript(&result);
}
if (NS_FAILED(rv)) {
return rv;
}
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW) {
// Report the exception now, before we try using the JSContext for
// the JS_DefineUCProperty call. Note that this reports in our current
// realm, which is the XBL scope.
aes.ReportException();
}
// Now, enter the node's realm, wrap the eval result, and define it on
// the bound node.
JSAutoRealm ar2(cx, aBoundNode);
nsDependentString name(mName);
if (!JS_WrapValue(cx, &result) ||
!::JS_DefineUCProperty(cx, aBoundNode,
reinterpret_cast<const char16_t*>(mName),
name.Length(), result, mJSAttributes)) {
return NS_ERROR_OUT_OF_MEMORY;
}
*aDidInstall = true;
return NS_OK;
}
nsresult nsXBLProtoImplField::Read(nsIObjectInputStream* aStream) {
nsAutoString name;
nsresult rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
mName = ToNewUnicode(name);
rv = aStream->Read32(&mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString fieldText;
rv = aStream->ReadString(fieldText);
NS_ENSURE_SUCCESS(rv, rv);
mFieldTextLength = fieldText.Length();
if (mFieldTextLength) mFieldText = ToNewUnicode(fieldText);
return NS_OK;
}
nsresult nsXBLProtoImplField::Write(nsIObjectOutputStream* aStream) {
XBLBindingSerializeDetails type = XBLBinding_Serialize_Field;
if (mJSAttributes & JSPROP_READONLY) {
type |= XBLBinding_Serialize_ReadOnly;
}
nsresult rv = aStream->Write8(type);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write32(mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
return aStream->WriteWStringZ(mFieldText ? mFieldText : u"");
}

View File

@ -1,60 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLProtoImplField_h__
#define nsXBLProtoImplField_h__
#include "nsAtom.h"
#include "nsString.h"
#include "jsapi.h"
#include "nsString.h"
#include "nsXBLProtoImplMember.h"
class nsIObjectInputStream;
class nsIObjectOutputStream;
class nsIURI;
class nsXBLProtoImplField {
public:
nsXBLProtoImplField(const char16_t* aName, const char16_t* aReadOnly);
explicit nsXBLProtoImplField(const bool aIsReadOnly);
~nsXBLProtoImplField();
void AppendFieldText(const nsAString& aText);
void SetLineNumber(uint32_t aLineNumber) { mLineNumber = aLineNumber; }
nsXBLProtoImplField* GetNext() const { return mNext; }
void SetNext(nsXBLProtoImplField* aNext) { mNext = aNext; }
nsresult InstallField(JS::Handle<JSObject*> aBoundNode,
const nsXBLPrototypeBinding& aProtoBinding,
bool* aDidInstall) const;
nsresult InstallAccessors(JSContext* aCx,
JS::Handle<JSObject*> aTargetClassObject);
nsresult Read(nsIObjectInputStream* aStream);
nsresult Write(nsIObjectOutputStream* aStream);
const char16_t* GetName() const { return mName; }
unsigned AccessorAttributes() const {
return JSPROP_GETTER | JSPROP_SETTER |
(mJSAttributes & (JSPROP_ENUMERATE | JSPROP_PERMANENT));
}
bool IsEmpty() const { return mFieldTextLength == 0; }
protected:
nsXBLProtoImplField* mNext;
char16_t* mName;
char16_t* mFieldText;
uint32_t mFieldTextLength;
uint32_t mLineNumber;
unsigned mJSAttributes;
};
#endif // nsXBLProtoImplField_h__

View File

@ -1,90 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLProtoImplMember_h__
#define nsXBLProtoImplMember_h__
#include "nsAtom.h"
#include "nsString.h"
#include "nsString.h"
#include "nsIServiceManager.h"
#include "nsContentUtils.h" // For NS_CONTENT_DELETE_LIST_MEMBER.
#include "nsCycleCollectionParticipant.h"
class nsIObjectOutputStream;
struct nsXBLTextWithLineNumber {
char16_t* mText;
uint32_t mLineNumber;
nsXBLTextWithLineNumber() : mText(nullptr), mLineNumber(0) {
MOZ_COUNT_CTOR(nsXBLTextWithLineNumber);
}
~nsXBLTextWithLineNumber() {
MOZ_COUNT_DTOR(nsXBLTextWithLineNumber);
if (mText) {
free(mText);
}
}
void AppendText(const nsAString& aText) {
if (mText) {
char16_t* temp = mText;
mText = ToNewUnicode(nsDependentString(temp) + aText);
free(temp);
} else {
mText = ToNewUnicode(aText);
}
}
char16_t* GetText() { return mText; }
void SetLineNumber(uint32_t aLineNumber) { mLineNumber = aLineNumber; }
uint32_t GetLineNumber() { return mLineNumber; }
};
class nsXBLProtoImplMember {
public:
explicit nsXBLProtoImplMember(const char16_t* aName)
: mNext(nullptr), mExposeToUntrustedContent(false) {
mName = ToNewUnicode(nsDependentString(aName));
}
virtual ~nsXBLProtoImplMember() {
free(mName);
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLProtoImplMember, this, mNext);
}
nsXBLProtoImplMember* GetNext() { return mNext; }
void SetNext(nsXBLProtoImplMember* aNext) { mNext = aNext; }
bool ShouldExposeToUntrustedContent() { return mExposeToUntrustedContent; }
void SetExposeToUntrustedContent(bool aExpose) {
mExposeToUntrustedContent = aExpose;
}
const char16_t* GetName() { return mName; }
virtual nsresult InstallMember(JSContext* aCx,
JS::Handle<JSObject*> aTargetClassObject) = 0;
virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi,
const nsString& aClassStr,
JS::Handle<JSObject*> aClassObject) = 0;
virtual void Trace(const TraceCallbacks& aCallbacks, void* aClosure) = 0;
virtual nsresult Write(nsIObjectOutputStream* aStream) { return NS_OK; }
protected:
nsXBLProtoImplMember* mNext; // The members of an implementation are chained.
char16_t* mName; // The name of the field, method, or property.
bool mExposeToUntrustedContent; // If this binding is installed on an element
// in an untrusted scope, should this
// implementation member be accessible to the
// content?
};
#endif // nsXBLProtoImplMember_h__

View File

@ -1,328 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsAtom.h"
#include "nsString.h"
#include "jsapi.h"
#include "nsIContent.h"
#include "mozilla/dom/Document.h"
#include "nsIGlobalObject.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
#include "nsXBLProtoImplMethod.h"
#include "nsJSUtils.h"
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h"
#include "xpcpublic.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ScriptSettings.h"
using namespace mozilla;
using namespace mozilla::dom;
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const char16_t* aName)
: nsXBLProtoImplMember(aName), mMethod() {
MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
}
nsXBLProtoImplMethod::~nsXBLProtoImplMethod() {
MOZ_COUNT_DTOR(nsXBLProtoImplMethod);
if (!IsCompiled()) {
delete GetUncompiledMethod();
}
}
void nsXBLProtoImplMethod::AppendBodyText(const nsAString& aText) {
MOZ_ASSERT(!IsCompiled(),
"Must not be compiled when accessing uncompiled method");
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
SetUncompiledMethod(uncompiledMethod);
}
uncompiledMethod->AppendBodyText(aText);
}
void nsXBLProtoImplMethod::AddParameter(const nsAString& aText) {
MOZ_ASSERT(!IsCompiled(),
"Must not be compiled when accessing uncompiled method");
if (aText.IsEmpty()) {
NS_WARNING("Empty name attribute in xbl:parameter!");
return;
}
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
SetUncompiledMethod(uncompiledMethod);
}
uncompiledMethod->AddParameter(aText);
}
void nsXBLProtoImplMethod::SetLineNumber(uint32_t aLineNumber) {
MOZ_ASSERT(!IsCompiled(),
"Must not be compiled when accessing uncompiled method");
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
if (!uncompiledMethod) {
uncompiledMethod = new nsXBLUncompiledMethod();
SetUncompiledMethod(uncompiledMethod);
}
uncompiledMethod->SetLineNumber(aLineNumber);
}
nsresult nsXBLProtoImplMethod::InstallMember(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) {
MOZ_ASSERT(IsCompiled(), "Should not be installing an uncompiled method");
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
#ifdef DEBUG
{
JS::Rooted<JSObject*> globalObject(
aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
globalObject == xpc::GetXBLScope(aCx, globalObject));
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
}
#endif
JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
if (jsMethodObject) {
nsDependentString name(mName);
JS::Rooted<JSObject*> method(aCx,
JS::CloneFunctionObject(aCx, jsMethodObject));
NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY);
if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
static_cast<const char16_t*>(mName),
name.Length(), method, JSPROP_ENUMERATE)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
return NS_OK;
}
nsresult nsXBLProtoImplMethod::CompileMember(
AutoJSAPI& jsapi, const nsString& aClassStr,
JS::Handle<JSObject*> aClassObject) {
AssertInCompilationScope();
MOZ_ASSERT(!IsCompiled(), "Trying to compile an already-compiled method");
MOZ_ASSERT(aClassObject, "Must have class object to compile");
nsXBLUncompiledMethod* uncompiledMethod = GetUncompiledMethod();
// No parameters or body was supplied, so don't install method.
if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
SetCompiledMethod(nullptr);
return NS_OK;
}
// Don't install method if no name was supplied.
if (!mName) {
delete uncompiledMethod;
// Early return after which we consider ourselves compiled.
SetCompiledMethod(nullptr);
return NS_OK;
}
// We have a method.
// Allocate an array for our arguments.
int32_t paramCount = uncompiledMethod->GetParameterCount();
char** args = nullptr;
if (paramCount > 0) {
args = new char*[paramCount];
// Add our parameters to our args array.
int32_t argPos = 0;
for (nsXBLParameter* curr = uncompiledMethod->mParameters; curr;
curr = curr->mNext) {
args[argPos] = curr->mName;
argPos++;
}
}
// Get the body
nsDependentString body;
char16_t* bodyText = uncompiledMethod->mBodyText.GetText();
if (bodyText) body.Rebind(bodyText);
// Now that we have a body and args, compile the function
// and then define it.
NS_ConvertUTF16toUTF8 cname(mName);
NS_ConvertUTF16toUTF8 functionUri(aClassStr);
int32_t hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
functionUri.Truncate(hash);
}
JSContext* cx = jsapi.cx();
JSAutoRealm ar(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(),
uncompiledMethod->mBodyText.GetLineNumber());
JS::Rooted<JSObject*> methodObject(cx);
JS::RootedVector<JSObject*> emptyVector(cx);
nsresult rv = nsJSUtils::CompileFunction(
jsapi, emptyVector, options, cname, paramCount,
const_cast<const char**>(args), body, methodObject.address());
// Destroy our uncompiled method and delete our arg list.
delete uncompiledMethod;
delete[] args;
if (NS_FAILED(rv)) {
SetUncompiledMethod(nullptr);
return rv;
}
SetCompiledMethod(methodObject);
return NS_OK;
}
void nsXBLProtoImplMethod::Trace(const TraceCallbacks& aCallbacks,
void* aClosure) {
if (IsCompiled() && GetCompiledMethodPreserveColor()) {
aCallbacks.Trace(&mMethod.AsHeapObject(), "mMethod", aClosure);
}
}
nsresult nsXBLProtoImplMethod::Read(nsIObjectInputStream* aStream) {
AssertInCompilationScope();
MOZ_ASSERT(!IsCompiled() && !GetUncompiledMethod());
AutoJSContext cx;
JS::Rooted<JSObject*> methodObject(cx);
nsresult rv = XBL_DeserializeFunction(aStream, &methodObject);
if (NS_FAILED(rv)) {
SetUncompiledMethod(nullptr);
return rv;
}
SetCompiledMethod(methodObject);
return NS_OK;
}
nsresult nsXBLProtoImplMethod::Write(nsIObjectOutputStream* aStream) {
AssertInCompilationScope();
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethodPreserveColor()) {
nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSObject*> method(RootingCx(), GetCompiledMethod());
return XBL_SerializeFunction(aStream, method);
}
return NS_OK;
}
nsresult nsXBLProtoImplAnonymousMethod::Execute(
nsIContent* aBoundElement, const nsXBLPrototypeBinding& aProtoBinding) {
MOZ_ASSERT(aBoundElement->IsElement());
MOZ_ASSERT(IsCompiled(), "Can't execute uncompiled method");
if (!GetCompiledMethod()) {
// Nothing to do here
return NS_OK;
}
// Get the script context the same way
// nsXBLProtoImpl::InstallImplementation does.
Document* document = aBoundElement->OwnerDoc();
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(document->GetInnerWindow());
if (!global) {
return NS_OK;
}
nsAutoMicroTask mt;
// We are going to run script via JS::Call, so we need a script entry point,
// but as this is XBL related it does not appear in the HTML spec.
// We need an actual JSContext to do GetXBLScopeOrGlobal, and it needs to
// be in the compartment of globalObject. But we want our XBL execution scope
// to be our entry global.
AutoJSAPI jsapi;
if (!jsapi.Init(global)) {
return NS_ERROR_UNEXPECTED;
}
JS::Rooted<JSObject*> scopeObject(
jsapi.cx(),
xpc::GetXBLScopeOrGlobal(jsapi.cx(), global->GetGlobalJSObject()));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
dom::AutoEntryScript aes(scopeObject,
"XBL <constructor>/<destructor> invocation", true);
JSContext* cx = aes.cx();
JS::RootedVector<JSObject*> scopeChain(cx);
if (!nsJSUtils::GetScopeChainForXBL(cx, aBoundElement->AsElement(),
aProtoBinding, &scopeChain)) {
return NS_ERROR_OUT_OF_MEMORY;
}
MOZ_ASSERT(scopeChain.length() != 0);
// Clone the function object, using our scope chain (for backwards
// compat to the days when this was an event handler).
JS::Rooted<JSObject*> jsMethodObject(cx, GetCompiledMethod());
JS::Rooted<JSObject*> method(
cx, JS::CloneFunctionObject(cx, jsMethodObject, scopeChain));
if (!method) return NS_ERROR_OUT_OF_MEMORY;
// Now call the method
// Check whether script is enabled.
bool scriptAllowed = xpc::Scriptability::Get(method).Allowed();
if (scriptAllowed) {
JS::Rooted<JS::Value> retval(cx);
JS::Rooted<JS::Value> methodVal(cx, JS::ObjectValue(*method));
// No need to check the return here as AutoEntryScript has taken ownership
// of error reporting.
::JS::Call(cx, scopeChain[0], methodVal, JS::HandleValueArray::empty(),
&retval);
}
return NS_OK;
}
nsresult nsXBLProtoImplAnonymousMethod::Write(
nsIObjectOutputStream* aStream, XBLBindingSerializeDetails aType) {
AssertInCompilationScope();
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethodPreserveColor()) {
nsresult rv = aStream->Write8(aType);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSObject*> method(RootingCx(), GetCompiledMethod());
rv = XBL_SerializeFunction(aStream, method);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

View File

@ -1,139 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLProtoImplMethod_h__
#define nsXBLProtoImplMethod_h__
#include "mozilla/Attributes.h"
#include "nsAtom.h"
#include "nsString.h"
#include "nsString.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLSerialize.h"
class nsIContent;
struct nsXBLParameter {
nsXBLParameter* mNext;
char* mName;
explicit nsXBLParameter(const nsAString& aName) {
MOZ_COUNT_CTOR(nsXBLParameter);
mName = ToNewCString(aName);
mNext = nullptr;
}
~nsXBLParameter() {
MOZ_COUNT_DTOR(nsXBLParameter);
free(mName);
NS_CONTENT_DELETE_LIST_MEMBER(nsXBLParameter, this, mNext);
}
};
struct nsXBLUncompiledMethod {
nsXBLParameter* mParameters;
nsXBLParameter* mLastParameter;
nsXBLTextWithLineNumber mBodyText;
nsXBLUncompiledMethod()
: mParameters(nullptr), mLastParameter(nullptr), mBodyText() {
MOZ_COUNT_CTOR(nsXBLUncompiledMethod);
}
~nsXBLUncompiledMethod() {
MOZ_COUNT_DTOR(nsXBLUncompiledMethod);
delete mParameters;
}
int32_t GetParameterCount() {
int32_t result = 0;
for (nsXBLParameter* curr = mParameters; curr; curr = curr->mNext) result++;
return result;
}
void AppendBodyText(const nsAString& aText) { mBodyText.AppendText(aText); }
void AddParameter(const nsAString& aText) {
nsXBLParameter* param = new nsXBLParameter(aText);
if (!mParameters)
mParameters = param;
else
mLastParameter->mNext = param;
mLastParameter = param;
}
void SetLineNumber(uint32_t aLineNumber) {
mBodyText.SetLineNumber(aLineNumber);
}
};
class nsXBLProtoImplMethod : public nsXBLProtoImplMember {
public:
explicit nsXBLProtoImplMethod(const char16_t* aName);
virtual ~nsXBLProtoImplMethod();
void AppendBodyText(const nsAString& aBody);
void AddParameter(const nsAString& aName);
void SetLineNumber(uint32_t aLineNumber);
virtual nsresult InstallMember(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) override;
virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi,
const nsString& aClassStr,
JS::Handle<JSObject*> aClassObject) override;
virtual void Trace(const TraceCallbacks& aCallbacks, void* aClosure) override;
nsresult Read(nsIObjectInputStream* aStream);
virtual nsresult Write(nsIObjectOutputStream* aStream) override;
bool IsCompiled() const { return mMethod.IsCompiled(); }
void SetUncompiledMethod(nsXBLUncompiledMethod* aUncompiledMethod) {
mMethod.SetUncompiled(aUncompiledMethod);
}
nsXBLUncompiledMethod* GetUncompiledMethod() const {
return mMethod.GetUncompiled();
}
protected:
void SetCompiledMethod(JSObject* aCompiledMethod) {
mMethod.SetJSFunction(aCompiledMethod);
}
JSObject* GetCompiledMethod() const { return mMethod.GetJSFunction(); }
JSObject* GetCompiledMethodPreserveColor() const {
return mMethod.GetJSFunctionPreserveColor();
}
JS::Heap<nsXBLMaybeCompiled<nsXBLUncompiledMethod> > mMethod;
};
class nsXBLProtoImplAnonymousMethod : public nsXBLProtoImplMethod {
public:
explicit nsXBLProtoImplAnonymousMethod(const char16_t* aName)
: nsXBLProtoImplMethod(aName) {}
nsresult Execute(nsIContent* aBoundElement, const nsXBLPrototypeBinding&);
// Override InstallMember; these methods never get installed as members on
// binding instantiations (though they may hang out in mMembers on the
// prototype implementation).
virtual nsresult InstallMember(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) override {
return NS_OK;
}
using nsXBLProtoImplMethod::Write;
nsresult Write(nsIObjectOutputStream* aStream,
XBLBindingSerializeDetails aType);
};
#endif // nsXBLProtoImplMethod_h__

View File

@ -1,345 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsAtom.h"
#include "nsString.h"
#include "jsapi.h"
#include "nsIContent.h"
#include "nsXBLProtoImplProperty.h"
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
#include "nsJSUtils.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLSerialize.h"
#include "xpcpublic.h"
using namespace mozilla;
using namespace mozilla::dom;
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const char16_t* aName,
const char16_t* aGetter,
const char16_t* aSetter,
const char16_t* aReadOnly,
uint32_t aLineNumber)
: nsXBLProtoImplMember(aName),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
,
mIsCompiled(false)
#endif
{
MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
if (aReadOnly) {
nsAutoString readOnly;
readOnly.Assign(*aReadOnly);
if (readOnly.LowerCaseEqualsLiteral("true"))
mJSAttributes |= JSPROP_READONLY;
}
if (aGetter) {
AppendGetterText(nsDependentString(aGetter));
SetGetterLineNumber(aLineNumber);
}
if (aSetter) {
AppendSetterText(nsDependentString(aSetter));
SetSetterLineNumber(aLineNumber);
}
}
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const char16_t* aName,
const bool aIsReadOnly)
: nsXBLProtoImplMember(aName),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
,
mIsCompiled(false)
#endif
{
MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
if (aIsReadOnly) mJSAttributes |= JSPROP_READONLY;
}
nsXBLProtoImplProperty::~nsXBLProtoImplProperty() {
MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
if (!mGetter.IsCompiled()) {
delete mGetter.GetUncompiled();
}
if (!mSetter.IsCompiled()) {
delete mSetter.GetUncompiled();
}
}
void nsXBLProtoImplProperty::EnsureUncompiledText(PropertyOp& aPropertyOp) {
if (!aPropertyOp.GetUncompiled()) {
nsXBLTextWithLineNumber* text = new nsXBLTextWithLineNumber();
aPropertyOp.SetUncompiled(text);
}
}
void nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText) {
MOZ_ASSERT(!mIsCompiled, "Must not be compiled when accessing getter text");
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->AppendText(aText);
}
void nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText) {
MOZ_ASSERT(!mIsCompiled, "Must not be compiled when accessing setter text");
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->AppendText(aText);
}
void nsXBLProtoImplProperty::SetGetterLineNumber(uint32_t aLineNumber) {
MOZ_ASSERT(!mIsCompiled, "Must not be compiled when accessing getter text");
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
void nsXBLProtoImplProperty::SetSetterLineNumber(uint32_t aLineNumber) {
MOZ_ASSERT(!mIsCompiled, "Must not be compiled when accessing setter text");
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
const char* gPropertyArgs[] = {"val"};
nsresult nsXBLProtoImplProperty::InstallMember(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) {
MOZ_ASSERT(mIsCompiled, "Should not be installing an uncompiled property");
MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
#ifdef DEBUG
{
JS::Rooted<JSObject*> globalObject(
aCx, JS::GetNonCCWObjectGlobal(aTargetClassObject));
MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
globalObject == xpc::GetXBLScope(aCx, globalObject));
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
}
#endif
JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
if (getter || setter) {
if (getter) {
if (!(getter = JS::CloneFunctionObject(aCx, getter)))
return NS_ERROR_OUT_OF_MEMORY;
}
if (setter) {
if (!(setter = JS::CloneFunctionObject(aCx, setter)))
return NS_ERROR_OUT_OF_MEMORY;
}
nsDependentString name(mName);
if (!::JS_DefineUCProperty(aCx, aTargetClassObject,
static_cast<const char16_t*>(mName),
name.Length(), getter, setter, mJSAttributes))
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsresult nsXBLProtoImplProperty::CompileMember(
AutoJSAPI& jsapi, const nsString& aClassStr,
JS::Handle<JSObject*> aClassObject) {
AssertInCompilationScope();
MOZ_ASSERT(!mIsCompiled, "Trying to compile an already-compiled property");
MOZ_ASSERT(aClassObject, "Must have class object to compile");
MOZ_ASSERT(!mGetter.IsCompiled() && !mSetter.IsCompiled());
JSContext* cx = jsapi.cx();
if (!mName)
return NS_ERROR_FAILURE; // Without a valid name, we can't install the
// member.
// We have a property.
nsresult rv = NS_OK;
nsAutoCString functionUri;
if (mGetter.GetUncompiled() || mSetter.GetUncompiled()) {
functionUri = NS_ConvertUTF16toUTF8(aClassStr);
int32_t hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
functionUri.Truncate(hash);
}
}
bool deletedGetter = false;
nsXBLTextWithLineNumber* getterText = mGetter.GetUncompiled();
if (getterText && getterText->GetText()) {
nsDependentString getter(getterText->GetText());
if (!getter.IsEmpty()) {
JSAutoRealm ar(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), getterText->GetLineNumber());
nsCString name =
NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
JS::Rooted<JSObject*> getterObject(cx);
JS::RootedVector<JSObject*> emptyVector(cx);
rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 0,
nullptr, getter, getterObject.address());
delete getterText;
deletedGetter = true;
mGetter.SetJSFunction(getterObject);
if (mGetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_GETTER;
}
if (NS_FAILED(rv)) {
mGetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_GETTER;
/*chaining to return failure*/
}
}
} // if getter is not empty
if (!deletedGetter) { // Empty getter
delete getterText;
mGetter.SetJSFunction(nullptr);
}
if (NS_FAILED(rv)) {
// We failed to compile our getter. So either we've set it to null, or
// it's still set to the text object. In either case, it's safe to return
// the error here, since then we'll be cleaned up as uncompiled and that
// will be ok. Going on and compiling the setter and _then_ returning an
// error, on the other hand, will try to clean up a compiled setter as
// uncompiled and crash.
return rv;
}
bool deletedSetter = false;
nsXBLTextWithLineNumber* setterText = mSetter.GetUncompiled();
if (setterText && setterText->GetText()) {
nsDependentString setter(setterText->GetText());
if (!setter.IsEmpty()) {
JSAutoRealm ar(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), setterText->GetLineNumber());
nsCString name =
NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
JS::Rooted<JSObject*> setterObject(cx);
JS::RootedVector<JSObject*> emptyVector(cx);
rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 1,
gPropertyArgs, setter,
setterObject.address());
delete setterText;
deletedSetter = true;
mSetter.SetJSFunction(setterObject);
if (mSetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_SETTER;
}
if (NS_FAILED(rv)) {
mSetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_SETTER;
/*chaining to return failure*/
}
}
} // if setter wasn't empty....
if (!deletedSetter) { // Empty setter
delete setterText;
mSetter.SetJSFunction(nullptr);
}
#ifdef DEBUG
mIsCompiled = NS_SUCCEEDED(rv);
#endif
return rv;
}
void nsXBLProtoImplProperty::Trace(const TraceCallbacks& aCallbacks,
void* aClosure) {
if (mJSAttributes & JSPROP_GETTER) {
aCallbacks.Trace(&mGetter.AsHeapObject(), "mGetter", aClosure);
}
if (mJSAttributes & JSPROP_SETTER) {
aCallbacks.Trace(&mSetter.AsHeapObject(), "mSetter", aClosure);
}
}
nsresult nsXBLProtoImplProperty::Read(nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType) {
AssertInCompilationScope();
MOZ_ASSERT(!mIsCompiled);
MOZ_ASSERT(!mGetter.GetUncompiled() && !mSetter.GetUncompiled());
AutoJSContext cx;
JS::Rooted<JSObject*> getterObject(cx);
if (aType == XBLBinding_Serialize_GetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
nsresult rv = XBL_DeserializeFunction(aStream, &getterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSAttributes |= JSPROP_GETTER;
}
mGetter.SetJSFunction(getterObject);
JS::Rooted<JSObject*> setterObject(cx);
if (aType == XBLBinding_Serialize_SetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
nsresult rv = XBL_DeserializeFunction(aStream, &setterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSAttributes |= JSPROP_SETTER;
}
mSetter.SetJSFunction(setterObject);
#ifdef DEBUG
mIsCompiled = true;
#endif
return NS_OK;
}
nsresult nsXBLProtoImplProperty::Write(nsIObjectOutputStream* aStream) {
AssertInCompilationScope();
XBLBindingSerializeDetails type;
if (mJSAttributes & JSPROP_GETTER) {
type = mJSAttributes & JSPROP_SETTER
? XBLBinding_Serialize_GetterSetterProperty
: XBLBinding_Serialize_GetterProperty;
} else {
type = XBLBinding_Serialize_SetterProperty;
}
if (mJSAttributes & JSPROP_READONLY) {
type |= XBLBinding_Serialize_ReadOnly;
}
nsresult rv = aStream->Write8(type);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT_IF(mJSAttributes & (JSPROP_GETTER | JSPROP_SETTER), mIsCompiled);
if (mJSAttributes & JSPROP_GETTER) {
JS::Rooted<JSObject*> function(RootingCx(), mGetter.GetJSFunction());
rv = XBL_SerializeFunction(aStream, function);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mJSAttributes & JSPROP_SETTER) {
JS::Rooted<JSObject*> function(RootingCx(), mSetter.GetJSFunction());
rv = XBL_SerializeFunction(aStream, function);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

View File

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLProtoImplProperty_h__
#define nsXBLProtoImplProperty_h__
#include "mozilla/Attributes.h"
#include "nsAtom.h"
#include "nsString.h"
#include "nsString.h"
#include "nsXBLSerialize.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
class nsXBLProtoImplProperty : public nsXBLProtoImplMember {
public:
nsXBLProtoImplProperty(const char16_t* aName, const char16_t* aGetter,
const char16_t* aSetter, const char16_t* aReadOnly,
uint32_t aLineNumber);
nsXBLProtoImplProperty(const char16_t* aName, const bool aIsReadOnly);
virtual ~nsXBLProtoImplProperty();
void AppendGetterText(const nsAString& aGetter);
void AppendSetterText(const nsAString& aSetter);
void SetGetterLineNumber(uint32_t aLineNumber);
void SetSetterLineNumber(uint32_t aLineNumber);
virtual nsresult InstallMember(
JSContext* aCx, JS::Handle<JSObject*> aTargetClassObject) override;
virtual nsresult CompileMember(mozilla::dom::AutoJSAPI& jsapi,
const nsString& aClassStr,
JS::Handle<JSObject*> aClassObject) override;
virtual void Trace(const TraceCallbacks& aCallback, void* aClosure) override;
nsresult Read(nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType);
virtual nsresult Write(nsIObjectOutputStream* aStream) override;
protected:
typedef JS::Heap<nsXBLMaybeCompiled<nsXBLTextWithLineNumber> > PropertyOp;
void EnsureUncompiledText(PropertyOp& aPropertyOp);
// The raw text for the getter, or the JS object (after compilation).
PropertyOp mGetter;
// The raw text for the setter, or the JS object (after compilation).
PropertyOp mSetter;
unsigned mJSAttributes; // A flag for all our JS properties
// (getter/setter/readonly/shared/enum)
#ifdef DEBUG
bool mIsCompiled;
#endif
};
#endif // nsXBLProtoImplProperty_h__

File diff suppressed because it is too large Load Diff

View File

@ -1,319 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLPrototypeBinding_h__
#define nsXBLPrototypeBinding_h__
#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsICSSLoaderObserver.h"
#include "nsInterfaceHashtable.h"
#include "nsXBLDocumentInfo.h"
#include "nsXBLProtoImpl.h"
#include "nsXBLProtoImplMethod.h"
#include "nsXBLPrototypeHandler.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/WeakPtr.h"
class nsAtom;
class nsIContent;
class nsXBLAttributeEntry;
class nsXBLBinding;
class nsXBLProtoImplField;
// *********************************************************************/
// The XBLPrototypeBinding class
// Instances of this class are owned by the nsXBLDocumentInfo object returned
// by XBLDocumentInfo(). Consumers who want to refcount things should refcount
// that.
class nsXBLPrototypeBinding final
: public mozilla::SupportsWeakPtr<nsXBLPrototypeBinding> {
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsXBLPrototypeBinding)
mozilla::dom::Element* GetBindingElement() const { return mBinding; }
void SetBindingElement(mozilla::dom::Element* aElement);
nsIURI* BindingURI() const { return mBindingURI; }
nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }
// Checks if aURI refers to this binding by comparing to both possible
// binding URIs.
bool CompareBindingURI(nsIURI* aURI) const;
bool GetAllowScripts() const;
nsresult BindingAttached(nsIContent* aBoundElement);
nsresult BindingDetached(nsIContent* aBoundElement);
nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; }
void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) {
mPrototypeHandler = aHandler;
}
nsXBLProtoImplAnonymousMethod* GetConstructor();
nsresult SetConstructor(nsXBLProtoImplAnonymousMethod* aConstructor);
nsXBLProtoImplAnonymousMethod* GetDestructor();
nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor);
nsXBLProtoImplField* FindField(const nsString& aFieldName) const {
return mImplementation ? mImplementation->FindField(aFieldName) : nullptr;
}
// Resolve all the fields for this binding on the object |obj|.
// False return means a JS exception was set.
bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const {
return !mImplementation || mImplementation->ResolveAllFields(cx, obj);
}
// Undefine all our fields from object |obj| (which should be a
// JSObject for a bound element).
void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const {
if (mImplementation) {
mImplementation->UndefineFields(cx, obj);
}
}
const nsString& ClassName() const {
return mImplementation ? mImplementation->mClassName : EmptyString();
}
nsresult InitClass(const nsString& aClassName, JSContext* aContext,
JS::Handle<JSObject*> aScriptObject,
JS::MutableHandle<JSObject*> aClassObject, bool* aNew);
nsresult ConstructInterfaceTable(const nsAString& aImpls);
void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
nsXBLProtoImpl* GetImplementation() { return mImplementation; }
nsresult InstallImplementation(nsXBLBinding* aBinding);
bool HasImplementation() const { return mImplementation != nullptr; }
void AttributeChanged(nsAtom* aAttribute, int32_t aNameSpaceID,
bool aRemoveFlag,
mozilla::dom::Element* aChangedElement,
nsIContent* aAnonymousContent, bool aNotify);
void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }
nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }
void SetInitialAttributes(mozilla::dom::Element* aBoundElement,
nsIContent* aAnonymousContent);
nsAtom* GetBaseTag(int32_t* aNamespaceID);
void SetBaseTag(int32_t aNamespaceID, nsAtom* aTag);
bool ImplementsInterface(REFNSIID aIID) const;
void Initialize();
nsresult ResolveBaseBinding();
const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers() {
if (!mKeyHandlersRegistered) {
CreateKeyHandlers();
mKeyHandlersRegistered = true;
}
return &mKeyHandlers;
}
private:
nsresult Read(nsIObjectInputStream* aStream, nsXBLDocumentInfo* aDocInfo,
mozilla::dom::Document* aDocument, uint8_t aFlags);
/**
* Read a new binding from the stream aStream into the xbl document aDocument.
* aDocInfo should be the xbl document info for the binding document.
* aFlags can contain XBLBinding_Serialize_InheritStyle to indicate that
* mInheritStyle flag should be set, and XBLBinding_Serialize_IsFirstBinding
* to indicate the first binding in a document.
* XBLBinding_Serialize_BindToUntrustedContent indicates that
* nsXBLPrototypeBinding::mBindToUntrustedContent should be true.
*/
public:
static nsresult ReadNewBinding(nsIObjectInputStream* aStream,
nsXBLDocumentInfo* aDocInfo,
mozilla::dom::Document* aDocument,
uint8_t aFlags);
/**
* Write this binding to the stream.
*/
nsresult Write(nsIObjectOutputStream* aStream);
/**
* Read a content node from aStream and return it in aChild.
* aDocument and aNim are the document and node info manager for the document
* the child will be inserted into.
*/
nsresult ReadContentNode(nsIObjectInputStream* aStream,
mozilla::dom::Document* aDocument,
nsNodeInfoManager* aNim, nsIContent** aChild);
/**
* Write the content node aNode to aStream.
*
* This method is called recursively for each child descendant. For the
* topmost call, aNode must be an element.
*
* Text, CDATA and comment nodes are serialized as:
* the constant XBLBinding_Serialize_TextNode,
* XBLBinding_Serialize_CDATANode or XBLBinding_Serialize_CommentNode the text
* for the node Elements are serialized in the following format: node's
* namespace, written with WriteNamespace node's namespace prefix node's tag
* 32-bit attribute count
* table of attributes:
* attribute's namespace, written with WriteNamespace
* attribute's namespace prefix
* attribute's tag
* attribute's value
* attribute forwarding table:
* source namespace
* source attribute
* destination namespace
* destination attribute
* the constant XBLBinding_Serialize_NoMoreAttributes
* 32-bit count of the number of child nodes
* each child node is serialized in the same manner in sequence
* the constant XBLBinding_Serialize_NoContent
*/
nsresult WriteContentNode(nsIObjectOutputStream* aStream, nsIContent* aNode);
/**
* Read or write a namespace id from or to aStream. If the namespace matches
* one of the built-in ones defined in nsNameSpaceManager.h, it will be
* written as a single byte with that value. Otherwise,
* XBLBinding_Serialize_CustomNamespace is written out, followed by a string
* written with writeWStringZ.
*/
nsresult ReadNamespace(nsIObjectInputStream* aStream, int32_t& aNameSpaceID);
nsresult WriteNamespace(nsIObjectOutputStream* aStream, int32_t aNameSpaceID);
public:
nsXBLPrototypeBinding();
~nsXBLPrototypeBinding();
// Init must be called after construction to initialize the prototype
// binding. It may well throw errors (eg on out-of-memory). Do not confuse
// this with the Initialize() method, which must be called after the
// binding's handlers, properties, etc are all set.
nsresult Init(const nsACString& aRef, nsXBLDocumentInfo* aInfo,
mozilla::dom::Element* aElement, bool aFirstBinding = false);
void Traverse(nsCycleCollectionTraversalCallback& cb) const;
void Unlink();
void Trace(const TraceCallbacks& aCallbacks, void* aClosure) const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
// Internal member functions.
public:
/**
* GetImmediateChild locates the immediate child of our binding element which
* has the localname given by aTag and is in the XBL namespace.
*/
mozilla::dom::Element* GetImmediateChild(nsAtom* aTag);
mozilla::dom::Element* LocateInstance(mozilla::dom::Element* aBoundElt,
nsIContent* aTemplRoot,
nsIContent* aCopyRoot,
mozilla::dom::Element* aTemplChild);
bool SimpleScopeChain() const { return mSimpleScopeChain; }
bool BindToUntrustedContent() const { return mBindToUntrustedContent; }
typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>, nsXBLAttributeEntry>
InnerAttributeTable;
protected:
// Ensure that mAttributeTable has been created.
void EnsureAttributeTable();
// Ad an entry to the attribute table
void AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* aSourceTag,
int32_t aDestNamespaceID, nsAtom* aDestTag,
mozilla::dom::Element* aContent);
void ConstructAttributeTable(mozilla::dom::Element* aElement);
void CreateKeyHandlers();
// MEMBER VARIABLES
protected:
nsCOMPtr<nsIURI> mBindingURI;
nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only
// non-null on the first binding.
RefPtr<mozilla::dom::Element>
mBinding; // Strong. We own a ref to our content element in the binding
// doc.
nsAutoPtr<nsXBLPrototypeHandler>
mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
// the url of the base binding
nsCOMPtr<nsIURI> mBaseBindingURI;
nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes
// methods, properties, fields, the
// constructor, and the destructor).
// Weak. The docinfo will own our base binding.
mozilla::WeakPtr<nsXBLPrototypeBinding> mBaseBinding;
bool mCheckedBaseProto;
bool mKeyHandlersRegistered;
// FIXME(emilio): This is dead code now.
bool mBindToUntrustedContent;
// True if constructors, handlers, etc for this binding would skip the scope
// chain for parent elements and go directly to the document.
// FIXME(emilio): This is dead code now.
bool mSimpleScopeChain;
nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak,
// since it owns us.
// A table for attribute containers. Namespace IDs are used as
// keys in the table. Containers are InnerAttributeTables.
// This table is used to efficiently handle attribute changes.
nsAutoPtr<nsClassHashtable<nsUint32HashKey, InnerAttributeTable>>
mAttributeTable;
class IIDHashKey : public PLDHashEntryHdr {
public:
typedef const nsIID& KeyType;
typedef const nsIID* KeyTypePointer;
explicit IIDHashKey(const nsIID* aKey) : mKey(*aKey) {}
IIDHashKey(const IIDHashKey& aOther) : mKey(aOther.GetKey()) {}
~IIDHashKey() {}
KeyType GetKey() const { return mKey; }
bool KeyEquals(const KeyTypePointer aKey) const {
return mKey.Equals(*aKey);
}
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
// Just use the 32-bit m0 field.
return aKey->m0;
}
enum { ALLOW_MEMMOVE = true };
private:
nsIID mKey;
};
nsInterfaceHashtable<IIDHashKey, nsIContent>
mInterfaceTable; // A table of cached interfaces that we support.
nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,267 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLPrototypeHandler_h__
#define nsXBLPrototypeHandler_h__
#include "mozilla/EventForwards.h"
#include "mozilla/MemoryReporting.h"
#include "nsAtom.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIController.h"
#include "nsAutoPtr.h"
#include "nsXBLEventHandler.h"
#include "nsIWeakReference.h"
#include "nsCycleCollectionParticipant.h"
#include "js/TypeDecls.h"
class nsIContent;
class nsIObjectInputStream;
class nsIObjectOutputStream;
class nsXBLPrototypeBinding;
namespace mozilla {
struct IgnoreModifierState;
namespace dom {
class AutoJSAPI;
class Event;
class EventTarget;
class KeyboardEvent;
class MouseEvent;
class UIEvent;
} // namespace dom
namespace layers {
class KeyboardShortcut;
} // namespace layers
} // namespace mozilla
#define NS_HANDLER_TYPE_XBL_JS (1 << 0)
#define NS_HANDLER_TYPE_XBL_COMMAND (1 << 1)
#define NS_HANDLER_TYPE_XUL (1 << 2)
#define NS_HANDLER_HAS_ALLOW_UNTRUSTED_ATTR (1 << 4)
#define NS_HANDLER_ALLOW_UNTRUSTED (1 << 5)
#define NS_HANDLER_TYPE_SYSTEM (1 << 6)
#define NS_HANDLER_TYPE_PREVENTDEFAULT (1 << 7)
// XXX Use Event_Binding:: codes?
#define NS_PHASE_CAPTURING 1
#define NS_PHASE_TARGET 2
#define NS_PHASE_BUBBLING 3
// Values of the reserved attribute. When unset, the default value depends on
// the permissions.default.shortcuts preference.
enum XBLReservedKey : uint8_t {
XBLReservedKey_False = 0,
XBLReservedKey_True = 1,
XBLReservedKey_Unset = 2,
};
namespace mozilla {
namespace dom {
class Element;
class Event;
} // namespace dom
} // namespace mozilla
class nsXBLPrototypeHandler {
typedef mozilla::IgnoreModifierState IgnoreModifierState;
typedef mozilla::layers::KeyboardShortcut KeyboardShortcut;
typedef mozilla::Modifiers Modifiers;
public:
// This constructor is used by XBL handlers (both the JS and command shorthand
// variety)
nsXBLPrototypeHandler(const char16_t* aEvent, const char16_t* aPhase,
const char16_t* aAction, const char16_t* aCommand,
const char16_t* aKeyCode, const char16_t* aCharCode,
const char16_t* aModifiers, const char16_t* aButton,
const char16_t* aClickCount, const char16_t* aGroup,
const char16_t* aPreventDefault,
const char16_t* aAllowUntrusted,
nsXBLPrototypeBinding* aBinding, uint32_t aLineNumber);
// This constructor is used only by XUL key handlers (e.g., <key>)
explicit nsXBLPrototypeHandler(mozilla::dom::Element* aKeyElement,
XBLReservedKey aReserved);
// This constructor is used for handlers loaded from the cache
explicit nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding);
~nsXBLPrototypeHandler();
/**
* Try and convert this XBL handler into an APZ KeyboardShortcut for handling
* key events on the compositor thread. This only works for XBL handlers that
* represent scroll commands.
*
* @param aOut the converted KeyboardShortcut, must be non null
* @return whether the handler was converted into a KeyboardShortcut
*/
bool TryConvertToKeyboardShortcut(KeyboardShortcut* aOut) const;
bool EventTypeEquals(nsAtom* aEventType) const {
return mEventName == aEventType;
}
// if aCharCode is not zero, it is used instead of the charCode of aKeyEvent.
bool KeyEventMatched(mozilla::dom::KeyboardEvent* aKeyEvent,
uint32_t aCharCode,
const IgnoreModifierState& aIgnoreModifierState);
bool MouseEventMatched(mozilla::dom::MouseEvent* aMouseEvent);
already_AddRefed<mozilla::dom::Element> GetHandlerElement();
void AppendHandlerText(const nsAString& aText);
uint8_t GetPhase() { return mPhase; }
uint8_t GetType() { return mType; }
XBLReservedKey GetIsReserved() { return mReserved; }
nsXBLPrototypeHandler* GetNextHandler() { return mNextHandler; }
void SetNextHandler(nsXBLPrototypeHandler* aHandler) {
mNextHandler = aHandler;
}
MOZ_CAN_RUN_SCRIPT
nsresult ExecuteHandler(mozilla::dom::EventTarget* aTarget,
mozilla::dom::Event* aEvent);
already_AddRefed<nsAtom> GetEventName();
void SetEventName(nsAtom* aName) { mEventName = aName; }
nsXBLEventHandler* GetEventHandler() {
if (!mHandler) {
mHandler = NS_NewXBLEventHandler(this, mEventName);
}
return mHandler;
}
nsXBLEventHandler* GetCachedEventHandler() { return mHandler; }
bool HasAllowUntrustedAttr() {
return (mType & NS_HANDLER_HAS_ALLOW_UNTRUSTED_ATTR) != 0;
}
// This returns a valid value only if HasAllowUntrustedEventsAttr returns
// true.
bool AllowUntrustedEvents() {
return (mType & NS_HANDLER_ALLOW_UNTRUSTED) != 0;
}
nsresult Read(nsIObjectInputStream* aStream);
nsresult Write(nsIObjectOutputStream* aStream);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
public:
static uint32_t gRefCnt;
protected:
void Init() {
++gRefCnt;
if (gRefCnt == 1)
// Get the primary accelerator key.
InitAccessKeys();
}
already_AddRefed<nsIController> GetController(
mozilla::dom::EventTarget* aTarget);
inline int32_t GetMatchingKeyCode(const nsAString& aKeyName);
void ConstructPrototype(
mozilla::dom::Element* aKeyElement, const char16_t* aEvent = nullptr,
const char16_t* aPhase = nullptr, const char16_t* aAction = nullptr,
const char16_t* aCommand = nullptr, const char16_t* aKeyCode = nullptr,
const char16_t* aCharCode = nullptr, const char16_t* aModifiers = nullptr,
const char16_t* aButton = nullptr, const char16_t* aClickCount = nullptr,
const char16_t* aGroup = nullptr,
const char16_t* aPreventDefault = nullptr,
const char16_t* aAllowUntrusted = nullptr);
void ReportKeyConflict(const char16_t* aKey, const char16_t* aModifiers,
mozilla::dom::Element* aElement,
const char* aMessageName);
void GetEventType(nsAString& type);
bool ModifiersMatchMask(mozilla::dom::UIEvent* aEvent,
const IgnoreModifierState& aIgnoreModifierState);
MOZ_CAN_RUN_SCRIPT
nsresult DispatchXBLCommand(mozilla::dom::EventTarget* aTarget,
mozilla::dom::Event* aEvent);
MOZ_CAN_RUN_SCRIPT
nsresult DispatchXULKeyCommand(mozilla::dom::Event* aEvent);
nsresult EnsureEventHandler(mozilla::dom::AutoJSAPI& jsapi, nsAtom* aName,
JS::MutableHandle<JSObject*> aHandler);
Modifiers GetModifiers() const;
Modifiers GetModifiersMask() const;
static int32_t KeyToMask(int32_t key);
static int32_t AccelKeyMask();
static int32_t kMenuAccessKey;
static void InitAccessKeys();
static const int32_t cShift;
static const int32_t cAlt;
static const int32_t cControl;
static const int32_t cMeta;
static const int32_t cOS;
static const int32_t cShiftMask;
static const int32_t cAltMask;
static const int32_t cControlMask;
static const int32_t cMetaMask;
static const int32_t cOSMask;
static const int32_t cAllModifiers;
protected:
union {
nsIWeakReference*
mHandlerElement; // For XUL <key> element handlers. [STRONG]
char16_t* mHandlerText; // For XBL handlers (we don't build an
// element for the <handler>, and instead
// we cache the JS text or command name
// that we should use.
};
uint32_t mLineNumber; // The line number we started at in the XBL file
// The following four values make up 32 bits.
uint8_t mPhase; // The phase (capturing, bubbling)
uint8_t mType; // The type of the handler. The handler is either a XUL key
// handler, an XBL "command" event, or a normal XBL event with
// accompanying JavaScript. The high bit is used to indicate
// whether this handler should prevent the default action.
uint8_t mMisc; // Miscellaneous extra information. For key events,
// stores whether or not we're a key code or char code.
// For mouse events, stores the clickCount.
XBLReservedKey
mReserved; // <key> is reserved for chrome. Not used by handlers.
int32_t mKeyMask; // Which modifier keys this event handler expects to have
// down in order to be matched.
// The primary filter information for mouse/key events.
int32_t mDetail; // For key events, contains a charcode or keycode. For
// mouse events, stores the button info.
// Prototype handlers are chained. We own the next handler in the chain.
nsXBLPrototypeHandler* mNextHandler;
RefPtr<nsAtom> mEventName; // The type of the event, e.g., "keypress"
RefPtr<nsXBLEventHandler> mHandler;
nsXBLPrototypeBinding* mPrototypeBinding; // the binding owns us
};
#endif

View File

@ -1,32 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "nsXBLSerialize.h"
#include "jsfriendapi.h"
#include "nsXBLPrototypeBinding.h"
#include "nsIXPConnect.h"
#include "nsContentUtils.h"
using namespace mozilla;
nsresult XBL_SerializeFunction(nsIObjectOutputStream* aStream,
JS::Handle<JSObject*> aFunction) {
AssertInCompilationScope();
AutoJSContext cx;
MOZ_ASSERT(js::GetContextCompartment(cx) ==
js::GetObjectCompartment(aFunction));
return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, aFunction);
}
nsresult XBL_DeserializeFunction(
nsIObjectInputStream* aStream,
JS::MutableHandle<JSObject*> aFunctionObjectp) {
AssertInCompilationScope();
AutoJSContext cx;
return nsContentUtils::XPConnect()->ReadFunction(aStream, cx,
aFunctionObjectp.address());
}

View File

@ -1,86 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLSerialize_h__
#define nsXBLSerialize_h__
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "js/TypeDecls.h"
typedef uint8_t XBLBindingSerializeDetails;
// A version number to ensure we don't load cached data in a different
// file format.
#define XBLBinding_Serialize_Version 0x00000007
// Set for the first binding in a document
#define XBLBinding_Serialize_IsFirstBinding (1 << 0)
// Set to indicate that nsXBLPrototypeBinding::mBindToUntrustedContent should be
// true
#define XBLBinding_Serialize_BindToUntrustedContent (1 << 3)
// Set to indicate that nsXBLPrototypeBinding::mSimpleScopeChain should be true
#define XBLBinding_Serialize_SimpleScopeChain (1 << 4)
// Appears at the end of the serialized data to indicate that no more bindings
// are present for this document.
#define XBLBinding_Serialize_NoMoreBindings 0x80
// Implementation member types. The serialized value for each member contains
// one of these values, combined with the read-only flag
// XBLBinding_Serialize_ReadOnly. Use XBLBinding_Serialize_Mask to filter out
// the read-only flag and check for just the member type.
#define XBLBinding_Serialize_NoMoreItems \
0 // appears at the end of the members list
#define XBLBinding_Serialize_Field 1
#define XBLBinding_Serialize_GetterProperty 2
#define XBLBinding_Serialize_SetterProperty 3
#define XBLBinding_Serialize_GetterSetterProperty 4
#define XBLBinding_Serialize_Method 5
#define XBLBinding_Serialize_Constructor 6
#define XBLBinding_Serialize_Destructor 7
#define XBLBinding_Serialize_Handler 8
#define XBLBinding_Serialize_Attribute 0xA
#define XBLBinding_Serialize_Mask 0x0F
#define XBLBinding_Serialize_ReadOnly 0x80
// Appears at the end of the list of insertion points to indicate that there
// are no more.
#define XBLBinding_Serialize_NoMoreInsertionPoints 0xFFFFFFFF
// When serializing content nodes, a single-byte namespace id is written out
// first. The special values below can appear in place of a namespace id.
// Indicates that this is not one of the built-in namespaces defined in
// nsNameSpaceManager.h. The string form will be serialized immediately
// following.
#define XBLBinding_Serialize_CustomNamespace 0xFE
// Flags to indicate a non-element node. Otherwise, it is an element.
#define XBLBinding_Serialize_TextNode 0xFB
#define XBLBinding_Serialize_CDATANode 0xFC
#define XBLBinding_Serialize_CommentNode 0xFD
// Indicates that there is no content to serialize/deserialize
#define XBLBinding_Serialize_NoContent 0xFF
// Appears at the end of the forwarded attributes list to indicate that there
// are no more attributes.
#define XBLBinding_Serialize_NoMoreAttributes 0xFF
static_assert(XBLBinding_Serialize_CustomNamespace >= kNameSpaceID_LastBuiltin,
"The custom namespace should not be in use as a real namespace");
nsresult XBL_SerializeFunction(nsIObjectOutputStream* aStream,
JS::Handle<JSObject*> aFunctionObject);
nsresult XBL_DeserializeFunction(nsIObjectInputStream* aStream,
JS::MutableHandle<JSObject*> aFunctionObject);
#endif // nsXBLSerialize_h__

View File

@ -1,986 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/ArrayUtils.h"
#include "mozilla/ComputedStyle.h"
#include "nsCOMPtr.h"
#include "nsNetUtil.h"
#include "nsXBLService.h"
#include "nsIInputStream.h"
#include "nsNameSpaceManager.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsString.h"
#include "plstr.h"
#include "nsIContent.h"
#include "mozilla/dom/Document.h"
#include "nsIXMLContentSink.h"
#include "nsContentCID.h"
#include "mozilla/dom/XMLDocument.h"
#include "nsGkAtoms.h"
#include "nsIObserverService.h"
#include "nsXBLContentSink.h"
#include "nsXBLBinding.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLDocumentInfo.h"
#include "nsCRT.h"
#include "nsContentUtils.h"
#include "nsSyncLoadService.h"
#include "nsContentPolicyUtils.h"
#include "nsTArray.h"
#include "nsError.h"
#include "nsIDocumentObserver.h"
#include "nsFrameManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptError.h"
#include "nsXBLSerialize.h"
#ifdef MOZ_XUL
# include "nsXULPrototypeCache.h"
#endif
#include "nsIDOMEventListener.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/RestyleManager.h"
#include "mozilla/dom/ChildIterator.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/Element.h"
using namespace mozilla;
using namespace mozilla::dom;
#define NS_MAX_XBL_BINDING_RECURSION 20
nsXBLService* nsXBLService::gInstance = nullptr;
static bool IsAncestorBinding(Document* aDocument, nsIURI* aChildBindingURI,
nsIContent* aChild) {
NS_ASSERTION(aDocument, "expected a document");
NS_ASSERTION(aChildBindingURI, "expected a binding URI");
NS_ASSERTION(aChild, "expected a child content");
uint32_t bindingRecursion = 0;
for (nsIContent* bindingParent = aChild->GetBindingParent(); bindingParent;
bindingParent = bindingParent->GetBindingParent()) {
nsXBLBinding* binding = bindingParent->GetXBLBinding();
if (!binding) {
continue;
}
if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
++bindingRecursion;
if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
continue;
}
AutoTArray<nsString, 1> params;
CopyUTF8toUTF16(aChildBindingURI->GetSpecOrDefault(),
*params.AppendElement());
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), aDocument,
nsContentUtils::eXBL_PROPERTIES, "TooDeepBindingRecursion", params);
return true;
}
}
return false;
}
// Individual binding requests.
class nsXBLBindingRequest {
public:
nsCOMPtr<nsIURI> mBindingURI;
nsCOMPtr<nsIContent> mBoundElement;
void DocumentLoaded(Document* aBindingDoc) {
// We only need the document here to cause frame construction, so
// we need the current doc, not the owner doc.
Document* doc = mBoundElement->GetUncomposedDoc();
if (!doc) return;
// Get the binding.
bool ready = false;
nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI,
&ready);
if (!ready) return;
// Destroy the frames for mBoundElement. Do this after getting the binding,
// since if the binding fetch fails then we don't want to destroy the
// frames.
if (PresShell* presShell = doc->GetPresShell()) {
presShell->DestroyFramesForAndRestyle(mBoundElement->AsElement());
}
MOZ_ASSERT(!mBoundElement->GetPrimaryFrame());
}
nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
: mBindingURI(aURI), mBoundElement(aBoundElement) {}
};
// nsXBLStreamListener, a helper class used for
// asynchronous parsing of URLs
/* Header file */
class nsXBLStreamListener final : public nsIStreamListener,
public nsIDOMEventListener {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIDOMEVENTLISTENER
nsXBLStreamListener(Document* aBoundDocument, nsIXMLContentSink* aSink,
Document* aBindingDocument);
void AddRequest(nsXBLBindingRequest* aRequest) {
mBindingRequests.AppendElement(aRequest);
}
bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
private:
~nsXBLStreamListener();
nsCOMPtr<nsIStreamListener> mInner;
AutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
nsWeakPtr mBoundDocument;
nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
nsCOMPtr<Document> mBindingDocument; // Only set until OnStartRequest
};
/* Implementation file */
NS_IMPL_ISUPPORTS(nsXBLStreamListener, nsIStreamListener, nsIRequestObserver,
nsIDOMEventListener)
nsXBLStreamListener::nsXBLStreamListener(Document* aBoundDocument,
nsIXMLContentSink* aSink,
Document* aBindingDocument)
: mSink(aSink), mBindingDocument(aBindingDocument) {
/* member initializers and constructor code */
mBoundDocument = do_GetWeakReference(aBoundDocument);
}
nsXBLStreamListener::~nsXBLStreamListener() {
for (uint32_t i = 0; i < mBindingRequests.Length(); i++) {
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
delete req;
}
}
NS_IMETHODIMP
nsXBLStreamListener::OnDataAvailable(nsIRequest* request,
nsIInputStream* aInStr,
uint64_t aSourceOffset, uint32_t aCount) {
if (mInner)
return mInner->OnDataAvailable(request, aInStr, aSourceOffset, aCount);
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsXBLStreamListener::OnStartRequest(nsIRequest* request) {
// Make sure we don't hold on to the sink and binding document past this point
nsCOMPtr<nsIXMLContentSink> sink;
mSink.swap(sink);
nsCOMPtr<Document> doc;
mBindingDocument.swap(doc);
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsILoadGroup> group;
request->GetLoadGroup(getter_AddRefs(group));
nsresult rv =
doc->StartDocumentLoad("loadAsInteractiveData", channel, group, nullptr,
getter_AddRefs(mInner), true, sink);
NS_ENSURE_SUCCESS(rv, rv);
// Make sure to add ourselves as a listener after StartDocumentLoad,
// since that resets the event listners on the document.
doc->AddEventListener(NS_LITERAL_STRING("load"), this, false);
return mInner->OnStartRequest(request);
}
NS_IMETHODIMP
nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsresult aStatus) {
nsresult rv = NS_OK;
if (mInner) {
rv = mInner->OnStopRequest(request, aStatus);
}
// Don't hold onto the inner listener; holding onto it can create a cycle
// with the document
mInner = nullptr;
return rv;
}
bool nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt) {
// XXX Could be more efficient.
uint32_t count = mBindingRequests.Length();
for (uint32_t i = 0; i < count; i++) {
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
bool eq;
if (req->mBoundElement == aElt &&
NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq)
return true;
}
return false;
}
nsresult nsXBLStreamListener::HandleEvent(Event* aEvent) {
nsresult rv = NS_OK;
uint32_t i;
uint32_t count = mBindingRequests.Length();
// Get the binding document; note that we don't hold onto it in this object
// to avoid creating a cycle
EventTarget* target = aEvent->GetCurrentTarget();
nsCOMPtr<Document> bindingDocument = do_QueryInterface(target);
NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
// See if we're still alive.
nsCOMPtr<Document> doc(do_QueryReferent(mBoundDocument));
if (!doc) {
NS_WARNING(
"XBL load did not complete until after document went away! Modal "
"dialog bug?\n");
} else {
// We have to do a flush prior to notification of the document load.
// This has to happen since the HTML content sink can be holding on
// to notifications related to our children (e.g., if you bind to the
// <body> tag) that result in duplication of content.
// We need to get the sink's notifications flushed and then make the binding
// ready.
if (count > 0) {
nsXBLBindingRequest* req = mBindingRequests.ElementAt(0);
Document* document = req->mBoundElement->GetUncomposedDoc();
if (document)
document->FlushPendingNotifications(FlushType::ContentAndNotify);
}
// Remove ourselves from the set of pending docs.
nsBindingManager* bindingManager = doc->BindingManager();
nsIURI* documentURI = bindingDocument->GetDocumentURI();
bindingManager->RemoveLoadingDocListener(documentURI);
if (!bindingDocument->GetRootElement()) {
// FIXME: How about an error console warning?
NS_WARNING(
"XBL doc with no root element - this usually shouldn't happen");
return NS_ERROR_FAILURE;
}
// Put our doc info in the doc table.
nsBindingManager* xblDocBindingManager = bindingDocument->BindingManager();
RefPtr<nsXBLDocumentInfo> info =
xblDocBindingManager->GetXBLDocumentInfo(documentURI);
xblDocBindingManager->RemoveXBLDocumentInfo(
info); // Break the self-imposed cycle.
if (!info) {
if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
NS_WARNING(
"An XBL file is malformed. Did you forget the XBL namespace on the "
"bindings tag?");
}
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), nullptr,
nsContentUtils::eXBL_PROPERTIES, "MalformedXBL", nsTArray<nsString>(),
documentURI);
return NS_ERROR_FAILURE;
}
// If the doc is a chrome URI, then we put it into the XUL cache.
#ifdef MOZ_XUL
if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
if (cache && cache->IsEnabled()) cache->PutXBLDocumentInfo(info);
}
#endif
bindingManager->PutXBLDocumentInfo(info);
// Notify all pending requests that their bindings are
// ready and can be installed.
for (i = 0; i < count; i++) {
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
req->DocumentLoaded(bindingDocument);
}
}
target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
return rv;
}
// Implementation //////////////////////////////////////////////////////////////
// Implement our nsISupports methods
NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference)
void nsXBLService::Init() {
gInstance = new nsXBLService();
NS_ADDREF(gInstance);
}
// Constructors/Destructors
nsXBLService::nsXBLService(void) {}
nsXBLService::~nsXBLService(void) {}
// static
bool nsXBLService::IsChromeOrResourceURI(nsIURI* aURI) {
return aURI->SchemeIs("chrome") || aURI->SchemeIs("resource");
}
// Servo avoids wasting work styling subtrees of elements with XBL bindings by
// default, so whenever we leave LoadBindings in a way that doesn't guarantee
// that the subtree is styled we need to take care of doing it manually.
static void EnsureSubtreeStyled(Element* aElement) {
if (!aElement->HasServoData()) {
return;
}
if (Servo_Element_IsDisplayNone(aElement)) {
return;
}
PresShell* presShell = aElement->OwnerDoc()->GetPresShell();
if (!presShell || !presShell->DidInitialize()) {
return;
}
ServoStyleSet* servoSet = presShell->StyleSet();
StyleChildrenIterator iter(aElement);
for (nsIContent* child = iter.GetNextChild(); child;
child = iter.GetNextChild()) {
Element* element = Element::FromNode(child);
if (!element) {
continue;
}
if (element->HasServoData()) {
// If any child was styled, all of them should be styled already, so we
// can bail out.
return;
}
servoSet->StyleNewSubtree(element);
}
}
// Ensures that EnsureSubtreeStyled is called on the element on destruction.
class MOZ_RAII AutoEnsureSubtreeStyled {
public:
explicit AutoEnsureSubtreeStyled(Element* aElement) : mElement(aElement) {}
~AutoEnsureSubtreeStyled() { EnsureSubtreeStyled(mElement); }
private:
Element* mElement;
};
// RAII class to restyle the XBL bound element when it shuffles the flat tree.
class MOZ_RAII AutoStyleElement {
public:
explicit AutoStyleElement(Element* aElement)
: mElement(aElement), mHadData(aElement->HasServoData()) {
if (mHadData) {
RestyleManager::ClearServoDataFromSubtree(
mElement, RestyleManager::IncludeRoot::No);
}
}
~AutoStyleElement() {
PresShell* presShell = mElement->OwnerDoc()->GetPresShell();
if (!mHadData || !presShell || !presShell->DidInitialize()) {
return;
}
}
private:
Element* mElement;
bool mHadData;
};
static bool IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) {
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
return true;
}
return aPrincipal->SchemeIs("chrome");
}
// This function loads a particular XBL file and installs all of the bindings
// onto the element.
nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
nsIPrincipal* aOriginPrincipal,
nsXBLBinding** aBinding) {
MOZ_ASSERT(aOriginPrincipal, "Must have an origin principal");
*aBinding = nullptr;
AutoEnsureSubtreeStyled subtreeStyled(aElement);
if (MOZ_UNLIKELY(!aURL)) {
return NS_OK;
}
#ifdef DEBUG
// Ensures that XBL bindings are not used in the following conditions:
//
// 1) In the content process
// 2) In a document that disallows XUL/XBL which only loads bindings
// referenced in a chrome stylesheet.
//
// If the conditions are met, trigger an assertion since there shouldn't
// be this kind of binding usage.
//
// The assertion might not catch all violations because (2) is needed
// for the current test setup. Someone may unknownly using a binding
// in AllowXULXBL() documents in content process in production without
// knowing.
if (XRE_IsContentProcess() &&
IsSystemOrChromeURLPrincipal(aOriginPrincipal) &&
!aElement->OwnerDoc()->AllowXULXBL()) {
MOZ_ASSERT(false, "Unexpected XBL binding used in the content process");
}
#endif
// Easy case: The binding was already loaded.
nsXBLBinding* binding = aElement->GetXBLBinding();
if (binding && !binding->MarkedForDeath() &&
binding->PrototypeBinding()->CompareBindingURI(aURL)) {
return NS_OK;
}
nsCOMPtr<Document> document = aElement->OwnerDoc();
nsAutoCString urlspec;
nsresult rv = aURL->GetSpec(urlspec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
AutoStyleElement styleElement(aElement);
if (binding) {
FlushStyleBindings(aElement);
binding = nullptr;
}
bool ready;
RefPtr<nsXBLBinding> newBinding;
if (NS_FAILED(rv = GetBinding(aElement, aURL, false, aOriginPrincipal, &ready,
getter_AddRefs(newBinding)))) {
return rv;
}
if (!newBinding) {
#ifdef DEBUG
nsAutoCString str(
NS_LITERAL_CSTRING(
"Failed to locate XBL binding. XBL is now using id instead of name "
"to reference bindings. Make sure you have switched over. The "
"invalid binding name is: ") +
aURL->GetSpecOrDefault());
NS_ERROR(str.get());
#endif
return NS_OK;
}
if (::IsAncestorBinding(document, aURL, aElement)) {
return NS_ERROR_ILLEGAL_VALUE;
}
// We loaded a style binding. It goes on the end.
// Install the binding on the content node.
aElement->SetXBLBinding(newBinding);
{
nsAutoScriptBlocker scriptBlocker;
// Set the binding's bound element.
newBinding->SetBoundElement(aElement);
// Tell the binding to build the anonymous content.
newBinding->GenerateAnonymousContent();
// Tell the binding to install event handlers
newBinding->InstallEventHandlers();
// Set up our properties
rv = newBinding->InstallImplementation();
NS_ENSURE_SUCCESS(rv, rv);
newBinding.forget(aBinding);
}
return NS_OK;
}
void nsXBLService::FlushStyleBindings(Element* aElement) {
nsCOMPtr<Document> document = aElement->OwnerDoc();
nsXBLBinding* binding = aElement->GetXBLBinding();
if (binding) {
// Clear out the script references.
binding->ChangeDocument(document, nullptr);
aElement->SetXBLBinding(nullptr); // Flush old style bindings
}
}
// Internal helper methods /////////////////////////////////////////////////////
nsresult nsXBLService::BindingReady(nsIContent* aBoundElement, nsIURI* aURI,
bool* aIsReady) {
// Don't do a security check here; we know this binding is set to go.
return GetBinding(aBoundElement, aURI, true, nullptr, aIsReady, nullptr);
}
nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
bool aPeekOnly,
nsIPrincipal* aOriginPrincipal,
bool* aIsReady, nsXBLBinding** aResult) {
// More than 6 binding URIs are rare, see bug 55070 comment 18.
AutoTArray<nsCOMPtr<nsIURI>, 6> uris;
return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady,
aResult, uris);
}
static bool MayBindToContent(nsXBLPrototypeBinding* aProtoBinding,
nsIContent* aBoundElement, nsIURI* aURI) {
// If this binding explicitly allows untrusted content, we're done.
if (aProtoBinding->BindToUntrustedContent()) {
return true;
}
// We let XUL content and content in XUL documents through, since XUL is
// restricted anyway and we want to minimize remote XUL breakage.
if (aBoundElement->IsXULElement() ||
aBoundElement->OwnerDoc()->IsXULElement()) {
return true;
}
// Similarly, we make an exception for anonymous content (which
// lives in the XBL scope), because it's already protected from content,
// and tends to use a lot of bindings that we wouldn't otherwise need to
// whitelist.
if (aBoundElement->IsInAnonymousSubtree()) {
return true;
}
// Allow if the bound content subsumes the binding.
nsCOMPtr<Document> bindingDoc =
aProtoBinding->XBLDocumentInfo()->GetDocument();
NS_ENSURE_TRUE(bindingDoc, false);
if (aBoundElement->NodePrincipal()->Subsumes(bindingDoc->NodePrincipal())) {
return true;
}
// One last special case: we need to watch out for in-document data: URI
// bindings from remote-XUL-whitelisted domains (especially tests), because
// they end up with a null principal (rather than inheriting the document's
// principal), which causes them to fail the check above.
if (nsContentUtils::AllowXULXBLForPrincipal(aBoundElement->NodePrincipal())) {
if (aURI->SchemeIs("data")) {
return true;
}
}
// Disallow.
return false;
}
nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
bool aPeekOnly,
nsIPrincipal* aOriginPrincipal,
bool* aIsReady, nsXBLBinding** aResult,
nsTArray<nsCOMPtr<nsIURI>>& aDontExtendURIs) {
NS_ASSERTION(aPeekOnly || aResult,
"Must have non-null out param if not just peeking to see "
"whether the binding is ready");
if (aResult) *aResult = nullptr;
if (!aURI) return NS_ERROR_FAILURE;
nsAutoCString ref;
aURI->GetRef(ref);
nsCOMPtr<Document> boundDocument = aBoundElement->OwnerDoc();
RefPtr<nsXBLDocumentInfo> docInfo;
nsresult rv =
LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI,
aOriginPrincipal, false, getter_AddRefs(docInfo));
NS_ENSURE_SUCCESS(rv, rv);
if (!docInfo) return NS_ERROR_FAILURE;
WeakPtr<nsXBLPrototypeBinding> protoBinding =
docInfo->GetPrototypeBinding(ref);
if (!protoBinding) {
#ifdef DEBUG
nsAutoCString message("Unable to locate an XBL binding for URI ");
message += aURI->GetSpecOrDefault();
message += " in document ";
message += boundDocument->GetDocumentURI()->GetSpecOrDefault();
NS_WARNING(message.get());
#endif
return NS_ERROR_FAILURE;
}
// If the binding isn't whitelisted, refuse to apply it to content that
// doesn't subsume it (modulo a few exceptions).
if (!MayBindToContent(protoBinding, aBoundElement, aURI)) {
#ifdef DEBUG
nsAutoCString message("Permission denied to apply binding ");
message += aURI->GetSpecOrDefault();
message +=
" to unprivileged content. Set bindToUntrustedContent=true on "
"the binding to override this restriction.";
NS_WARNING(message.get());
#endif
return NS_ERROR_FAILURE;
}
aDontExtendURIs.AppendElement(protoBinding->BindingURI());
nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
if (altBindingURI) {
aDontExtendURIs.AppendElement(altBindingURI);
}
rv = protoBinding->ResolveBaseBinding();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> baseBindingURI;
WeakPtr<nsXBLPrototypeBinding> baseProto = protoBinding->GetBasePrototype();
if (baseProto) {
baseBindingURI = baseProto->BindingURI();
} else {
baseBindingURI = protoBinding->GetBaseBindingURI();
if (baseBindingURI) {
uint32_t count = aDontExtendURIs.Length();
for (uint32_t index = 0; index < count; ++index) {
bool equal;
rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
NS_ENSURE_SUCCESS(rv, rv);
if (equal) {
AutoTArray<nsString, 2> params;
CopyUTF8toUTF16(protoBinding->BindingURI()->GetSpecOrDefault(),
*params.AppendElement());
CopyUTF8toUTF16(baseBindingURI->GetSpecOrDefault(),
*params.AppendElement());
nsContentUtils::ReportToConsole(
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), nullptr,
nsContentUtils::eXBL_PROPERTIES, "CircularExtendsBinding", params,
boundDocument->GetDocumentURI());
return NS_ERROR_ILLEGAL_VALUE;
}
}
}
}
RefPtr<nsXBLBinding> baseBinding;
if (baseBindingURI) {
nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
child->NodePrincipal(), aIsReady,
getter_AddRefs(baseBinding), aDontExtendURIs);
if (NS_FAILED(rv)) return rv; // We aren't ready yet.
}
*aIsReady = true;
if (!aPeekOnly) {
// Make a new binding
NS_ENSURE_STATE(protoBinding);
nsXBLBinding* newBinding = new nsXBLBinding(protoBinding);
if (baseBinding) {
if (!baseProto) {
protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
}
newBinding->SetBaseBinding(baseBinding);
}
NS_ADDREF(*aResult = newBinding);
}
return NS_OK;
}
nsresult nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
Document* aBoundDocument,
nsIURI* aBindingURI,
nsIPrincipal* aOriginPrincipal,
bool aForceSyncLoad,
nsXBLDocumentInfo** aResult) {
MOZ_ASSERT(aBindingURI, "Must have a binding URI");
MOZ_ASSERT(!aOriginPrincipal || aBoundDocument,
"If we're doing a security check, we better have a document!");
*aResult = nullptr;
// Allow XBL in unprivileged documents if it's specified in a privileged or
// chrome: stylesheet. This allows themes to specify XBL bindings.
if (aOriginPrincipal && !IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
NS_ENSURE_TRUE(!aBoundDocument || aBoundDocument->AllowXULXBL(),
NS_ERROR_XBL_BLOCKED);
}
RefPtr<nsXBLDocumentInfo> info;
nsCOMPtr<nsIURI> documentURI;
nsresult rv = NS_GetURIWithoutRef(aBindingURI, getter_AddRefs(documentURI));
NS_ENSURE_SUCCESS(rv, rv);
nsBindingManager* bindingManager = nullptr;
// The first thing to check is the binding manager, which (if it exists)
// should have a reference to the nsXBLDocumentInfo if this document
// has ever loaded this binding before.
if (aBoundDocument) {
bindingManager = aBoundDocument->BindingManager();
info = bindingManager->GetXBLDocumentInfo(documentURI);
if (aBoundDocument->IsStaticDocument() &&
IsChromeOrResourceURI(aBindingURI)) {
aForceSyncLoad = true;
}
}
// It's possible the document is already being loaded. If so, there's no
// document yet, but we need to glom on our request so that it will be
// processed whenever the doc does finish loading.
NodeInfo* ni = nullptr;
if (aBoundElement) ni = aBoundElement->NodeInfo();
if (!info && bindingManager &&
(!ni ||
!(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) ||
ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) ||
((ni->Equals(nsGkAtoms::input) || ni->Equals(nsGkAtoms::select)) &&
aBoundElement->IsHTMLElement()))) &&
!aForceSyncLoad) {
nsCOMPtr<nsIStreamListener> listener;
if (bindingManager)
listener = bindingManager->GetLoadingDocListener(documentURI);
if (listener) {
nsXBLStreamListener* xblListener =
static_cast<nsXBLStreamListener*>(listener.get());
// Create a new load observer.
if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
nsXBLBindingRequest* req =
new nsXBLBindingRequest(aBindingURI, aBoundElement);
xblListener->AddRequest(req);
}
return NS_OK;
}
}
#ifdef MOZ_XUL
// The second line of defense is the global nsXULPrototypeCache,
// if it's being used.
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
bool useXULCache = cache && cache->IsEnabled();
if (!info && useXULCache) {
// This cache crosses the entire product, so that any XBL bindings that are
// part of chrome will be reused across all XUL documents.
info = cache->GetXBLDocumentInfo(documentURI);
}
bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
if (!info) {
// Next, look in the startup cache
if (!info && useStartupCache) {
rv = nsXBLDocumentInfo::ReadPrototypeBindings(
documentURI, getter_AddRefs(info), aBoundDocument);
if (NS_SUCCEEDED(rv)) {
cache->PutXBLDocumentInfo(info);
}
}
}
#endif
if (!info) {
// Finally, if all lines of defense fail, we go and fetch the binding
// document.
// Always load chrome synchronously
if (documentURI->SchemeIs("chrome")) {
aForceSyncLoad = true;
}
nsCOMPtr<Document> document;
rv = FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
aBindingURI, aOriginPrincipal, aForceSyncLoad,
getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
if (document) {
nsBindingManager* xblDocBindingManager = document->BindingManager();
info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
if (!info) {
NS_ERROR(
"An XBL file is malformed. Did you forget the XBL namespace on "
"the bindings tag?");
return NS_ERROR_FAILURE;
}
xblDocBindingManager->RemoveXBLDocumentInfo(
info); // Break the self-imposed cycle.
// If the doc is a chrome URI, then we put it into the XUL cache.
#ifdef MOZ_XUL
if (useStartupCache) {
cache->PutXBLDocumentInfo(info);
// now write the bindings into the startup cache
info->WritePrototypeBindings();
}
#endif
}
}
if (info && bindingManager) {
// Cache it in our binding manager's document table. This way,
// we can ensure that if the document has loaded this binding
// before, it can continue to use it even if the XUL prototype
// cache gets flushed. That way, if a flush does occur, we
// don't get into a weird state where we're using different
// XBLDocumentInfos for the same XBL document in a single
// document that has loaded some bindings.
bindingManager->PutXBLDocumentInfo(info);
}
info.forget(aResult);
return NS_OK;
}
nsresult nsXBLService::FetchBindingDocument(
nsIContent* aBoundElement, Document* aBoundDocument, nsIURI* aDocumentURI,
nsIURI* aBindingURI, nsIPrincipal* aOriginPrincipal, bool aForceSyncLoad,
Document** aResult) {
nsresult rv = NS_OK;
// Initialize our out pointer to nullptr
*aResult = nullptr;
// Now we have to synchronously load the binding file.
// Create an XML content sink and a parser.
nsCOMPtr<nsILoadGroup> loadGroup;
if (aBoundDocument) loadGroup = aBoundDocument->GetDocumentLoadGroup();
// We really shouldn't have to force a sync load for anything here... could
// we get away with not doing that? Not sure.
if (IsChromeOrResourceURI(aDocumentURI)) aForceSyncLoad = true;
// Create document and contentsink and set them up.
nsCOMPtr<Document> doc;
rv = NS_NewXMLDocument(getter_AddRefs(doc));
NS_ENSURE_SUCCESS(rv, rv);
// XBL documents must allow XUL and XBL elements in them but the usual check
// only checks if the document is loaded in the system principal which is
// sometimes not the case.
doc->ForceEnableXULXBL();
nsCOMPtr<nsIXMLContentSink> xblSink;
rv =
NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
// Open channel
// Note: There are some cases where aOriginPrincipal and aBoundDocument are
// purposely set to null (to bypass security checks) when calling
// LoadBindingDocumentInfo() which calls FetchBindingDocument(). LoadInfo
// will end up with no principal or node in those cases, so we use
// systemPrincipal. This achieves the same result of bypassing security
// checks, but it gives the wrong information to potential future consumers of
// loadInfo.
nsCOMPtr<nsIChannel> channel;
if (aOriginPrincipal) {
// if there is an originPrincipal we should also have aBoundDocument
MOZ_ASSERT(aBoundDocument,
"can not create a channel without aBoundDocument");
rv = NS_NewChannelWithTriggeringPrincipal(
getter_AddRefs(channel), aDocumentURI, aBoundDocument, aOriginPrincipal,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
nsILoadInfo::SEC_ALLOW_CHROME,
nsIContentPolicy::TYPE_XBL,
nullptr, // aPerformanceStorage
loadGroup);
} else {
rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
nsIContentPolicy::TYPE_XBL,
nullptr, // nsICookieSettings
nullptr, // PerformanceStorage
loadGroup);
}
NS_ENSURE_SUCCESS(rv, rv);
if (!aForceSyncLoad) {
// We can be asynchronous
nsXBLStreamListener* xblListener =
new nsXBLStreamListener(aBoundDocument, xblSink, doc);
// Add ourselves to the list of loading docs.
nsBindingManager* bindingManager;
if (aBoundDocument)
bindingManager = aBoundDocument->BindingManager();
else
bindingManager = nullptr;
if (bindingManager)
bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
// Add our request.
nsXBLBindingRequest* req =
new nsXBLBindingRequest(aBindingURI, aBoundElement);
xblListener->AddRequest(req);
// Now kick off the async read.
rv = channel->AsyncOpen(xblListener);
if (NS_FAILED(rv)) {
// Well, we won't be getting a load. Make sure to clean up our stuff!
if (bindingManager) {
bindingManager->RemoveLoadingDocListener(aDocumentURI);
}
}
return NS_OK;
}
nsCOMPtr<nsIStreamListener> listener;
rv = doc->StartDocumentLoad("loadAsInteractiveData", channel, loadGroup,
nullptr, getter_AddRefs(listener), true, xblSink);
NS_ENSURE_SUCCESS(rv, rv);
// Now do a blocking synchronous parse of the file.
nsCOMPtr<nsIInputStream> in;
rv = channel->Open(getter_AddRefs(in));
NS_ENSURE_SUCCESS(rv, rv);
rv = nsSyncLoadService::PushSyncStreamToListener(in.forget(), listener,
channel);
NS_ENSURE_SUCCESS(rv, rv);
doc.swap(*aResult);
return NS_OK;
}

View File

@ -1,118 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef nsXBLService_h_
#define nsXBLService_h_
#include "nsString.h"
#include "nsWeakReference.h"
#include "nsTArray.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
class nsXBLBinding;
class nsXBLDocumentInfo;
class nsIContent;
class nsIURI;
class nsIPrincipal;
namespace mozilla {
namespace dom {
class Document;
class Element;
class EventTarget;
} // namespace dom
} // namespace mozilla
class nsXBLService final : public nsSupportsWeakReference {
NS_DECL_ISUPPORTS
static nsXBLService* gInstance;
static void Init();
static void Shutdown() { NS_IF_RELEASE(gInstance); }
static nsXBLService* GetInstance() { return gInstance; }
static bool IsChromeOrResourceURI(nsIURI* aURI);
// This function loads a particular XBL file and installs all of the bindings
// onto the element. aOriginPrincipal must not be null here.
nsresult LoadBindings(mozilla::dom::Element* aElement, nsIURI* aURL,
nsIPrincipal* aOriginPrincipal,
nsXBLBinding** aBinding);
// Indicates whether or not a binding is fully loaded.
nsresult BindingReady(nsIContent* aBoundElement, nsIURI* aURI,
bool* aIsReady);
private:
nsXBLService();
virtual ~nsXBLService();
// This method checks the hashtable and then calls FetchBindingDocument on a
// miss. aOriginPrincipal or aBoundDocument may be null to bypass security
// checks.
nsresult LoadBindingDocumentInfo(nsIContent* aBoundElement,
mozilla::dom::Document* aBoundDocument,
nsIURI* aBindingURI,
nsIPrincipal* aOriginPrincipal,
bool aForceSyncLoad,
nsXBLDocumentInfo** aResult);
protected:
// This function clears out the bindings on a given element.
void FlushStyleBindings(mozilla::dom::Element*);
// This method synchronously loads and parses an XBL file.
nsresult FetchBindingDocument(nsIContent* aBoundElement,
mozilla::dom::Document* aBoundDocument,
nsIURI* aDocumentURI, nsIURI* aBindingURI,
nsIPrincipal* aOriginPrincipal,
bool aForceSyncLoad,
mozilla::dom::Document** aResult);
/**
* This method calls the one below with an empty |aDontExtendURIs| array.
*/
nsresult GetBinding(nsIContent* aBoundElement, nsIURI* aURI, bool aPeekFlag,
nsIPrincipal* aOriginPrincipal, bool* aIsReady,
nsXBLBinding** aResult);
/**
* This method loads a binding doc and then builds the specific binding
* required. It can also peek without building.
* @param aBoundElement the element to get a binding for
* @param aURI the binding URI
* @param aPeekFlag if true then just peek to see if the binding is ready
* @param aIsReady [out] if the binding is ready or not
* @param aResult [out] where to store the resulting binding (not used if
* aPeekFlag is true, otherwise it must be non-null)
* @param aDontExtendURIs a set of URIs that are already bound to this
* element. If a binding extends any of these then further loading
* is aborted (because it would lead to the binding extending itself)
* and NS_ERROR_ILLEGAL_VALUE is returned.
*
* @note This method always calls LoadBindingDocumentInfo(), so it's
* enough to funnel all security checks through that function.
*/
nsresult GetBinding(nsIContent* aBoundElement, nsIURI* aURI, bool aPeekFlag,
nsIPrincipal* aOriginPrincipal, bool* aIsReady,
nsXBLBinding** aResult,
nsTArray<nsCOMPtr<nsIURI>>& aDontExtendURIs);
// MEMBER VARIABLES
public:
static bool gDisableChromeCache;
static bool gAllowDataURIs; // Whether we should allow data
// urls in -moz-binding. Needed for
// testing.
};
#endif

View File

@ -1,12 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef nsXBLBinding_h_
#define nsXBLBinding_h_
// Empty stub to make bindgen happy until XBL is removed.
class nsXBLBindingStub final {};
#endif // nsXBLBinding_h_

View File

@ -1,8 +0,0 @@
"use strict";
module.exports = {
"extends": [
"plugin:mozilla/mochitest-test",
"plugin:mozilla/chrome-test",
]
};

View File

@ -1,21 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
#bar {
-moz-binding: url("#binding");
}
</style>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="binding">
<implementation>
<property name="prop" readonly="true" exposeToUntrustedContent="true"
onget="return 2;"/>
</implementation>
</binding>
</bindings>
</head>
<!-- Use a timeout so that we get bfcached -->
<body onload="setTimeout(window.opener.runTest, 100)">
<div id="bar"></div>
</body>
</html>

View File

@ -1,13 +0,0 @@
[DEFAULT]
support-files =
file_fieldScopeChain.xml
[test_bug378518.xul]
skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
[test_bug398135.xul]
[test_bug398492.xul]
[test_bug721452.xul]
[test_bug723676.xul]
[test_bug772966.xul]
[test_bug1086996.xhtml]
[test_fieldScopeChain.html]

View File

@ -1 +0,0 @@
<body onload='window.opener.loadDone()'>

View File

@ -1,14 +0,0 @@
<?xml version="1.0"?>
<bindings id="xbltestBindings" xmlns="http://www.mozilla.org/xbl">
<binding id="xbltest">
<content>PASS</content>
<implementation>
<constructor>
var win = window;
win.document.bindingConstructorRan = true;
win.ok(true, "binding URI with no fragment applied");
win.SimpleTest.finish();
</constructor>
</implementation>
</binding>
</bindings>

View File

@ -1,181 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=372769
-->
<head>
<title>Test for Bug 372769</title>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test1">
<implementation>
<field name="one">1</field>
<field name="two">9</field>
<field name="three">3</field>
<field name="four">10</field>
<field name="five">11</field>
<field name="six">this.four = 4; 6;</field>
<field name="seven">this.five = 5; 7;</field>
</implementation>
</binding>
<binding id="test2">
<implementation>
<!-- Tests for recursive resolves -->
<field name="eight">this.eight</field>
<field name="nine">this.ten</field>
<field name="ten">this.nine</field>
<!-- Tests for non-DOM overrides -->
<field name="eleven">11</field>
<field name="twelve">12</field>
<!-- Tests for DOM overrides -->
<field name="parentNode">this.parentNode</field>
<field name="ownerDocument">"ownerDocument override"</field>
</implementation>
</binding>
<binding id="test3-ancestor">
<implementation>
<field name="thirteen">"13 ancestor"</field>
<field name="fourteen">"14 ancestor"</field>
<property name="fifteen" readonly="true" onget="return '15 ancestor'"/>
</implementation>
</binding>
<binding id="test3" extends="#test3-ancestor">
<implementation>
<field name="thirteen">13</field>
<field name="fifteen">15</field>
<field name="sixteen">16</field>
<field name="sixteen">"16 later"</field>
<field name="seventeen">17</field>
<field name="eighteen">"18 field"</field>
<property name="eighteen" readonly="true" onget="return 18"/>
<property name="nineteen" readonly="true" onget="return 19"/>
<field name="nineteen">"19 field"</field>
</implementation>
</binding>
<binding id="test4">
<implementation>
<field name="twenty">for (var i in this) ; 20;</field>
</implementation>
</binding>
<binding id="test5">
<implementation>
<field name="twenty-one">for (var i in this) ; 21;</field>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=372769">Mozilla Bug 372769</a>
<p id="display1" style="-moz-binding: url(#test1)"></p>
<p id="display2" style="-moz-binding: url(#test2)"></p>
<p id="display3" style="-moz-binding: url(#test3)"></p>
<p id="display4" style="-moz-binding: url(#test4)"></p>
<p id="display5" style="-moz-binding: url(#test5)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 372769 **/
SimpleTest = parent.SimpleTest;
ok = parent.ok;
is = parent.is;
$ = function(x) { return document.getElementById(x); }
window.onload = function() {
var d = $("display1");
is(d.one, 1, "Should be able to read field");
d.two = 2;
is(d.two, 2, "Should be able to write field");
is("three" in d, true, 'Should have a property named "three"');
is(d.three, 3, "Should be 3");
is(d.four, 10, "Unexpected value so far");
// Save "five" for now
is(d.six, 6, "Should be 6");
is(d.four, 4, "Now should be 4");
d.four = 9;
is(d.four, 9, "Just set it to 9");
var found = false;
for (var prop in d) {
if (prop == "seven") {
found = true;
break;
}
}
is(found, true, "Enumeration is broken");
is(d.four, 9, "Shouldn't have rerun field six");
is(d.five, 11, "Shouldn't have run field 7");
is(d.seven, 7, "Should be 7")
is(d.five, 5, "Should have run field 7");
d = $("display2");
is(typeof(d.eight), "undefined", "Recursive resolve should bail out");
is(typeof(d.nine), "undefined", "Recursive double resolve should bail out");
is(typeof(d.ten), "undefined",
"This recursive double resolve should bail out too");
// Get .eleven so it's resolved now
is(d.eleven, 11, "Unexpected value for .eleven");
var newProto = {};
newProto.eleven = "Proto 11";
newProto.twelve = "Proto 12";
newProto.__proto__ = d.__proto__;
d.__proto__ = newProto;
is(d.eleven, 11, "Proto should not have affected this");
is(d.twelve, "Proto 12", "Proto should have overridden 'twelve'");
is(d.parentNode, undefined, "We overrode this, yes we did");
is(typeof(d.parentNode), "undefined", "This is a recursive resolve too");
is(d.ownerDocument, "ownerDocument override",
"Should have overridden ownerDocument");
d = $("display3");
is(d.thirteen, 13, "descendant should win here");
is(d.fourteen, "14 ancestor",
"ancestor should win if descendant does nothing")
is(d.fifteen, 15,
"Field beats ancestor's property, since the latter lives on higher proto")
is(d.sixteen, 16, "First field wins");
is(d.__proto__.seventeen, undefined, "Shouldn't have this on proto");
is(typeof(d.__proto__.seventeen), "undefined",
"Really, should be undefined");
is(d.seventeen, 17, "Should have this prop on the node itself, though");
is(d.eighteen, 18, "Property beats field");
is(d.nineteen, 19, "Property still beats field");
d = $("display4");
is(d.twenty, 20, "Should be 20");
d = $("display5");
found = false;
for (var prop2 in d) {
if (prop2 == "twenty-one") {
found = true;
break;
}
}
is(found, true, "Enumeration is broken");
is(d["twenty-one"], 21, "Should be 21");
SimpleTest.finish();
}
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,32 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
#div1 {
color: green;
-moz-binding: url(file_bug379959_xbl.xml#xbltest);
}
#div2 {
color: green;
-moz-binding: url(http://example.com/tests/dom/xbl/test/file_bug379959_xbl.xml#xbltest);
}
</style>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
onload = function() {
// same origin should be allowed
var nodes1 = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div1'));
parent.postMessage({test: "sameOriginIsAllowed",
result: nodes1 ? nodes1.length : 0,
senderURL: "http://mochi.test:8888"}, "*");
// cross origin should be blocked
var nodes2 = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div2'));
parent.postMessage({test: "crossOriginIsBlocked",
result: nodes2 ? nodes2.length : 0,
senderURL: "http://mochi.test:8888"}, "*");
}
</script>
</html>

View File

@ -1,20 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
#d {
color: green;
-moz-binding: url(data:text/xml;charset=utf-8,%3C%3Fxml%20version%3D%221.0%22%3F%3E%0A%3Cbindings%20id%3D%22xbltestBindings%22%20xmlns%3D%22http%3A//www.mozilla.org/xbl%22%3E%0A%20%20%3Cbinding%20id%3D%22xbltest%22%3E%3Ccontent%3EPASS%3C/content%3E%3C/binding%3E%0A%3C/bindings%3E%0A);
}
</style>
<body>
<div id="d"></div>
<script>
onload = function() {
var nodes = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('d'));
parent.postMessage({test: "dataIsAllowed",
result: nodes ? nodes.length : 0,
senderURL: "http://mochi.test:8888"}, "*");
}
</script>
</html>

View File

@ -1,4 +0,0 @@
<?xml version="1.0"?>
<bindings id="xbltestBindings" xmlns="http://www.mozilla.org/xbl">
<binding id="xbltest"><content>PASS</content></binding>
</bindings>

View File

@ -1,117 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=397934
-->
<head>
<title>Test for Bug 397934</title>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="ancestor">
<implementation>
<field name="testAncestor">"ancestor"</field>
</implementation>
</binding>
<binding id="test1" extends="#ancestor">
<implementation>
<constructor>
this.storage = window;
</constructor>
<field name="window"></field>
<field name="storage">null</field>
<field name="parentNode"></field>
<field name="ownerDocument">"ownerDocument"</field>
<field name="emptyTest1"></field>
<field name="emptyTest1">"empty1"</field>
<field name="emptyTest2">"empty2"</field>
<field name="emptyTest2"></field>
<field name="testAncestor"></field>
<field name="testEvalOnce">XPCNativeWrapper.unwrap(window).counter++; undefined</field>
</implementation>
</binding>
<binding id="test2" extends="#ancestor">
<implementation>
<constructor>
this.storage = window;
</constructor>
<field name="window">undefined</field>
<field name="storage">null</field>
<field name="parentNode">undefined</field>
<field name="ownerDocument">"ownerDocument"</field>
<field name="emptyTest1">undefined</field>
<field name="emptyTest1">"empty1"</field>
<field name="emptyTest2">"empty2"</field>
<field name="emptyTest2">undefined</field>
<field name="testAncestor">undefined</field>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=397934">Mozilla Bug 397934</a>
<p id="display1" style="-moz-binding: url(#test1)"></p>
<p id="display2" style="-moz-binding: url(#test2)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 397934 **/
SimpleTest = parent.SimpleTest;
ok = parent.ok;
is = parent.is;
$ = function(x) { return document.getElementById(x); }
window.onload = function() {
var d;
d = $("display1");
is(d.storage, window,
"test1" +
": |window| in the constructor should have resolved to our window");
is(d.ownerDocument, "ownerDocument",
"test1" + ": Control to test field overriding DOM prop");
is(d.parentNode, document.body, "test1" + ": unexpected parent");
is(d.emptyTest1, undefined,
"test1" + ": First field wins even if undefined");
is(typeof(d.emptyTest1), "undefined",
"test1" + ": First field wins even if undefined, double-check");
is(d.emptyTest2, "empty2",
"test1" + ": First field wins");
is(d.testAncestor, "ancestor",
"test1" + ": Empty field should not override ancestor binding");
var win = window;
win.counter = 0;
d.testEvalOnce;
d.testEvalOnce;
is(win.counter, 1, "Field should have evaluated once and only once");
d = $("display2");
is(d.storage, undefined,
"test2" +
": |window| in the constructor should have resolved to undefined");
is(typeof(d.storage), "undefined",
"test2" +
": |window| in the constructor should really have resolved to undefined");
is(d.ownerDocument, "ownerDocument",
"test2" + ": Control to test field overriding DOM prop");
is(d.parentNode, undefined, "test2" + ": unexpected parent");
is(typeof(d.parentNode), "undefined", "test2" + ": unexpected parent for real");
is(d.emptyTest1, undefined,
"test2" + ": First field wins even if undefined");
is(typeof(d.emptyTest1), "undefined",
"test2" + ": First field wins even if undefined, double-check");
is(d.emptyTest2, "empty2",
"test2" + ": First field wins");
is(d.testAncestor, undefined,
"test2" + ": Undefined field should override ancestor binding");
is(typeof(d.testAncestor), "undefined",
"test2" + ": Undefined field should really override ancestor binding");
SimpleTest.finish();
}
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,14 +0,0 @@
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="test">
<content>
<children/>
Binding Attached
</content>
<implementation>
<property name="xblBoundProperty" onget="return 1;"
exposeToUntrustedContent="true"/>
</implementation>
</binding>
</bindings>

View File

@ -1,17 +0,0 @@
function handleRequest(request, response)
{
var query = {};
request.queryString.split('&').forEach(function (val) {
[name, value] = val.split('=');
query[name] = unescape(value);
});
response.setHeader("Content-Type", "text/css", false);
css = "#" + query.id + " { -moz-binding: url(\"";
if (query.server) {
css += "http://" + query.server + "/tests/dom/xbl/test/";
}
css += "file_bug481558.xbl#test\"); }";
response.write(css);
}

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
#b {
-moz-binding: url("file_bug591198_xbl.xml#xbltest");
}
span {
white-space: nowrap;
}
</style>
<script>
function sendResults() {
var res = {
widths: []
};
ps = document.getElementsByTagName('span');
for (var i = 0; i < ps.length; i++) {
res.widths.push(ps[i].offsetWidth);
}
try {
res.anonChildCount =
SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('b')).length;
}
catch (ex) {}
parent.postMessage(JSON.stringify(res), "*");
}
</script>
</head>
<body onload="sendResults();">
<div><span id=b>long long text here</span></div>
<div><span>long long text here</span></div>
<div><span>PASS</span></div>
</body>
</html>

View File

@ -1,5 +0,0 @@
<?xml version="1.0"?>
<bindings id="xbltestBindings" xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="xbltest"><content>PASS<html:b style="display:none"><children/></html:b></content></binding>
</bindings>

View File

@ -1,54 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=844783
-->
<head>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="testBinding">
<implementation>
<constructor>
is(windowExpando, 42, "Expandos show up without explicit waiving");
someFunction();
ok(called, "Function called");
go();
</constructor>
</implementation>
<handlers>
<handler event="testevent" action="is(boundExpando, 11, 'See expandos on |this|'); SimpleTest.finish();"/>
</handlers>
</binding>
</bindings>
<script type="application/javascript">
<![CDATA[
is = parent.is;
ok = parent.ok;
SimpleTest = parent.SimpleTest;
window.windowExpando = 42;
window.someFunction = function() { ok(true, "Called"); window.called = true; };
function go() {
var bound = document.getElementById('bound');
bound.boundExpando = 11;
bound.dispatchEvent(new CustomEvent('testevent'));
}
function setup() {
// When the bindings are applied, the constructor will be invoked and the
// test will continue.
document.getElementById('bound').style.MozBinding = 'url(#testBinding)';
}
]]>
</script>
</head>
<body onload="setup()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=844783">Mozilla Bug 844783</a>
<p id="display"></p>
<div id="content">
<div id="bound">Bound element</div>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1,13 +0,0 @@
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="foo" simpleScopeChain="true">
<implementation>
<field name="bar">baz</field>
<constructor>
<![CDATA[
is(document, this.ownerDocument, "Shouldn't have forms in the scope chain");
]]>
</constructor>
</implementation>
</binding>
</bindings>

View File

@ -1,38 +0,0 @@
[DEFAULT]
support-files =
bug310107-resource.xhtml
file_bug310107.html
file_bug366770.xml
file_bug372769.xhtml
file_bug379959_cross.html
file_bug379959_data.html
file_bug379959_xbl.xml
file_bug397934.xhtml
file_bug481558.xbl
file_bug481558css.sjs
file_bug591198_inner.html
file_bug591198_xbl.xml
file_bug844783.xhtml
[test_bug310107.html]
[test_bug366770.html]
[test_bug371724.xhtml]
[test_bug372769.html]
[test_bug378866.xhtml]
[test_bug379959.html]
[test_bug389322.xhtml]
[test_bug397934.html]
[test_bug400705.xhtml]
[test_bug401907.xhtml]
[test_bug403162.xhtml]
[test_bug468210.xhtml]
[test_bug481558.html]
[test_bug526178.xhtml]
[test_bug542406.xhtml]
[test_bug591198.html]
[test_bug639338.xhtml]
[test_bug790265.xhtml]
[test_bug844783.html]
[test_bug872273.xhtml]
[test_bug1098628_throw_from_construct.xhtml]
[test_bug1359859.xhtml]

View File

@ -1,62 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1086996
-->
<head>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="handlerBinding">
<implementation>
<constructor>
<![CDATA[window.constructedHandlerBinding();]]>
</constructor>
</implementation>
<handlers>
<handler event="testevent" action="XPCNativeWrapper.unwrap(window).gotEvent();" allowuntrusted="true"/>
</handlers>
</binding>
<binding id="mainBinding">
<content>
<html:p id="acWithBinding" style="-moz-binding: url(#handlerBinding)"> Anonymous Content</html:p>
</content>
<implementation>
<method name="doEventDispatch" exposeToUntrustedContent="true">
<body>
<![CDATA[document.getAnonymousNodes(this)[0].dispatchEvent(new CustomEvent('testevent'));]]>
</body>
</method>
</implementation>
</binding>
</bindings>
<title>Test for Bug 1086996</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1086996">Mozilla Bug 1086996</a>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
<![CDATA[
/** Test for Bug 1086996 **/
SimpleTest.waitForExplicitFinish();
function constructedHandlerBinding() {
ok(true, "Constructed handler binding!");
setTimeout(function() { $('boundContent').doEventDispatch(); }, 0);
}
function gotEvent() {
ok(true, "Successfully triggered event handler");
SimpleTest.finish();
}
]]>
</script>
</pre>
<!-- This div needs to come after the <script> so we don't run the binding ctor
before the <script> has been parsed -->
<div id="boundContent" style="-moz-binding: url(#mainBinding)"></div>
</body>
</html>

View File

@ -1,41 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1098628
-->
<head>
<title>Test for Bug 1098628</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 1098628 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.monitorConsole(SimpleTest.finish, [{errorMessage: new RegExp('flimfniffle')}]);
addLoadEvent(function() {
SimpleTest.executeSoon(SimpleTest.endMonitorConsole);
});
]]>
</script>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<implementation>
<constructor><![CDATA[
SimpleTest.expectUncaughtException();
throw "flimfniffle";
]]></constructor>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1098628">Mozilla Bug 1098628</a>
<p id="display" style="-moz-binding: url(#test)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1,45 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1359859
-->
<head>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="testBinding">
<implementation>
<constructor>
window.running();
this.constructed = true;
SimpleTest.expectUncaughtException();
throw new Error("Constructor threw");
</constructor>
<field name="throwingField">
SimpleTest.expectUncaughtException();
throw new Error("field threw")
</field>
<field name="normalField">"hello"</field>
</implementation>
</binding>
</bindings>
<script>
// We need to wait for the binding to load.
SimpleTest.waitForExplicitFinish();
function running() {
// Wait for the rest of the constructor to run
SimpleTest.executeSoon(function() {
is(document.getElementById("bound").throwingField, undefined,
"Should not have a value for a throwing field");
is(document.getElementById("bound").normalField, "hello",
"Binding should be installed");
// The real test is that we haven't gotten any error events so far.
SimpleTest.finish();
});
}
</script>
</head>
<body>
<div id="bound" style="-moz-binding: url(#testBinding)"/>
</body>
</html>

View File

@ -1,53 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=310107
-->
<head>
<title>Test for Bug 310107</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=310107">Mozilla Bug 310107</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 310107 **/
SimpleTest.waitForExplicitFinish();
var win = window.open("bug310107-resource.xhtml", "", "width=10, height=10");
function runTest() {
window.el = win.document.getElementById("bar");
window.doc = win.document;
is(window.el.prop, 2, "Unexpected prop value at load");
win.location = "file_bug310107.html";
}
function loadDone() {
is(window.el.prop, 2, "Prop still 2 because we're in bfcache");
is(window.el, window.doc.getElementById("bar"),
"document didn't get bfcached?");
// Remove our node from the DOM
window.el.remove();
is(window.el.prop, undefined, "Binding should have been detached");
is(typeof(window.el.prop), "undefined", "Really undefined");
win.close();
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -1,24 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=366770
-->
<head>
<title>Test for Bug 366770</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=366770">Mozilla Bug 366770</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<span id="span" style="-moz-binding: url(file_bug366770.xml);"></span>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 366770 **/
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=371724
-->
<head>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="rd">
<implementation>
<property name="hallo" onget="return true;" readonly="true" exposeToUntrustedContent="true"/>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=371724">Mozilla Bug 371724</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<div id="a" style="-moz-binding:url('#rd');">Success!</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 371724 **/
SimpleTest.waitForExplicitFinish();
function checkReadOnly() {
var elt = document.getElementById('a');
var oldValue = elt.hallo;
var actual;
try {
elt.hallo = false;
actual = elt.hallo;
} catch (ex) {
actual = "" + ex;
}
is(actual, true,
"Setting a readonly xbl property should do nothing if !strict");
checkReadOnlyStrict();
}
function checkReadOnlyStrict() {
"use strict";
var elt = document.getElementById('a');
var actual;
try {
elt.hallo = false;
actual = "should have thrown";
} catch (ex) {
actual = ex instanceof TypeError;
}
is(actual, true,
"Setting a readonly xbl property should throw a TypeError exception if strict");
SimpleTest.finish();
}
addLoadEvent(checkReadOnly);
</script>
</pre>
</body>
</html>

View File

@ -1,34 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=372769
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 372769</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Embed the real test. It will take care of everything else.
function setup() {
SpecialPowers.pushPrefEnv({'set': [['dom.use_xbl_scopes_for_remote_xul', false]]}, go);
}
function go() {
$('ifr').setAttribute('src', 'file_bug372769.xhtml');
}
</script>
</head>
<body onload="setup();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=372769">Mozilla Bug 372769</a>
<p id="display"></p>
<div id="content">
<iframe id="ifr"></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1,78 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=378518
-->
<window title="Mozilla Bug 378518"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="mybinding">
<content>
</content>
</binding>
</bindings>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=378518"
target="_blank">Mozilla Bug 378518</a>
</body>
<!-- The elements we're testing with -->
<command id="myBoxCommand" oncommand="myBoxClicked = true;"/>
<command id="myCheckBoxCommand" oncommand="myCheckBoxClicked = true;"/>
<command id="myExtendedBoxCommand" oncommand="myExtendedBoxClicked = true;"/>
<box id="myBox" command="myBoxCommand">
<label>myBox</label>
</box>
<checkbox id="myCheckBox" command="myCheckBoxCommand" label="myCheckBox"/>
<box id="myExtendedBox" command="myExtendedBoxCommand"
style="-moz-binding:url(#mybinding)">
<label>myExtendedBox</label>
</box>
<!-- test code goes here -->
<script type="application/javascript"> <![CDATA[
var myBoxClicked = false;
var myCheckBoxClicked = false;
var myExtendedBoxClicked = false;
function testClick(elemName) {
var wu = window.windowUtils;
var a = document.getElementById(elemName).getBoundingClientRect();
wu.sendMouseEvent('mousedown', a.left + 1, a.top + 1, 0, 1, 0);
wu.sendMouseEvent('mouseup', a.left + 1, a.top + 1, 0, 1, 0);
}
function doTest() {
testClick('myBox');
testClick('myCheckBox');
testClick('myExtendedBox');
ok(!myBoxClicked, "Shouldn't fire");
ok(myCheckBoxClicked, "Should fire");
ok(!myExtendedBoxClicked, "Shouldn't fire");
SimpleTest.finish();
}
/** Test for Bug 378518 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
setTimeout(doTest, 0);
});
]]>
</script>
</window>

View File

@ -1,57 +0,0 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=378866
-->
<head>
<title>Test for Bug 378866</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="b1">
<content><html:span><html:span>
<children/>
</html:span></html:span></content>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=378866">Mozilla Bug 378866</a>
<p id="display"></p>
<div id="content">
<span id="grandparent" style="-moz-binding: url(#b1);">
<span id="parent">
<span id="child"/>
</span>
</span>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 378866 **/
function runTest() {
var anon = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('grandparent'));
var child = SpecialPowers.wrap(document).getElementById('child');
var insertionPoint = anon[0].childNodes[0];
insertionPoint.remove();
child.appendChild(insertionPoint);
var e = document.createEvent("Event");
e.initEvent("foo", true, true);
child.dispatchEvent(e);
ok(true, "Moving insertion point shouldn't cause problems in event dispatching");
addLoadEvent(SimpleTest.finish);
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(runTest);
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,69 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=379959
-->
<head>
<title>Test for Bug 379959</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="runTest();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=379959">Mozilla Bug 379959</a>
<p id="display">
Note: In order to re-run this test correctly you need to shift-reload
rather than simply reload. If you just reload we will restore the
previous url in the iframe which will result in an extra unexpected
message.
</p>
<div id="content" style="display: none"></div>
<iframe id="dataFrame"></iframe>
<iframe id="originFrame"></iframe>
<pre id="test">
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
var seenData = false;
var seenSameOrigin = false;
var seenCrossOrign = false;
function receiveMessage(e) {
is(e.origin, "http://mochi.test:8888", "wrong sender!");
if (e.data.test === "dataIsAllowed") {
is(e.data.result, 1, "data-url load should have succeeded");
seenData = true;
}
else if (e.data.test === "sameOriginIsAllowed") {
is(e.data.result, 1, "same site load should have succeeded");
seenSameOrigin = true;
}
else if (e.data.test === "crossOriginIsBlocked") {
is(e.data.result, 0, "cross site load should have failed");
seenCrossOrign = true;
}
else {
ok (false, "unrecognized test");
}
if (seenData && seenSameOrigin && seenCrossOrign) {
window.removeEventListener("message", receiveMessage);
SimpleTest.finish();
}
}
window.addEventListener("message", receiveMessage);
function runTest() {
// make sure data: is allowed
document.getElementById('dataFrame').src = "file_bug379959_data.html";
// make sure same-origin is allowed but cross site is blocked
document.getElementById('originFrame').src = "file_bug379959_cross.html";
}
</script>
</pre>
</body>
</html>

View File

@ -1,118 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=389322
-->
<head>
<title>Test for Bug 389322</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script>var ctorRan = false;</script>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<implementation>
<field name="field"><![CDATA[
(function () {
try {
eval("let x = 1;");
var success = true;
}
catch (e) { success = false; }
window.report("XBL fields", success)
return ""
}())
]]></field>
<property name="property">
<getter><![CDATA[
try {
eval("let x = 1;");
var success = true;
}
catch (e) { success = false; }
window.report("XBL property getters", success)
return 1
]]></getter>
<setter><![CDATA[
try {
eval("let x = 1;");
var success = true
}
catch (e) { success = false }
window.report("XBL property setters", success)
return val
]]></setter>
</property>
<method name="method">
<body><![CDATA[
try {
eval("let x = 1;");
var success = true;
}
catch (e) { success = false; }
window.report("XBL methods", success)
]]></body>
</method>
<constructor><![CDATA[
this.property += 1
var x = this.field;
this.method()
try {
eval("let x = 1;");
var success = true
}
catch (e) { success = false }
var win = window;
win.report("XBL constructors", success)
var ev = document.createEvent("Events")
ev.initEvent("custom", false, false)
this.dispatchEvent(ev)
win.ctorRan = true;
]]></constructor>
</implementation>
<handlers>
<handler action='
try {
eval("let x = 1;");
var success = true
}
catch (e) { success = false }
report("XBL event handlers", success);
' event="custom"/>
</handlers>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=389322">Mozilla Bug 389322</a>
<p id="display" style="-moz-binding: url(#test)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 389322 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
is(ctorRan, true, "Constructor should have run");
});
addLoadEvent(SimpleTest.finish);
function report(testName, success) {
is(success, true, "JS 1.7 should work in " + testName);
}
]]>
</script>
<script type="text/javascript"><![CDATA[
try {
eval("let x = 1;");
var success = true;
}
catch (e) { success = false; }
is(success, true, "let should work in HTML script tags");
]]></script>
</pre>
</body>
</html>

View File

@ -1,34 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=397934
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 397934</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Embed the real test. It will take care of everything else.
function setup() {
SpecialPowers.pushPrefEnv({'set': [['dom.use_xbl_scopes_for_remote_xul', false]]}, go);
}
function go() {
$('ifr').setAttribute('src', 'file_bug397934.xhtml');
}
</script>
</head>
<body onload="setup();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=397934">Mozilla Bug 397934</a>
<p id="display"></p>
<div id="content">
<iframe id="ifr"></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1,135 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=398135
-->
<window title="Mozilla Bug 398135"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript">window.log = ""</script>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="ancestor">
<implementation>
<constructor>
window.log += "ancestorConstructor:";
</constructor>
<destructor>
window.log += "ancestorDestructor:";
</destructor>
<field name="ancestorField">"ancestorField"</field>
<property name="ancestorProp" onget="return 'ancestorProp'"/>
<method name="ancestorMethod">
<body>
return "ancestorMethod";
</body>
</method>
</implementation>
</binding>
<binding id="test" extends="#ancestor">
<implementation>
<constructor>
window.log += "descendantConstructor:";
</constructor>
<destructor>
window.log += "descendantDestructor:";
</destructor>
<field name="descendantField">"descendantField"</field>
<field name="contentField">
document.getAnonymousNodes(this)[0];
</field>
<property name="descendantProp" onget="return 'descendantProp'"/>
<method name="descendantMethod">
<body>
return "descendantMethod";
</body>
</method>
</implementation>
<content>
<span/>
<children/>
</content>
</binding>
</bindings>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=398135"
target="_blank">Mozilla Bug 398135</a>
</body>
<hbox id="display" style="-moz-binding: url(#test)"></hbox>
<script type="application/javascript">
<![CDATA[
/** Test for Bug 398135 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var d;
d = $("display");
function testInTree(type) {
is(d.ancestorField, "ancestorField", "Wrong ancestor field " + type);
is(d.descendantField, "descendantField", "Wrong descendant field " + type);
is(d.ancestorProp, "ancestorProp", "Wrong ancestor prop " + type);
is(d.descendantProp, "descendantProp", "Wrong descendant prop " + type);
is(d.ancestorMethod(), "ancestorMethod", "Wrong ancestor method " + type);
is(d.descendantMethod(), "descendantMethod",
"Wrong descendant method " + type);
is(d.contentField, document.getAnonymousNodes(d)[0],
"Unexpected content field " + type);
}
function testNotInTree(type) {
is(typeof(d.ancestorField), "undefined", "Wrong ancestor field " + type);
is(typeof(d.descendantField), "undefined",
"Wrong descendant field " + type);
is(typeof(d.ancestorProp), "undefined", "Wrong ancestor prop " + type);
is(typeof(d.descendantProp), "undefined", "Wrong descendant prop " + type);
is(typeof(d.ancestorMethod), "undefined", "Wrong ancestor method " + type);
is(typeof(d.descendantMethod), "undefined",
"Wrong descendant method " + type);
is(typeof(d.contentField), "undefined",
"Unexpected content field " + type);
}
is(window.log, "ancestorConstructor:descendantConstructor:",
"Constructors did not fire?");
window.log = "";
testInTree("before removal");
var parent = d.parentNode;
var nextSibling = d.nextSibling;
parent.removeChild(d);
testNotInTree("after first removal");
todo(window.log == "descendantDestructor:ancestorDestructor:",
"Destructors did not fire");
window.log = "";
parent.insertBefore(d, nextSibling);
is(window.log, "ancestorConstructor:descendantConstructor:",
"Constructors did not fire a second time?");
window.log = "";
testInTree("after reinsertion");
// Now munge the proto chain to test the robustness of the proto-unhooking
// code
var origProto = d.__proto__;
var origProtoProto = origProto.__proto__;
var newProto = new Object();
origProto.__proto__ = newProto;
newProto.__proto__ = origProtoProto;
parent.removeChild(d);
todo(window.log == "descendantDestructor:ancestorDestructor:",
"Destructors did not fire a second time?");
testNotInTree("after second removal");
});
addLoadEvent(SimpleTest.finish);
]]>
</script>
</window>

View File

@ -1,84 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=398492
-->
<window title="Mozilla Bug 398492"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<content>
<xul:hbox id="xxx"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<children/>
</xul:hbox>
</content>
</binding>
</bindings>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=398492"
target="_blank">Mozilla Bug 398492</a>
</body>
<hbox id="testbox" style="-moz-binding: url(#test)">Text</hbox>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
/** Test for Bug 398492 **/
SimpleTest.waitForExplicitFinish();
const InspectorUtils = SpecialPowers.InspectorUtils;
function getXBLParent(node) {
return SpecialPowers.unwrap(InspectorUtils.getParentForNode(node, true));
}
addLoadEvent(function() {
var n = $("testbox");
var kid = n.firstChild;
var anonKid = document.getAnonymousNodes(n)[0];
is(anonKid instanceof XULElement, true, "Must be a XUL element");
is(anonKid, getXBLParent(kid), "Unexpected anonymous nodes");
var n2 = n.cloneNode(true);
var kid2 = n2.firstChild;
var anonKids = document.getAnonymousNodes(n2);
is(anonKids, null, "No XBL binding attached to cloned node");
var n3 = document.createXULElement("hbox");
document.documentElement.appendChild(n3);
var kid3 = document.createTextNode("Text");
n3.appendChild(kid3);
// Note - we rely on the fact that the binding is preloaded
// by the other hbox here, so that the binding will be applied
// sync.
n3.style.MozBinding = "url(" + document.location.href + "#test)";
n3.getBoundingClientRect(); // Flush styles.
var anonKid3 = document.getAnonymousNodes(n3)[0];
is(anonKid3 instanceof XULElement, true,
"Must be a XUL element after addBinding");
is(anonKid3, getXBLParent(kid3),
"Unexpected anonymous nodes after addBinding");
n.removeChild(kid);
isnot(anonKid, getXBLParent(kid),
"Should have removed kid from insertion point");
n3.removeChild(kid3);
isnot(anonKid3, getXBLParent(kid3),
"Should have removed kid3 from insertion point");
SimpleTest.finish();
});
]]></script>
</window>

View File

@ -1,48 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=400705
-->
<head>
<title>Test for Bug 400705</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<implementation>
<field name="a">window.countera++</field>
<field name="b">window.counterb++</field>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=400705">Mozilla Bug 400705</a>
<p id="display" style="-moz-binding: url(#test)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 400705 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
window.countera = 0;
window.counterb = 0;
var d = $("display");
// Control to make sure fields are lazy and all
d.a;
is(window.countera, 1, "Should have evaluated field");
d.remove();
is(window.counterb, 0, "Should not evaluate field on binding teardown");
SimpleTest.finish();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,58 +0,0 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=401907
-->
<head>
<title>Test for Bug 401907</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="binding">
<implementation>
<constructor>
var win = window;
win.ok(true, "First binding with ID 'binding' should be used!");
win.testRun = true;
if (win.needsFinish) {
win.SimpleTest.finish();
}
</constructor>
</implementation>
</binding>
<binding id="binding">
<implementation>
<constructor>
var win = window;
win.ok(false, "First binding with ID 'binding' should be used!");
win.testRun = true;
if (win.needsFinish) {
win.SimpleTest.finish();
}
</constructor>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=401907">Mozilla Bug 401907</a>
<p id="display"></p>
<div id="content">
<div style="-moz-binding: url(#binding)">Bound element</div>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
/** Test for Bug 401907 **/
if (!window.testRun) {
window.needsFinish = true;
SimpleTest.waitForExplicitFinish();
}
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,57 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=403162
-->
<head>
<title>Test for Bug 403162</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<handlers>
<handler event="foo" action="window.triggerCount++" allowuntrusted="true"/>
</handlers>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=403162">Mozilla Bug 403162</a>
<p id="display" style="-moz-binding: url(#test)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
var triggerCount = 0;
function dispatchEvent(t) {
var ev = document.createEvent("Events");
ev.initEvent("foo", true, true);
t.dispatchEvent(ev);
}
/** Test for Bug 403162 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var t = $("display");
is(triggerCount, 0, "Haven't dispatched event");
dispatchEvent(t);
is(triggerCount, 1, "Dispatched once");
dispatchEvent(t);
is(triggerCount, 2, "Dispatched twice");
t.remove();
dispatchEvent(t);
is(triggerCount, 2, "Listener should be gone now");
SimpleTest.finish();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,51 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=468210
-->
<head>
<title>Test for Bug 468210</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<!-- Keep the stuff inside <content> without spaces, so that the getAnonymousNodes works right -->
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="foo">
<content><span xmlns='http://www.w3.org/1999/xhtml'><children xmlns="http://www.mozilla.org/xbl"/></span></content>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=468210">Mozilla Bug 468210</a>
<p id="display">
<div id="d" style="-moz-binding: url(#foo);"></div>
<a name="foo"></a>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
<![CDATA[
/** Test for Bug 468210 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var div = $("d");
var n = document.anchors.length;
is(n, 1, "Unexpected number of anchors");
var anon = SpecialPowers.wrap(document).getAnonymousNodes(div)[0];
ok(SpecialPowers.call_Instanceof(anon, HTMLSpanElement), "Unexpected node");
is(SpecialPowers.unwrap(anon.parentNode), div, "Unexpected parent");
document.body.appendChild(div);
is(anon.parentNode, null, "Parent should have become null");
// An attr set to test notifications
anon.setAttribute("h", "i");
});
addLoadEvent(SimpleTest.finish);
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=481558
-->
<head>
<title>Test for Bug 481558</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
<link rel="stylesheet" type="text/css"
href="file_bug481558css.sjs?id=id1">
<link rel="stylesheet" type="text/css"
href="file_bug481558css.sjs?id=id2&server=example.com">
<link rel="stylesheet" type="text/css" href="http://example.com/tests/dom/xbl/test/file_bug481558css.sjs?id=id3">
<link rel="stylesheet" type="text/css" href="http://example.com/tests/dom/xbl/test/file_bug481558css.sjs?id=id4&server=localhost:8888">
</head>
<body onload="runTest();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=481558">Mozilla Bug 481558</a>
<p id="id1"></p>
<p id="id2"></p>
<p id="id3"></p>
<p id="id4"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
function runTest() {
is ($('id1').xblBoundProperty, 1, "XBL should be attached");
is ($('id2').xblBoundProperty, undefined, "XBL shouldn't be attached");
is ($('id3').xblBoundProperty, undefined, "XBL shouldn't be attached");
is ($('id4').xblBoundProperty, undefined, "XBL shouldn't be attached");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -1,80 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml" style="display: none">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=526178
-->
<head>
<title>Test for Bug 526178</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style id="sheet">
#content * {
display: block;
-moz-binding: url("#binding");
}
</style>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="binding">
<implementation>
<constructor>
var win = window;
win.logString += this.localName;
win.bindingDone();
</constructor>
</implementation>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=526178">Mozilla Bug 526178</a>
<div id="content">
<a>
<b>
<c/>
</b>
<d/>
<e style="display: inline">
<f style="display: inline">
<g style="display: inline"/>
<h style="display: none"/>
<i style="display: inline"/>
</f>
<j style="display: none"/>
<k style="display: inline">
<l style="display: inline"/>
<m/>
<n style="display: inline"/>
</k>
</e>
<o style="display: none"/>
<p/>
</a>
</div>
<p id="display">
</p>
<pre id="test">
<script type="application/javascript">
<![CDATA[
/** Test for Bug 526178 **/
var logString = "";
// Add one for the root
var pendingBindings = $("content").getElementsByTagName("*").length + 1;
function bindingDone() {
if (--pendingBindings == 0) {
is(logString, "apoeknmljfihgdbchtml");
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
// Have to add the rule for the root dynamically so the binding doesn't try
// to load before bindingDone() is defined.
$("sheet").sheet.insertRule(':root { -moz-binding: url("#binding"); }', 0);
document.documentElement.style.display = "";
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,44 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=542406
-->
<head>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="foo">
<content><children/></content>
<implementation>
<field name="one" readonly="true">1</field>
<field name="three">3</field>
</implementation>
</binding>
</bindings>
<title>Test for Bug 542406</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=542406">Mozilla Bug 542406</a>
<p id="display" style="-moz-binding: url(#foo)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
<![CDATA[
/** Test for Bug 542406 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
is($("display").one, 1, "Field one not installed?");
$("display").one = 2;
is($("display").one, 1, "Field one not readonly");
is($("display").three, 3, "Field three not installed?");
$("display").three = 4;
is($("display").three, 4, "Field three readonly?");
SimpleTest.finish();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,45 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=591198
-->
<head>
<title>Test for Bug 591198</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body onload="gen.next();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=591198">Mozilla Bug 591198</a>
<iframe id=iframe></iframe>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
gen = runTest();
function* runTest() {
let iframe = $('iframe');
window.addEventListener("message", function(e) {
gen.next(JSON.parse(e.data));
});
iframe.src = "file_bug591198_inner.html";
let res = (yield);
is(res.widths[0], res.widths[2], "binding was rendered");
isnot(res.widths[0], res.widths[1], "binding was rendered");
is(res.anonChildCount, 2, "correct number of anon children");
iframe.src = "http://noxul.example.com/tests/dom/xbl/test/file_bug591198_inner.html";
res = (yield);
is(res.widths[0], res.widths[1], "binding was not rendered");
isnot(res.widths[0], res.widths[2], "binding was not rendered");
is("anonChildCount" in res, false, "no anon children");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -1,66 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=403162
-->
<head>
<title>Test for Bug 639338</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="test">
<handlers>
<handler event="DOMMouseScroll" action="window.triggerCount++" allowuntrusted="true"/>
<handler event="DOMMouseScroll" modifiers="shift" action="window.shiftCount++" allowuntrusted="true"/>
<handler event="DOMMouseScroll" modifiers="control" action="window.controlCount++" allowuntrusted="true"/>
</handlers>
</binding>
</bindings>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=639338">Mozilla Bug 639338</a>
<p id="display" style="-moz-binding: url(#test)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
var triggerCount = 0;
var shiftCount = 0;
var controlCount = 0;
function dispatchEvent(t, controlKey, shiftKey) {
var ev = document.createEvent("MouseScrollEvents");
ev.initMouseScrollEvent("DOMMouseScroll", true, true, window, 0, 0, 0, 0, 0, controlKey, false, shiftKey, false, 0, null, 0);
t.dispatchEvent(ev);
}
/** Test for Bug 403162 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var t = $("display");
is(triggerCount, 0, "Haven't dispatched event");
dispatchEvent(t, false, false);
is(triggerCount, 1, "Dispatched once");
is(shiftCount, 0, "Not shift");
is(controlCount, 0, "Not control");
dispatchEvent(t, false, true);
is(triggerCount, 2, "Dispatched twice");
is(shiftCount, 1, "Shift");
is(controlCount, 0, "Not control");
dispatchEvent(t, true, false);
is(triggerCount, 3, "Dispatched thrice");
is(shiftCount, 1, "Not shift");
is(controlCount, 1, "Control");
SimpleTest.finish();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,25 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script>
ok(true, "Handler with empty action didn't crash")
</script>
<body xmlns="http://www.w3.org/1999/xhtml"/>
<box style="-moz-binding: url(#binding)"/>
<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl">
<xbl:binding id="binding">
<xbl:content/>
<xbl:handlers>
<xbl:handler nt="action" action=""/>
</xbl:handlers>
</xbl:binding>
</xbl:bindings>
</window>

View File

@ -1,25 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script>
ok(true, "Method with empty body didn't crash");
</script>
<body xmlns="http://www.w3.org/1999/xhtml"/>
<box style="-moz-binding: url(#binding)"/>
<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl">
<xbl:binding id="binding">
<xbl:implementation>
<xbl:method name="init"/>
</xbl:implementation>
</xbl:binding>
</xbl:bindings>
</window>

View File

@ -1,42 +0,0 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=772966
-->
<window title="Mozilla Bug 772966"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTest()">
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=772966"
target="_blank">Mozilla Bug 772966</a>
</body>
<script>
function runTest() {
is(document.getElementById('b').test(123, 123, 123), 2, "Should have 2 params.");
}
</script>
<box id="b" style="-moz-binding: url(#binding)"/>
<xbl:bindings xmlns:xbl="http://www.mozilla.org/xbl">
<xbl:binding id="binding">
<xbl:implementation>
<xbl:method name="test">
<xbl:parameter name="p1"/>
<xbl:parameter name=""/>
<xbl:parameter name="p2"/>
<xbl:body><![CDATA[
return arguments.callee.length;
]]></xbl:body>
</xbl:method>
</xbl:implementation>
</xbl:binding>
</xbl:bindings>
</window>

View File

@ -1,55 +0,0 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=790265
-->
<head>
<title>Test for Bug 790265</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="binding">
<implementation>
<method name="foo" exposeToUntrustedContent="true">
<body><![CDATA[
return this;
]]></body>
</method>
</implementation>
</binding>
</bindings>
<style>
#toBind { display: none; }
#toBind.bound { -moz-binding: url(#binding); }
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=790265">Mozilla Bug 790265</a>
<p id="display"></p>
<div id="content">
<div id="toBind">Bound element</div>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
// Flush out style on $("toBind")
$("toBind").offsetWidth;
ok(!("foo" in $("toBind")), "Should not have binding applied");
is(getComputedStyle($("toBind")).MozBinding, "none",
"Computed binding should be none");
$("toBind").className = "bound";
// Flush the style change, so we kick off the binding load before onload
// fires and thus block onload.
$("toBind").offsetWidth;
addLoadEvent(function() {
ok("foo" in $("toBind"), "Should have binding applied");
is($("toBind").foo(), $("toBind"), "Should have correct return value");
SimpleTest.finish();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=844783
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 844783</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for XBL running in content scope for XUL-whitelisted domains. **/
SimpleTest.waitForExplicitFinish();
// Disable the automation pref before loading the test to make sure we load
// the proper configuration.
function setup() {
SpecialPowers.pushPrefEnv({clear: [['dom.use_xbl_scopes_for_remote_xul']] }, continueSetup);
}
// Embed the real test. It will take care of everything else.
function continueSetup() {
$('ifr').setAttribute('src', 'file_bug844783.xhtml');
}
</script>
</head>
<body onload="setup();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=844783">Mozilla Bug 844783</a>
<p id="display"></p>
<div id="content">
<iframe id="ifr"></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1,53 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=872273
-->
<head>
<bindings xmlns="http://www.mozilla.org/xbl">
<binding id="foo">
<implementation>
<method name="throwSomething" exposeToUntrustedContent="true">
<body>
throw new Error("foopy");
</body>
</method>
</implementation>
</binding>
</bindings>
<title>Test for Bug 872273</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=872273">Mozilla Bug 872273</a>
<p id="display" style="-moz-binding: url(#foo)"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
<![CDATA[
/** Test for Bug 872273 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
// Prevent the test from failing when the exception hits onerror.
SimpleTest.expectUncaughtException();
// Tell the test to expect exactly one console error with the given parameters,
// with SimpleTest.finish as a continuation function.
SimpleTest.monitorConsole(SimpleTest.finish, [{errorMessage: new RegExp('foopy')}]);
// Schedule the console accounting (and continuation) to run next, right
// after we throw (below).
SimpleTest.executeSoon(SimpleTest.endMonitorConsole);
// Throw.
$('display').throwSomething();
});
]]>
</script>
</pre>
</body>
</html>

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1095660
-->
<head>
<meta charset="utf-8">
<title>Test for Bug </title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug **/
SimpleTest.waitForExplicitFinish();
window.baz = 1;
document.baz = 2;
addLoadEvent(function() {
is(document.querySelector("pre").bar, 2,
"Should have document on field scope chain");
SimpleTest.finish();
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1095660">Mozilla Bug </a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test" style="-moz-binding: url(file_fieldScopeChain.xml#foo)">
<form>
<input name="document">
<input type="text" id="input-test" style="-moz-binding: url(file_fieldScopeChain.xml#foo)">
</form>
</pre>
</body>
</html>

View File

@ -74,9 +74,6 @@ LOCAL_INCLUDES += [
'/layout/xul/tree',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -160,9 +160,6 @@ LOCAL_INCLUDES += [
'/view',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
LOCAL_INCLUDES += [
'/widget/android',

View File

@ -56,9 +56,6 @@ LOCAL_INCLUDES += [
'/view',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
LOCAL_INCLUDES += [
'/dom/system/windows',

View File

@ -38,6 +38,3 @@ LOCAL_INCLUDES += [
'../style',
'/dom/base',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']

View File

@ -33,7 +33,6 @@ headers = [
"nsContentUtils.h",
"nsNameSpaceManager.h",
"nsMediaFeatures.h",
"nsXBLBinding.h",
"GeckoProfiler.h",
]
raw-lines = [

View File

@ -245,9 +245,6 @@ LOCAL_INCLUDES += [
'/image',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']
JAR_MANIFESTS += ['jar.mn']
RESOURCE_FILES += [

View File

@ -501,11 +501,7 @@ function BuildConditionSandbox(aURL) {
sandbox.webrtc = false;
#endif
#if MOZ_XBL
sandbox.xbl = true;
#else
sandbox.xbl = false;
#endif
sandbox.xbl = false; // Keep this until all xbl reftests are removed in Bug 1587142.
let retainedDisplayListsEnabled = prefs.getBoolPref("layout.display-list.retain", false);
sandbox.retainedDisplayLists = retainedDisplayListsEnabled && !g.compareRetainedDisplayLists;

View File

@ -21,6 +21,3 @@ FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/xul',
]
if CONFIG['MOZ_XBL']:
LOCAL_INCLUDES += ['/dom/xbl']

View File

@ -236,13 +236,6 @@ this.AppConstants = Object.freeze({
false,
#endif
MOZ_XBL:
#ifdef MOZ_XBL
true,
#else
false,
#endif
MOZ_SYSTEM_NSS:
#ifdef MOZ_SYSTEM_NSS
true,

View File

@ -1331,14 +1331,6 @@ option('--enable-bundled-fonts', default=bundled_fonts_default,
set_define('MOZ_BUNDLED_FONTS',
depends_if('--enable-bundled-fonts', when=allow_bundled_fonts)(lambda _: True))
# XBL
# ==============================================================
option('--enable-xbl', default=False,
help='{Enable|Disable} support for XBL (XML Binding Language)')
set_define('MOZ_XBL', depends_if('--enable-xbl')(lambda _: True))
set_config('MOZ_XBL', depends_if('--enable-xbl')(lambda _: True))
# Verify MAR signatures
# ==============================================================