blob: c6eff6e910480ea32209d279ffbcbe4b04c0f990 [file] [log] [blame]
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_SCRIPT_MOZJS_PROXY_HANDLER_H_
#define COBALT_SCRIPT_MOZJS_PROXY_HANDLER_H_
#include <string>
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jsproxy.h"
namespace cobalt {
namespace script {
namespace mozjs {
// SpiderMonkey has a concept of a Proxy object which is associated with another
// arbitrary object and a js::BaseProxyHandler interface. The handler interface
// provides a number of traps for providing custom implementations of
// fundamental ECMAScript operations such as getPropertyDescriptor.
//
// The implementation of each trap in the js::DirectProxyHandler class simply
// forwards each trap to the target object.
//
// In defining a JSClass a number of function pointers can be set that will
// be called when getting, setting, deleting, etc. a property, but these do not
// map well onto the Web IDL spec for implementing interfaces that support named
// and indexed properties.
//
// See third_party/mozjs/js/src/jsproxy.h for more details.
//
// ProxyHandler provides custom traps for getPropertyDescriptor, delete_, and
// enumerate to implement interfaces that support named and indexed properties.
class ProxyHandler : public js::DirectProxyHandler {
public:
typedef bool (*IsSupportedIndexFunction)(JSContext*, JS::HandleObject,
uint32_t);
typedef bool (*IsSupportedNameFunction)(JSContext*, JS::HandleObject,
const std::string&);
typedef void (*EnumerateSupportedIndexesFunction)(JSContext*,
JS::HandleObject,
JS::AutoIdVector*);
typedef void (*EnumerateSupportedNamesFunction)(JSContext*, JS::HandleObject,
JS::AutoIdVector*);
typedef bool (*IndexedDeleteFunction)(JSContext*, JS::HandleObject, uint32_t);
typedef bool (*NamedDeleteFunction)(JSContext*, JS::HandleObject,
const std::string&);
// Hooks for interfaces that support indexed properties.
struct IndexedPropertyHooks {
IsSupportedIndexFunction is_supported;
EnumerateSupportedIndexesFunction enumerate_supported;
JSPropertyOp getter;
JSStrictPropertyOp setter;
IndexedDeleteFunction deleter;
};
// Hooks for interfaces that support named properties.
struct NamedPropertyHooks {
IsSupportedNameFunction is_supported;
EnumerateSupportedNamesFunction enumerate_supported;
JSPropertyOp getter;
JSStrictPropertyOp setter;
NamedDeleteFunction deleter;
};
static JSObject* NewProxy(JSContext* context, JSObject* object,
JSObject* prototype, JSObject* parent,
ProxyHandler* handler);
// Construct a new ProxyHandler with the provided hooks.
ProxyHandler(const IndexedPropertyHooks& indexed_hooks,
const NamedPropertyHooks& named_hooks);
// Overridden fundamental traps.
bool getPropertyDescriptor(JSContext* context, JS::HandleObject proxy,
JS::HandleId id, JSPropertyDescriptor* descriptor,
unsigned flags) OVERRIDE;
bool getOwnPropertyDescriptor(JSContext* context, JS::HandleObject proxy,
JS::HandleId id,
JSPropertyDescriptor* descriptor,
unsigned flags) OVERRIDE;
bool delete_(JSContext* context, JS::HandleObject proxy, JS::HandleId id,
bool* succeeded) OVERRIDE;
bool enumerate(JSContext* context, JS::HandleObject proxy,
JS::AutoIdVector& properties) OVERRIDE; // NOLINT[runtime/references]
bool defineProperty(JSContext* context, JS::HandleObject proxy,
JS::HandleId id,
JSPropertyDescriptor* descriptor) OVERRIDE;
// The derived traps in js::DirectProxyHandler are not implemented in terms of
// the fundamental traps, where the traps in js::BaseProxyHandler are.
// Redefining the derived traps to be in terms of the fundamental traps means
// that we only need to override the fundamental traps when implementing
// custom behavior for i.e. interfaces that support named properties.
bool has(JSContext* context, JS::HandleObject proxy, JS::HandleId id,
bool* bp) OVERRIDE {
return js::BaseProxyHandler::has(context, proxy, id, bp);
}
bool hasOwn(JSContext* context, JS::HandleObject proxy, JS::HandleId id,
bool* bp) OVERRIDE {
return js::BaseProxyHandler::hasOwn(context, proxy, id, bp);
}
bool get(JSContext* context, JS::HandleObject proxy,
JS::HandleObject receiver, JS::HandleId id,
JS::MutableHandleValue vp) OVERRIDE {
return js::BaseProxyHandler::get(context, proxy, receiver, id, vp);
}
bool set(JSContext* context, JS::HandleObject proxy,
JS::HandleObject receiver, JS::HandleId id, bool strict,
JS::MutableHandleValue vp) OVERRIDE {
return js::BaseProxyHandler::set(context, proxy, receiver, id, strict, vp);
}
bool keys(JSContext* context, JS::HandleObject proxy,
JS::AutoIdVector& props) OVERRIDE { // NOLINT[runtime/references]
return js::BaseProxyHandler::keys(context, proxy, props);
}
bool iterate(JSContext* context, JS::HandleObject proxy, unsigned flags,
JS::MutableHandleValue vp) OVERRIDE {
return js::BaseProxyHandler::iterate(context, proxy, flags, vp);
}
bool has_custom_property() const { return has_custom_property_; }
private:
// https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty
// This is used to support named and indexed properties.
// Returns false on internal failure.
bool LegacyPlatformObjectGetOwnPropertyDescriptor(
JSContext* context, JS::HandleObject proxy, JS::HandleId id,
JSPropertyDescriptor* descriptor);
bool supports_named_properties() {
return named_property_hooks_.getter != NULL;
}
bool supports_indexed_properties() {
return indexed_property_hooks_.getter != NULL;
}
bool IsSupportedIndex(JSContext* context, JS::HandleObject object,
uint32_t index);
bool IsSupportedName(JSContext* context, JS::HandleObject object,
const std::string& name);
bool IsArrayIndexPropertyName(JSContext* context,
JS::HandleValue property_value,
uint32_t* out_index);
bool IsNamedPropertyVisible(JSContext* context, JS::HandleObject object,
const std::string& property_name);
IndexedPropertyHooks indexed_property_hooks_;
NamedPropertyHooks named_property_hooks_;
// Set to true if this object may have a custom property set on it.
bool has_custom_property_;
};
} // namespace mozjs
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_MOZJS_PROXY_HANDLER_H_