blob: 649bb9a23980f0d2f91ca3dc5119de8514fd5f1d [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.
#include "cobalt/script/mozjs/wrapper_factory.h"
#include <utility>
#include "base/lazy_instance.h"
#include "cobalt/script/mozjs/mozjs_wrapper_handle.h"
#include "cobalt/script/mozjs/wrapper_private.h"
#include "third_party/mozjs/js/src/jsproxy.h"
namespace cobalt {
namespace script {
namespace mozjs {
void WrapperFactory::RegisterWrappableType(
base::TypeId wrappable_type, const CreateWrapperFunction& create_function,
const PrototypeClassFunction& class_function) {
std::pair<WrappableTypeFunctionsHashMap::iterator, bool> pib =
wrappable_type_functions_.insert(std::make_pair(
wrappable_type,
WrappableTypeFunctions(create_function, class_function)));
DCHECK(pib.second)
<< "RegisterWrappableType registered for type more than once.";
}
JSObject* WrapperFactory::GetWrapperProxy(
const scoped_refptr<Wrappable>& wrappable) const {
if (!wrappable) {
return NULL;
}
JS::RootedObject wrapper_proxy(
context_,
MozjsWrapperHandle::GetObjectProxy(GetCachedWrapper(wrappable.get())));
if (!wrapper_proxy) {
scoped_ptr<Wrappable::WeakWrapperHandle> object_handle =
CreateWrapper(wrappable);
SetCachedWrapper(wrappable.get(), object_handle.Pass());
wrapper_proxy =
MozjsWrapperHandle::GetObjectProxy(GetCachedWrapper(wrappable.get()));
}
DCHECK(wrapper_proxy);
DCHECK(js::IsProxy(wrapper_proxy));
return wrapper_proxy;
}
bool WrapperFactory::HasWrapperProxy(
const scoped_refptr<Wrappable>& wrappable) const {
return wrappable &&
!!MozjsWrapperHandle::GetObjectProxy(
GetCachedWrapper(wrappable.get()));
}
bool WrapperFactory::IsWrapper(JS::HandleObject wrapper) const {
// If the object doesn't have a wrapper private, it means that it is not a
// platform object.
return (JS_GetClass(wrapper)->flags & JSCLASS_HAS_PRIVATE) &&
JS_GetPrivate(wrapper) != NULL;
}
scoped_ptr<Wrappable::WeakWrapperHandle> WrapperFactory::CreateWrapper(
const scoped_refptr<Wrappable>& wrappable) const {
WrappableTypeFunctionsHashMap::const_iterator it =
wrappable_type_functions_.find(wrappable->GetWrappableType());
if (it == wrappable_type_functions_.end()) {
NOTREACHED();
return scoped_ptr<Wrappable::WeakWrapperHandle>();
}
JS::RootedObject new_proxy(
context_, it->second.create_wrapper.Run(context_, wrappable));
WrapperPrivate* wrapper_private =
WrapperPrivate::GetFromProxyObject(context_, new_proxy);
DCHECK(wrapper_private);
return make_scoped_ptr<Wrappable::WeakWrapperHandle>(
new MozjsWrapperHandle(wrapper_private));
}
bool WrapperFactory::DoesObjectImplementInterface(JS::HandleObject object,
base::TypeId type_id) const {
// If the object doesn't have a wrapper private which means it is not a
// platform object, so the object doesn't implement the interface.
if (!WrapperPrivate::HasWrapperPrivate(context_, object)) {
return false;
}
WrappableTypeFunctionsHashMap::const_iterator it =
wrappable_type_functions_.find(type_id);
if (it == wrappable_type_functions_.end()) {
NOTREACHED();
return false;
}
const JSClass* proto_class = it->second.prototype_class.Run(context_);
JS::RootedObject object_proto_object(context_);
bool success =
JS_GetPrototype(context_, object, object_proto_object.address());
bool equality = false;
while (!equality && success && object_proto_object) {
// Get the class of the prototype.
JSClass* object_proto_class = JS_GetClass(object_proto_object);
equality = (object_proto_class == proto_class);
// Get the prototype of the previous prototype.
success = JS_GetPrototype(context_, object_proto_object,
object_proto_object.address());
}
return equality;
}
} // namespace mozjs
} // namespace script
} // namespace cobalt