PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/WebKitCore/WebKitBrowserHost.cpp

https://github.com/GordonSmith/FireBreath
C++ | 291 lines | 247 code | 28 blank | 16 comment | 27 complexity | c5ae8e4b23c24810c2656374af71f907 MD5 | raw file
  1. /**********************************************************\
  2. Original Author: Richard Bateman (taxilian)
  3. Created: Jun 7, 2011
  4. License: Dual license model; choose one of two:
  5. New BSD License
  6. http://www.opensource.org/licenses/bsd-license.php
  7. - or -
  8. GNU Lesser General Public License, version 2.1
  9. http://www.gnu.org/licenses/lgpl-2.1.html
  10. Copyright 2011 Facebook, Inc and Firebreath development team
  11. \**********************************************************/
  12. #include <boost/scoped_array.hpp>
  13. #include <JavaScriptCore/JSStringRef.h>
  14. #include "JSValueUtils.h"
  15. #include "WebKitBrowserHost.h"
  16. #include "JSObjectRefAPI.h"
  17. #include "DOM.h"
  18. #include <cstring>
  19. #include "BrowserStream.h"
  20. using namespace FB::WebKit;
  21. namespace
  22. {
  23. struct MethodCallReq
  24. {
  25. //FB::variant
  26. };
  27. template<class T>
  28. JSValueConverterMap::value_type makeConverterEntry()
  29. {
  30. return JSValueConverterMap::value_type(&typeid(T), select_JSValueRef_builder::select<T>());
  31. }
  32. JSValueConverterMap makeJSValueConverterMap()
  33. {
  34. JSValueConverterMap tdm;
  35. tdm.insert(makeConverterEntry<bool>());
  36. tdm.insert(makeConverterEntry<char>());
  37. tdm.insert(makeConverterEntry<unsigned char>());
  38. tdm.insert(makeConverterEntry<short>());
  39. tdm.insert(makeConverterEntry<unsigned short>());
  40. tdm.insert(makeConverterEntry<int>());
  41. tdm.insert(makeConverterEntry<unsigned int>());
  42. tdm.insert(makeConverterEntry<long>());
  43. tdm.insert(makeConverterEntry<unsigned long>());
  44. #ifndef BOOST_NO_LONG_LONG
  45. tdm.insert(makeConverterEntry<long long>());
  46. tdm.insert(makeConverterEntry<unsigned long long>());
  47. #endif
  48. tdm.insert(makeConverterEntry<float>());
  49. tdm.insert(makeConverterEntry<double>());
  50. tdm.insert(makeConverterEntry<std::string>());
  51. tdm.insert(makeConverterEntry<std::wstring>());
  52. tdm.insert(makeConverterEntry<FB::FBNull>());
  53. tdm.insert(makeConverterEntry<FB::FBVoid>());
  54. tdm.insert(makeConverterEntry<FB::VariantList>());
  55. tdm.insert(makeConverterEntry<FB::VariantMap>());
  56. tdm.insert(makeConverterEntry<FB::JSAPIPtr>());
  57. tdm.insert(makeConverterEntry<FB::JSAPIWeakPtr>());
  58. tdm.insert(makeConverterEntry<FB::JSObjectPtr>());
  59. return tdm;
  60. }
  61. const JSValueConverterMap& getJSValueConverterMap()
  62. {
  63. static const JSValueConverterMap tdm = makeJSValueConverterMap();
  64. return tdm;
  65. }
  66. }
  67. WebKitBrowserHost::WebKitBrowserHost(JSContextRef jsContext, JSObjectRef window, const FB::BrowserHostPtr& parentHost)
  68. : m_jsContext(jsContext), m_jsWindow(window), m_parentHost(parentHost)
  69. {
  70. }
  71. WebKitBrowserHost::~WebKitBrowserHost()
  72. {
  73. }
  74. void *WebKitBrowserHost::getContextID() const {
  75. return (void*)m_jsContext;
  76. }
  77. JSContextRef WebKitBrowserHost::getJSContext() const {
  78. return m_jsContext;
  79. }
  80. FB::DOM::DocumentPtr WebKitBrowserHost::getDOMDocument() {
  81. try {
  82. FB::JSObjectPtr doc(jsEval("document").convert_cast<FB::JSObjectPtr>());
  83. if (doc)
  84. return FB::DOM::Document::create(doc);
  85. }
  86. catch (...) {
  87. }
  88. return FB::DOM::DocumentPtr();
  89. }
  90. FB::DOM::WindowPtr WebKitBrowserHost::getDOMWindow() {
  91. try {
  92. FB::JSObjectPtr win(getVariant(m_jsWindow).convert_cast<FB::JSObjectPtr>());
  93. if (win)
  94. return FB::DOM::Window::create(win);
  95. }
  96. catch (...) {
  97. }
  98. return FB::DOM::WindowPtr();
  99. }
  100. FB::DOM::ElementPtr WebKitBrowserHost::getDOMElement() {
  101. try {
  102. FB::JSObjectPtr body(jsEval("document.body").convert_cast<FB::JSObjectPtr>());
  103. if (body)
  104. return FB::DOM::Element::create(body);
  105. }
  106. catch (...) {
  107. }
  108. return FB::DOM::ElementPtr();
  109. }
  110. FB::variant WebKitBrowserHost::jsEval(const std::string &script) {
  111. JSStringRef scriptJS = JSStringCreateWithUTF8CString(script.c_str());
  112. JSObjectRef fn = JSObjectMakeFunction(m_jsContext, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
  113. JSStringRelease(scriptJS);
  114. if (fn) {
  115. JSValueRef ret = JSObjectCallAsFunction(m_jsContext, fn, NULL, 0, NULL, NULL);
  116. return getVariant(ret);
  117. } else {
  118. throw FB::script_error("Could not eval: " + script);
  119. }
  120. }
  121. void WebKitBrowserHost::evaluateJavaScript(const std::string &script) {
  122. jsEval(script);
  123. }
  124. bool WebKitBrowserHost::_scheduleAsyncCall(void (*func)(void *), void *userData) const {
  125. // Default behavior is to use the parent browserhost for cross-thread calls
  126. return m_parentHost->ScheduleAsyncCall(func, userData);
  127. }
  128. FB::BrowserStreamPtr WebKitBrowserHost::_createStream( const BrowserStreamRequest& req ) const {
  129. return BrowserStreamPtr(); // TODO
  130. }
  131. FB::BrowserStreamPtr WebKitBrowserHost::_createUnsolicitedStream(const BrowserStreamRequest& req) const{
  132. return BrowserStreamPtr(); // TODO
  133. }
  134. FB::variant WebKitBrowserHost::getVariant(JSValueRef input)
  135. {
  136. if (input == NULL)
  137. return FB::FBNull();
  138. switch(JSValueGetType(m_jsContext, input)) {
  139. case kJSTypeUndefined:
  140. return FB::FBVoid();
  141. case kJSTypeNull:
  142. return FB::FBNull();
  143. case kJSTypeBoolean:
  144. return JSValueToBoolean(m_jsContext, input);
  145. case kJSTypeNumber: {
  146. JSStringRef strVal = JSValueToStringCopy(m_jsContext, input, NULL);
  147. size_t strSize = JSStringGetMaximumUTF8CStringSize(strVal);
  148. boost::scoped_array<char> buf(new char[strSize]);
  149. JSStringGetUTF8CString(strVal, buf.get(), strSize);
  150. JSStringRelease(strVal);
  151. if (memchr(buf.get(), '.', strSize) != NULL) {
  152. return boost::lexical_cast<double>(buf.get());
  153. } else if (memchr(buf.get(), '-', strSize) != NULL) {
  154. int64_t fullSize = boost::lexical_cast<int64_t>(buf.get());
  155. try {
  156. return boost::numeric_cast<int32_t>(fullSize);
  157. }
  158. catch (const boost::bad_numeric_cast&) {
  159. return fullSize;
  160. }
  161. } else {
  162. uint64_t fullSize = boost::lexical_cast<uint64_t>(buf.get());
  163. try {
  164. return boost::numeric_cast<uint32_t>(fullSize);
  165. }
  166. catch (const boost::bad_numeric_cast&) {
  167. return fullSize;
  168. }
  169. }
  170. break; // unreachable, but easier to read
  171. }
  172. case kJSTypeString: {
  173. JSStringRef strVal = JSValueToStringCopy(m_jsContext, input, NULL);
  174. size_t strSize = JSStringGetMaximumUTF8CStringSize(strVal);
  175. boost::scoped_array<char> buf(new char[strSize]);
  176. JSStringGetUTF8CString(strVal, buf.get(), strSize);
  177. JSStringRelease(strVal);
  178. return buf.get();
  179. }
  180. case kJSTypeObject: {
  181. JSValueRef except(NULL);
  182. JSObjectRef o(JSValueToObject(m_jsContext, input, &except));
  183. if (except != NULL) {
  184. JSStringRef strVal = JSValueToStringCopy(m_jsContext, except, NULL);
  185. size_t strSize = JSStringGetMaximumUTF8CStringSize(strVal);
  186. boost::scoped_array<char> buf(new char[strSize]);
  187. JSStringGetUTF8CString(strVal, buf.get(), strSize);
  188. JSStringRelease(strVal);
  189. throw FB::script_error(buf.get());
  190. } else if (o == NULL) {
  191. return FB::FBVoid();
  192. } else {
  193. return JSObjectRefAPIPtr(
  194. new JSObjectRefAPI(o, boost::static_pointer_cast<WebKitBrowserHost>( shared_from_this() ))
  195. );
  196. }
  197. }
  198. default:
  199. return FB::FBVoid();
  200. }
  201. return FB::FBVoid();
  202. }
  203. JSValueRef WebKitBrowserHost::JSValueRefFromVariant(const FB::variant& var)
  204. {
  205. const JSValueConverterMap& convertMap = getJSValueConverterMap();
  206. const std::type_info& type = var.get_type();
  207. JSValueConverterMap::const_iterator it = convertMap.find(&type);
  208. if (it == convertMap.end()) {
  209. // Unhandled type!
  210. return JSValueMakeUndefined(getJSContext());
  211. }
  212. return (it->second)(boost::static_pointer_cast<WebKitBrowserHost>(shared_from_this()), var);
  213. }
  214. void WebKitBrowserHost::shutdown()
  215. {
  216. boost::recursive_mutex::scoped_lock _l(m_jsObjectMutex);
  217. while (!m_jsObjectList.empty()) {
  218. JSObjectRefPtr ptr(m_jsObjectList.back());
  219. m_jsObjectList.pop_back();
  220. deferred_release(*ptr->getPtr());
  221. }
  222. FB::BrowserHost::shutdown();
  223. }
  224. JSObjectRefPtr WebKitBrowserHost::ProtectJSObjectRef(JSObjectRef o)
  225. {
  226. if (o == NULL) {
  227. return JSObjectRefPtr();
  228. }
  229. boost::recursive_mutex::scoped_lock _l(m_jsObjectMutex);
  230. JSObjectRefPtr ptr(boost::make_shared<FB::ShareableReference<JSObjectRef> >(new JSObjectRef(o)));
  231. m_jsObjectList.push_back(ptr);
  232. JSValueProtect(m_jsContext, *ptr->getPtr());
  233. return ptr;
  234. }
  235. void WebKitBrowserHost::ReleaseJSObjectRef(const JSObjectRefWeakPtr& oref)
  236. {
  237. boost::recursive_mutex::scoped_lock _l(m_jsObjectMutex);
  238. JSObjectRefPtr ptr(oref.lock());
  239. if (ptr) {
  240. m_jsObjectList.remove(ptr);
  241. deferred_release(*ptr->getPtr());
  242. delete ptr->getPtr();
  243. }
  244. }
  245. void WebKitBrowserHost::deferred_release(JSObjectRef o) const
  246. {
  247. boost::recursive_mutex::scoped_lock _l(m_deferMutex);
  248. m_deferredRelease.push_back(o);
  249. if (isMainThread()) {
  250. DoDeferredRelease();
  251. }
  252. }
  253. void WebKitBrowserHost::DoDeferredRelease() const
  254. {
  255. boost::recursive_mutex::scoped_lock _l(m_deferMutex);
  256. while (!m_deferredRelease.empty()) {
  257. JSObjectRef o = m_deferredRelease.back();
  258. m_deferredRelease.pop_back();
  259. JSValueUnprotect(m_jsContext, o);
  260. }
  261. }