mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-03 22:07:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
467
dom/bindings/DOMJSClass.h
Normal file
467
dom/bindings/DOMJSClass.h
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
/* -*- 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 mozilla_dom_DOMJSClass_h
|
||||
#define mozilla_dom_DOMJSClass_h
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
#include "mozilla/dom/PrototypeList.h" // auto-generated
|
||||
|
||||
#include "mozilla/dom/JSSlots.h"
|
||||
|
||||
class nsCycleCollectionParticipant;
|
||||
|
||||
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
|
||||
#define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT
|
||||
|
||||
// Keep this count up to date with any extra global slots added above.
|
||||
#define DOM_GLOBAL_SLOTS 1
|
||||
|
||||
// We use these flag bits for the new bindings.
|
||||
#define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
|
||||
#define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Returns true if code running in the given JSContext is allowed to access
|
||||
* [SecureContext] API on the given JSObject.
|
||||
*
|
||||
* [SecureContext] API exposure is restricted to use by code in a Secure
|
||||
* Contexts:
|
||||
*
|
||||
* https://w3c.github.io/webappsec-secure-contexts/
|
||||
*
|
||||
* Since we want [SecureContext] exposure to depend on the privileges of the
|
||||
* running code (rather than the privileges of an object's creator), this
|
||||
* function checks to see whether the given JSContext's Compartment is flagged
|
||||
* as a Secure Context. That allows us to make sure that system principal code
|
||||
* (which is marked as a Secure Context) can access Secure Context API on an
|
||||
* object in a different compartment, regardless of whether the other
|
||||
* compartment is a Secure Context or not.
|
||||
*
|
||||
* Checking the JSContext's Compartment doesn't work for expanded principal
|
||||
* globals accessing a Secure Context web page though (e.g. those used by frame
|
||||
* scripts). To handle that we fall back to checking whether the JSObject came
|
||||
* from a Secure Context.
|
||||
*
|
||||
* Note: We'd prefer this function to live in BindingUtils.h, but we need to
|
||||
* call it in this header, and BindingUtils.h includes us (i.e. we'd have a
|
||||
* circular dependency between headers if it lived there).
|
||||
*/
|
||||
inline bool
|
||||
IsSecureContextOrObjectIsFromSecureContext(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
return JS::CompartmentCreationOptionsRef(js::GetContextCompartment(aCx)).secureContext() ||
|
||||
JS::CompartmentCreationOptionsRef(js::GetObjectCompartment(aObj)).secureContext();
|
||||
}
|
||||
|
||||
typedef bool
|
||||
(* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc);
|
||||
|
||||
typedef bool
|
||||
(* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<JSObject*> obj,
|
||||
JS::AutoIdVector& props);
|
||||
|
||||
typedef bool
|
||||
(* DeleteNamedProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
|
||||
JS::ObjectOpResult& opresult);
|
||||
|
||||
// Returns true if the given global is of a type whose bit is set in
|
||||
// aNonExposedGlobals.
|
||||
bool
|
||||
IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal,
|
||||
uint32_t aNonExposedGlobals);
|
||||
|
||||
struct ConstantSpec
|
||||
{
|
||||
const char* name;
|
||||
JS::Value value;
|
||||
};
|
||||
|
||||
typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global);
|
||||
|
||||
namespace GlobalNames {
|
||||
// The names of our possible globals. These are the names of the actual
|
||||
// interfaces, not of the global names used to refer to them in IDL [Exposed]
|
||||
// annotations.
|
||||
static const uint32_t Window = 1u << 0;
|
||||
static const uint32_t BackstagePass = 1u << 1;
|
||||
static const uint32_t DedicatedWorkerGlobalScope = 1u << 2;
|
||||
static const uint32_t SharedWorkerGlobalScope = 1u << 3;
|
||||
static const uint32_t ServiceWorkerGlobalScope = 1u << 4;
|
||||
static const uint32_t WorkerDebuggerGlobalScope = 1u << 5;
|
||||
static const uint32_t WorkletGlobalScope = 1u << 6;
|
||||
} // namespace GlobalNames
|
||||
|
||||
struct PrefableDisablers {
|
||||
inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
|
||||
// Reading "enabled" on a worker thread is technically undefined behavior,
|
||||
// because it's written only on main threads, with no barriers of any sort.
|
||||
// So we want to avoid doing that. But we don't particularly want to make
|
||||
// expensive NS_IsMainThread calls here.
|
||||
//
|
||||
// The good news is that "enabled" is only written for things that have a
|
||||
// Pref annotation, and such things can never be exposed on non-Window
|
||||
// globals; our IDL parser enforces that. So as long as we check our
|
||||
// exposure set before checking "enabled" we will be ok.
|
||||
if (nonExposedGlobals &&
|
||||
IsNonExposedGlobal(cx, js::GetGlobalForObjectCrossCompartment(obj),
|
||||
nonExposedGlobals)) {
|
||||
return false;
|
||||
}
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
if (secureContext && !IsSecureContextOrObjectIsFromSecureContext(cx, obj)) {
|
||||
return false;
|
||||
}
|
||||
if (enabledFunc &&
|
||||
!enabledFunc(cx, js::GetGlobalForObjectCrossCompartment(obj))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// A boolean indicating whether this set of specs is enabled. Not const
|
||||
// because it will change at runtime if the corresponding pref is changed.
|
||||
bool enabled;
|
||||
|
||||
// A boolean indicating whether a Secure Context is required.
|
||||
const bool secureContext;
|
||||
|
||||
// Bitmask of global names that we should not be exposed in.
|
||||
const uint16_t nonExposedGlobals;
|
||||
|
||||
// A function pointer to a function that can say the property is disabled
|
||||
// even if "enabled" is set to true. If the pointer is null the value of
|
||||
// "enabled" is used as-is.
|
||||
const PropertyEnabled enabledFunc;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Prefable {
|
||||
inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const {
|
||||
if (MOZ_LIKELY(!disablers)) {
|
||||
return true;
|
||||
}
|
||||
return disablers->isEnabled(cx, obj);
|
||||
}
|
||||
|
||||
// Things that can disable this set of specs. |nullptr| means "cannot be
|
||||
// disabled".
|
||||
PrefableDisablers* const disablers;
|
||||
|
||||
// Array of specs, terminated in whatever way is customary for T.
|
||||
// Null to indicate a end-of-array for Prefable, when such an
|
||||
// indicator is needed.
|
||||
const T* const specs;
|
||||
};
|
||||
|
||||
// Conceptually, NativeProperties has seven (Prefable<T>*, jsid*, T*) trios
|
||||
// (where T is one of JSFunctionSpec, JSPropertySpec, or ConstantSpec), one for
|
||||
// each of: static methods and attributes, methods and attributes, unforgeable
|
||||
// methods and attributes, and constants.
|
||||
//
|
||||
// That's 21 pointers, but in most instances most of the trios are all null,
|
||||
// and there are many instances. To save space we use a variable-length type,
|
||||
// NativePropertiesN<N>, to hold the data and getters to access it. It has N
|
||||
// actual trios (stored in trios[]), plus four bits for each of the 7 possible
|
||||
// trios: 1 bit that states if that trio is present, and 3 that state that
|
||||
// trio's offset (if present) in trios[].
|
||||
//
|
||||
// All trio accesses should be done via the getters, which contain assertions
|
||||
// that check we don't overrun the end of the struct. (The trio data members are
|
||||
// public only so they can be statically initialized.) These assertions should
|
||||
// never fail so long as (a) accesses to the variable-length part are guarded by
|
||||
// appropriate Has*() calls, and (b) all instances are well-formed, i.e. the
|
||||
// value of N matches the number of mHas* members that are true.
|
||||
//
|
||||
// Finally, we define a typedef of NativePropertiesN<7>, NativeProperties, which
|
||||
// we use as a "base" type used to refer to all instances of NativePropertiesN.
|
||||
// (7 is used because that's the maximum valid parameter, though any other
|
||||
// value 1..6 could also be used.) This is reasonable because of the
|
||||
// aforementioned assertions in the getters. Upcast() is used to convert
|
||||
// specific instances to this "base" type.
|
||||
//
|
||||
template <int N>
|
||||
struct NativePropertiesN {
|
||||
// Trio structs are stored in the trios[] array, and each element in the
|
||||
// array could require a different T. Therefore, we can't use the correct
|
||||
// type for mPrefables and mSpecs. Instead we use void* and cast to the
|
||||
// correct type in the getters.
|
||||
struct Trio {
|
||||
const /*Prefable<const T>*/ void* const mPrefables;
|
||||
const jsid* const mIds;
|
||||
const /*T*/ void* const mSpecs;
|
||||
};
|
||||
|
||||
const int32_t iteratorAliasMethodIndex;
|
||||
|
||||
constexpr const NativePropertiesN<7>* Upcast() const {
|
||||
return reinterpret_cast<const NativePropertiesN<7>*>(this);
|
||||
}
|
||||
|
||||
#define DO(SpecT, FieldName) \
|
||||
public: \
|
||||
/* The bitfields indicating the trio's presence and (if present) offset. */ \
|
||||
const uint32_t mHas##FieldName##s:1; \
|
||||
const uint32_t m##FieldName##sOffset:3; \
|
||||
private: \
|
||||
const Trio* FieldName##sTrio() const { \
|
||||
MOZ_ASSERT(Has##FieldName##s()); \
|
||||
return &trios[m##FieldName##sOffset]; \
|
||||
} \
|
||||
public: \
|
||||
bool Has##FieldName##s() const { \
|
||||
return mHas##FieldName##s; \
|
||||
} \
|
||||
const Prefable<const SpecT>* FieldName##s() const { \
|
||||
return static_cast<const Prefable<const SpecT>*> \
|
||||
(FieldName##sTrio()->mPrefables); \
|
||||
} \
|
||||
const jsid* FieldName##Ids() const { \
|
||||
return FieldName##sTrio()->mIds; \
|
||||
} \
|
||||
const SpecT* FieldName##Specs() const { \
|
||||
return static_cast<const SpecT*>(FieldName##sTrio()->mSpecs); \
|
||||
}
|
||||
|
||||
DO(JSFunctionSpec, StaticMethod)
|
||||
DO(JSPropertySpec, StaticAttribute)
|
||||
DO(JSFunctionSpec, Method)
|
||||
DO(JSPropertySpec, Attribute)
|
||||
DO(JSFunctionSpec, UnforgeableMethod)
|
||||
DO(JSPropertySpec, UnforgeableAttribute)
|
||||
DO(ConstantSpec, Constant)
|
||||
|
||||
#undef DO
|
||||
|
||||
const Trio trios[N];
|
||||
};
|
||||
|
||||
// Ensure the struct has the expected size. The 8 is for the
|
||||
// iteratorAliasMethodIndex plus the bitfields; the rest is for trios[].
|
||||
static_assert(sizeof(NativePropertiesN<1>) == 8 + 3*sizeof(void*), "1 size");
|
||||
static_assert(sizeof(NativePropertiesN<2>) == 8 + 6*sizeof(void*), "2 size");
|
||||
static_assert(sizeof(NativePropertiesN<3>) == 8 + 9*sizeof(void*), "3 size");
|
||||
static_assert(sizeof(NativePropertiesN<4>) == 8 + 12*sizeof(void*), "4 size");
|
||||
static_assert(sizeof(NativePropertiesN<5>) == 8 + 15*sizeof(void*), "5 size");
|
||||
static_assert(sizeof(NativePropertiesN<6>) == 8 + 18*sizeof(void*), "6 size");
|
||||
static_assert(sizeof(NativePropertiesN<7>) == 8 + 21*sizeof(void*), "7 size");
|
||||
|
||||
// The "base" type.
|
||||
typedef NativePropertiesN<7> NativeProperties;
|
||||
|
||||
struct NativePropertiesHolder
|
||||
{
|
||||
const NativeProperties* regular;
|
||||
const NativeProperties* chromeOnly;
|
||||
};
|
||||
|
||||
// Helper structure for Xrays for DOM binding objects. The same instance is used
|
||||
// for instances, interface objects and interface prototype objects of a
|
||||
// specific interface.
|
||||
struct NativePropertyHooks
|
||||
{
|
||||
// The hook to call for resolving indexed or named properties. May be null if
|
||||
// there can't be any.
|
||||
ResolveOwnProperty mResolveOwnProperty;
|
||||
// The hook to call for enumerating indexed or named properties. May be null
|
||||
// if there can't be any.
|
||||
EnumerateOwnProperties mEnumerateOwnProperties;
|
||||
// The hook to call to delete a named property. May be null if there are no
|
||||
// named properties or no named property deleter. On success (true return)
|
||||
// the "found" argument will be set to true if there was in fact such a named
|
||||
// property and false otherwise. If it's set to false, the caller is expected
|
||||
// to proceed with whatever deletion behavior it would have if there were no
|
||||
// named properties involved at all (i.e. if the hook were null). If it's set
|
||||
// to true, it will indicate via opresult whether the delete actually
|
||||
// succeeded.
|
||||
DeleteNamedProperty mDeleteNamedProperty;
|
||||
|
||||
// The property arrays for this interface.
|
||||
NativePropertiesHolder mNativeProperties;
|
||||
|
||||
// This will be set to the ID of the interface prototype object for the
|
||||
// interface, if it has one. If it doesn't have one it will be set to
|
||||
// prototypes::id::_ID_Count.
|
||||
prototypes::ID mPrototypeID;
|
||||
|
||||
// This will be set to the ID of the interface object for the interface, if it
|
||||
// has one. If it doesn't have one it will be set to
|
||||
// constructors::id::_ID_Count.
|
||||
constructors::ID mConstructorID;
|
||||
|
||||
// The NativePropertyHooks instance for the parent interface (for
|
||||
// ShimInterfaceInfo).
|
||||
const NativePropertyHooks* mProtoHooks;
|
||||
|
||||
// The JSClass to use for expandos on our Xrays. Can be null, in which case
|
||||
// Xrays will use a default class of their choice.
|
||||
const JSClass* mXrayExpandoClass;
|
||||
};
|
||||
|
||||
enum DOMObjectType : uint8_t {
|
||||
eInstance,
|
||||
eGlobalInstance,
|
||||
eInterface,
|
||||
eInterfacePrototype,
|
||||
eGlobalInterfacePrototype,
|
||||
eNamedPropertiesObject
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
IsInstance(DOMObjectType type)
|
||||
{
|
||||
return type == eInstance || type == eGlobalInstance;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
IsInterfacePrototype(DOMObjectType type)
|
||||
{
|
||||
return type == eInterfacePrototype || type == eGlobalInterfacePrototype;
|
||||
}
|
||||
|
||||
typedef JSObject* (*AssociatedGlobalGetter)(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aObj);
|
||||
|
||||
typedef JSObject* (*ProtoGetter)(JSContext* aCx);
|
||||
|
||||
/**
|
||||
* Returns a handle to the relevant WebIDL prototype object for the current
|
||||
* compartment global (which may be a handle to null on out of memory). Once
|
||||
* allocated, the prototype object is guaranteed to exist as long as the global
|
||||
* does, since the global traces its array of WebIDL prototypes and
|
||||
* constructors.
|
||||
*/
|
||||
typedef JS::Handle<JSObject*> (*ProtoHandleGetter)(JSContext* aCx);
|
||||
|
||||
// Special JSClass for reflected DOM objects.
|
||||
struct DOMJSClass
|
||||
{
|
||||
// It would be nice to just inherit from JSClass, but that precludes pure
|
||||
// compile-time initialization of the form |DOMJSClass = {...};|, since C++
|
||||
// only allows brace initialization for aggregate/POD types.
|
||||
const js::Class mBase;
|
||||
|
||||
// A list of interfaces that this object implements, in order of decreasing
|
||||
// derivedness.
|
||||
const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH];
|
||||
|
||||
// We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
|
||||
// the proxy private if we use a proxy object.
|
||||
// Sometimes it's an nsISupports and sometimes it's not; this class tells
|
||||
// us which it is.
|
||||
const bool mDOMObjectIsISupports;
|
||||
|
||||
const NativePropertyHooks* mNativeHooks;
|
||||
|
||||
// A callback to find the associated global for our C++ object. Note that
|
||||
// this is used in cases when that global is _changing_, so it will not match
|
||||
// the global of the JSObject* passed in to this function!
|
||||
AssociatedGlobalGetter mGetAssociatedGlobal;
|
||||
ProtoHandleGetter mGetProto;
|
||||
|
||||
// This stores the CC participant for the native, null if this class does not
|
||||
// implement cycle collection or if it inherits from nsISupports (we can get
|
||||
// the CC participant by QI'ing in that case).
|
||||
nsCycleCollectionParticipant* mParticipant;
|
||||
|
||||
static const DOMJSClass* FromJSClass(const JSClass* base) {
|
||||
MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
|
||||
return reinterpret_cast<const DOMJSClass*>(base);
|
||||
}
|
||||
|
||||
static const DOMJSClass* FromJSClass(const js::Class* base) {
|
||||
return FromJSClass(Jsvalify(base));
|
||||
}
|
||||
|
||||
const JSClass* ToJSClass() const { return Jsvalify(&mBase); }
|
||||
};
|
||||
|
||||
// Special JSClass for DOM interface and interface prototype objects.
|
||||
struct DOMIfaceAndProtoJSClass
|
||||
{
|
||||
// It would be nice to just inherit from js::Class, but that precludes pure
|
||||
// compile-time initialization of the form
|
||||
// |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace
|
||||
// initialization for aggregate/POD types.
|
||||
const js::Class mBase;
|
||||
|
||||
// Either eInterface, eInterfacePrototype, eGlobalInterfacePrototype or
|
||||
// eNamedPropertiesObject.
|
||||
DOMObjectType mType; // uint8_t
|
||||
|
||||
// Boolean indicating whether this object wants a @@hasInstance property
|
||||
// pointing to InterfaceHasInstance defined on it. Only ever true for the
|
||||
// eInterface case.
|
||||
bool wantsInterfaceHasInstance;
|
||||
|
||||
const prototypes::ID mPrototypeID; // uint16_t
|
||||
const uint32_t mDepth;
|
||||
|
||||
const NativePropertyHooks* mNativeHooks;
|
||||
|
||||
// The value to return for toString() on this interface or interface prototype
|
||||
// object.
|
||||
const char* mToString;
|
||||
|
||||
ProtoGetter mGetParentProto;
|
||||
|
||||
static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) {
|
||||
MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS);
|
||||
return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base);
|
||||
}
|
||||
static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) {
|
||||
return FromJSClass(Jsvalify(base));
|
||||
}
|
||||
|
||||
const JSClass* ToJSClass() const { return Jsvalify(&mBase); }
|
||||
};
|
||||
|
||||
class ProtoAndIfaceCache;
|
||||
|
||||
inline bool
|
||||
DOMGlobalHasProtoAndIFaceCache(JSObject* global)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
|
||||
// This can be undefined if we GC while creating the global
|
||||
return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined();
|
||||
}
|
||||
|
||||
inline bool
|
||||
HasProtoAndIfaceCache(JSObject* global)
|
||||
{
|
||||
if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
|
||||
return false;
|
||||
}
|
||||
return DOMGlobalHasProtoAndIFaceCache(global);
|
||||
}
|
||||
|
||||
inline ProtoAndIfaceCache*
|
||||
GetProtoAndIfaceCache(JSObject* global)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL);
|
||||
return static_cast<ProtoAndIfaceCache*>(
|
||||
js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate());
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_DOMJSClass_h */
|
||||
Loading…
Add table
Add a link
Reference in a new issue