gecko-dev/dom/xbl/nsXBLDocumentInfo.cpp

328 строки
9.6 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
2012-05-21 15:12:37 +04:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/DebugOnly.h"
#include "nsXBLDocumentInfo.h"
#include "nsIDocument.h"
#include "nsXBLPrototypeBinding.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIDOMDocument.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 "mozilla/Services.h"
#include "xpcpublic.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h"
#include "nsCCUncollectableMarker.h"
Bug 742217. Reduce the use of nested namespaces in our binding code. r=peterv,bent In the new setup, all per-interface DOM binding files are exported into mozilla/dom. General files not specific to an interface are also exported into mozilla/dom. In terms of namespaces, most things now live in mozilla::dom. Each interface Foo that has generated code has a mozilla::dom::FooBinding namespace for said generated code (and possibly a mozilla::bindings::FooBinding_workers if there's separate codegen for workers). IDL enums are a bit weird: since the name of the enum and the names of its entries all end up in the same namespace, we still generate a C++ namespace with the name of the IDL enum type with "Values" appended to it, with a ::valuelist inside for the actual C++ enum. We then typedef EnumFooValues::valuelist to EnumFoo. That makes it a bit more difficult to refer to the values, but means that values from different enums don't collide with each other. The enums with the proto and constructor IDs in them now live under the mozilla::dom::prototypes and mozilla::dom::constructors namespaces respectively. Again, this lets us deal sanely with the whole "enum value names are flattened into the namespace the enum is in" deal. The main benefit of this setup (and the reason "Binding" got appended to the per-interface namespaces) is that this way "using mozilla::dom" should Just Work for consumers and still allow C++ code to sanely use the IDL interface names for concrete classes, which is fairly desirable. --HG-- rename : dom/bindings/Utils.cpp => dom/bindings/BindingUtils.cpp rename : dom/bindings/Utils.h => dom/bindings/BindingUtils.h
2012-05-03 08:35:38 +04:00
#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(nsIDocument* 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,
nsIDocument* 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;
}
UniquePtr<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(Move(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));
auto styleBackend = aBoundDocument ? aBoundDocument->GetStyleBackendType()
: StyleBackendType::Gecko;
nsCOMPtr<nsIDOMDocument> domdoc;
rv = NS_NewXBLDocument(getter_AddRefs(domdoc), aURI, nullptr, principal, styleBackend);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
NS_ASSERTION(doc, "Must have a document!");
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
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(), buf.get(), len);
}
void
nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
{
mFirstBinding = aBinding;
}
void
nsXBLDocumentInfo::FlushSkinStylesheets()
{
if (mBindingTable) {
for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->FlushSkinSheets();
}
}
}
#ifdef DEBUG
void
AssertInCompilationScope()
{
AutoJSContext cx;
MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
}
#endif