mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
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:
parent
8e592888cb
commit
d981495450
@ -236,7 +236,6 @@ module.exports = {
|
||||
"dom/websocket/**",
|
||||
"dom/workers/**",
|
||||
"dom/worklet/**",
|
||||
"dom/xbl/**",
|
||||
"dom/xml/**",
|
||||
"dom/xslt/**",
|
||||
"dom/xul/**",
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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']:
|
||||
|
@ -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']
|
||||
|
||||
|
@ -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'
|
||||
|
@ -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']
|
||||
|
@ -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);
|
||||
}
|
@ -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___
|
@ -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']
|
@ -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;
|
||||
}
|
@ -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
@ -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_
|
@ -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
|
@ -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__
|
@ -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;
|
||||
}
|
@ -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
|
@ -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();
|
||||
}
|
@ -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
|
@ -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__
|
@ -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;
|
||||
}
|
@ -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__
|
@ -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"");
|
||||
}
|
@ -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__
|
@ -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__
|
@ -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;
|
||||
}
|
@ -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__
|
@ -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;
|
||||
}
|
@ -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
@ -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
@ -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
|
@ -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());
|
||||
}
|
@ -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__
|
@ -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;
|
||||
}
|
@ -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
|
@ -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_
|
@ -1,8 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/mochitest-test",
|
||||
"plugin:mozilla/chrome-test",
|
||||
]
|
||||
};
|
@ -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>
|
@ -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]
|
@ -1 +0,0 @@
|
||||
<body onload='window.opener.loadDone()'>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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);
|
||||
}
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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]
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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'
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -38,6 +38,3 @@ LOCAL_INCLUDES += [
|
||||
'../style',
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_XBL']:
|
||||
LOCAL_INCLUDES += ['/dom/xbl']
|
||||
|
@ -33,7 +33,6 @@ headers = [
|
||||
"nsContentUtils.h",
|
||||
"nsNameSpaceManager.h",
|
||||
"nsMediaFeatures.h",
|
||||
"nsXBLBinding.h",
|
||||
"GeckoProfiler.h",
|
||||
]
|
||||
raw-lines = [
|
||||
|
@ -245,9 +245,6 @@ LOCAL_INCLUDES += [
|
||||
'/image',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_XBL']:
|
||||
LOCAL_INCLUDES += ['/dom/xbl']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
RESOURCE_FILES += [
|
||||
|
@ -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;
|
||||
|
@ -21,6 +21,3 @@ FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/xul',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_XBL']:
|
||||
LOCAL_INCLUDES += ['/dom/xbl']
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
# ==============================================================
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user