1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef GIN_OBJECT_TEMPLATE_BUILDER_H_ 6 #define GIN_OBJECT_TEMPLATE_BUILDER_H_ 7 8 #include "base/bind.h" 9 #include "base/callback.h" 10 #include "base/strings/string_piece.h" 11 #include "base/template_util.h" 12 #include "gin/converter.h" 13 #include "gin/function_template.h" 14 #include "gin/gin_export.h" 15 #include "v8/include/v8.h" 16 17 namespace gin { 18 19 namespace { 20 21 // Base template - used only for non-member function pointers. Other types 22 // either go to one of the below specializations, or go here and fail to compile 23 // because of base::Bind(). 24 template<typename T, typename Enable = void> 25 struct CallbackTraits { 26 static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate, 27 T callback) { 28 return CreateFunctionTemplate(isolate, base::Bind(callback)); 29 } 30 static void SetAsFunctionHandler(v8::Isolate* isolate, 31 v8::Local<v8::ObjectTemplate> tmpl, 32 T callback) { 33 CreateFunctionHandler(isolate, tmpl, base::Bind(callback)); 34 } 35 }; 36 37 // Specialization for base::Callback. 38 template<typename T> 39 struct CallbackTraits<base::Callback<T> > { 40 static v8::Handle<v8::FunctionTemplate> CreateTemplate( 41 v8::Isolate* isolate, const base::Callback<T>& callback) { 42 return CreateFunctionTemplate(isolate, callback); 43 } 44 static void SetAsFunctionHandler(v8::Isolate* isolate, 45 v8::Local<v8::ObjectTemplate> tmpl, 46 const base::Callback<T>& callback) { 47 CreateFunctionHandler(isolate, tmpl, callback); 48 } 49 }; 50 51 // Specialization for member function pointers. We need to handle this case 52 // specially because the first parameter for callbacks to MFP should typically 53 // come from the the JavaScript "this" object the function was called on, not 54 // from the first normal parameter. 55 template<typename T> 56 struct CallbackTraits<T, typename base::enable_if< 57 base::is_member_function_pointer<T>::value>::type> { 58 static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate, 59 T callback) { 60 return CreateFunctionTemplate(isolate, base::Bind(callback), 61 HolderIsFirstArgument); 62 } 63 static void SetAsFunctionHandler(v8::Isolate* isolate, 64 v8::Local<v8::ObjectTemplate> tmpl, 65 T callback) { 66 CreateFunctionHandler( 67 isolate, tmpl, base::Bind(callback), HolderIsFirstArgument); 68 } 69 }; 70 71 // This specialization allows people to construct function templates directly if 72 // they need to do fancier stuff. 73 template<> 74 struct GIN_EXPORT CallbackTraits<v8::Handle<v8::FunctionTemplate> > { 75 static v8::Handle<v8::FunctionTemplate> CreateTemplate( 76 v8::Handle<v8::FunctionTemplate> templ) { 77 return templ; 78 } 79 }; 80 81 } // namespace 82 83 84 // ObjectTemplateBuilder provides a handy interface to creating 85 // v8::ObjectTemplate instances with various sorts of properties. 86 class GIN_EXPORT ObjectTemplateBuilder { 87 public: 88 explicit ObjectTemplateBuilder(v8::Isolate* isolate); 89 ~ObjectTemplateBuilder(); 90 91 // It's against Google C++ style to return a non-const ref, but we take some 92 // poetic license here in order that all calls to Set() can be via the '.' 93 // operator and line up nicely. 94 template<typename T> 95 ObjectTemplateBuilder& SetValue(const base::StringPiece& name, T val) { 96 return SetImpl(name, ConvertToV8(isolate_, val)); 97 } 98 99 // In the following methods, T and U can be function pointer, member function 100 // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to 101 // use one of the first two options. Also see gin::CreateFunctionTemplate() 102 // for creating raw function templates. 103 template<typename T> 104 ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, 105 const T& callback) { 106 return SetImpl(name, CallbackTraits<T>::CreateTemplate(isolate_, callback)); 107 } 108 template<typename T> 109 ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, 110 const T& getter) { 111 return SetPropertyImpl(name, 112 CallbackTraits<T>::CreateTemplate(isolate_, getter), 113 v8::Local<v8::FunctionTemplate>()); 114 } 115 template<typename T, typename U> 116 ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, 117 const T& getter, const U& setter) { 118 return SetPropertyImpl(name, 119 CallbackTraits<T>::CreateTemplate(isolate_, getter), 120 CallbackTraits<U>::CreateTemplate(isolate_, setter)); 121 } 122 template<typename T> 123 ObjectTemplateBuilder& SetCallAsFunctionHandler(const T& callback) { 124 CallbackTraits<T>::SetAsFunctionHandler(isolate_, template_, callback); 125 return *this; 126 } 127 ObjectTemplateBuilder& AddNamedPropertyInterceptor(); 128 ObjectTemplateBuilder& AddIndexedPropertyInterceptor(); 129 130 v8::Local<v8::ObjectTemplate> Build(); 131 132 private: 133 ObjectTemplateBuilder& SetImpl(const base::StringPiece& name, 134 v8::Handle<v8::Data> val); 135 ObjectTemplateBuilder& SetPropertyImpl( 136 const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter, 137 v8::Handle<v8::FunctionTemplate> setter); 138 139 v8::Isolate* isolate_; 140 141 // ObjectTemplateBuilder should only be used on the stack. 142 v8::Local<v8::ObjectTemplate> template_; 143 }; 144 145 } // namespace gin 146 147 #endif // GIN_OBJECT_TEMPLATE_BUILDER_H_ 148