2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file plugin_webkit.h
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the implementation file of webkit js plugin
21 * accessing routines in EFL
23 #include <javascript_interface.h>
24 #include <dpl/log/log.h>
25 #include <dpl/scoped_array.h>
27 #include <dpl/singleton_impl.h>
29 #include <dpl/foreach.h>
30 #include <dpl/noncopyable.h>
31 #include <JavaScriptCore/JavaScript.h>
32 #include <JavaScriptCore/JSObjectRef.h>
34 IMPLEMENT_SINGLETON(JavaScriptInterface)
36 #define CHECK_JSVALUE_IS_UNDEFINED_RETURN(context, object, ret) \
37 if (JSValueIsUndefined(context, object)) {\
38 LogError("Object " << #object << " is undefined");\
42 #define CHECK_JSOBJECT_IS_NULL_RETURN(object, ret) \
44 LogError("Object " << #object << " is NULL");\
50 * Converts JSStringRef to std::string
52 std::string toString(const JSStringRef& arg)
56 size_t jsSize = JSStringGetMaximumUTF8CStringSize(arg);
59 DPL::ScopedArray<char> buffer(new char[jsSize]);
60 size_t written = JSStringGetUTF8CString(arg, buffer.Get(), jsSize);
61 if (written > jsSize) {
62 LogError("Conversion could not be fully performed.");
65 result = buffer.Get();
72 * Converts JSValueRef to std::string
74 std::string toString(JSContextRef ctx, JSValueRef value) {
77 JSStringRef str = JSValueToStringCopy(ctx, value, NULL);
78 result = toString(str);
83 JSValueRef getProperty(JSContextRef ctx, JSValueRef value, const char* name) {
84 Assert(ctx && value && name);
85 JSValueRef result = NULL;
86 JSObjectRef obj = JSValueToObject(ctx, value, NULL);
88 JSStringRef str = JSStringCreateWithUTF8CString(name);
89 result = JSObjectGetProperty(ctx, obj, str, NULL);
95 JSValueRef getPropertyObj(JSContextRef ctx, JSObjectRef obj, const char* name) {
96 Assert(ctx && obj && name);
97 JSStringRef str = JSStringCreateWithUTF8CString(name);
98 JSValueRef result = JSObjectGetProperty(ctx, obj, str, NULL);
103 JSObjectRef getJSGlobalObject(JSGlobalContextRef context){
104 return JSContextGetGlobalObject(context);
109 typedef JSValueRef (*JSCFunction)(
110 JSContextRef context,
112 JSObjectRef thisObject,
113 size_t argumentCount,
114 const JSValueRef arguments[],
115 JSValueRef* exception);
118 void JavaScriptInterface::setObjectProperty(JSGlobalContextRef context,
119 const JSObjectPtr& parentObject,
120 const std::string &propertyName,
121 const JSObjectPtr& propertyObject)
123 LogInfo("Webkit:setting property --" << propertyName << "--");
126 JSStringRef name = JSStringCreateWithUTF8CString(propertyName.c_str());
129 static_cast<JSGlobalContextRef>(context),
130 static_cast<JSObjectRef>(parentObject->getObject()), name,
131 static_cast<JSObjectRef>(propertyObject->getObject()),
132 kJSPropertyAttributeReadOnly, 0);
134 JSStringRelease(name);
137 void JavaScriptInterface::removeObjectProperty(JSGlobalContextRef context,
138 const JSObjectPtr& parentObject,
139 const std::string &propertyName)
142 //nothing to do -> no context
145 LogDebug("Deleting property --" << propertyName << "--");
147 JSStringRef name = JSStringCreateWithUTF8CString(propertyName.c_str());
148 JSObjectDeleteProperty(
149 static_cast<JSGlobalContextRef>(context),
150 static_cast<JSObjectRef>(parentObject->getObject()), name, 0);
152 JSStringRelease(name);
155 JavaScriptInterface::PropertiesList JavaScriptInterface::getObjectPropertiesList(
156 JSGlobalContextRef context,
157 const JSObjectPtr& object) const
159 PropertiesList result;
160 JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(
161 static_cast<JSGlobalContextRef>(context),
162 static_cast<JSObjectRef>(object->getObject()));
163 std::size_t count = JSPropertyNameArrayGetCount(properties);
164 result.reserve(count);
165 LogDebug("propesties count " << count);
166 for (std::size_t i = 0; i < count; ++i) {
167 JSStringRef property = JSPropertyNameArrayGetNameAtIndex(properties, i);
168 result.push_back(toString(property));
170 JSPropertyNameArrayRelease(properties);
174 JSObjectPtr JavaScriptInterface::makeJSFunctionObject(
175 JSGlobalContextRef context,
176 const std::string &name,
177 js_function_impl functionImplementation) const
179 LogDebug("Create JS function");
180 JSStringRef jsFunName = JSStringCreateWithUTF8CString(name.c_str());
182 JSObjectRef object = JSObjectMakeFunctionWithCallback(
185 reinterpret_cast<JSObjectCallAsFunctionCallback>(
186 functionImplementation));
188 JSStringRelease(jsFunName);
189 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
192 JSObjectPtr JavaScriptInterface::makeJSClassObject(
193 JSGlobalContextRef context,
194 JSObjectDeclaration::ConstClassTemplate classTemplate) const
196 LogDebug("Create JS object");
197 JSObjectRef object = JSObjectMake(
199 static_cast<JSClassRef>(
200 const_cast<JSObjectDeclaration::ClassTemplate>(classTemplate)),
202 return JSObjectPtr(new JSObject(object));
205 JSObjectPtr JavaScriptInterface::makeJSObjectBasedOnInterface(
206 JSGlobalContextRef context,
207 const std::string &interfaceName) const
209 LogDebug("Create JS object base on interface: " << interfaceName);
210 LogDebug("Context: " << context);
213 JSObjectPtr jsInterfaceObj = getJSObjectProperty(context,
214 getGlobalObject(context), interfaceName);
215 JSObjectRef object = JSObjectCallAsConstructor(context,
216 static_cast<JSObjectRef>(jsInterfaceObj->getObject()), 0, NULL,
218 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
221 JSObjectPtr JavaScriptInterface::makeJSInterface(
222 JSGlobalContextRef context,
223 JSObjectDeclaration::ConstClassTemplate classTemplate,
224 JSObjectDeclaration::ConstructorCallback constructorCallback) const
226 LogDebug("Create JS interface. Context: " << context);
227 JSObjectRef object = JSObjectMakeConstructor(context,
228 static_cast<JSClassRef>(
229 const_cast<JSObjectDeclaration::ClassTemplate>(
231 reinterpret_cast<JSObjectCallAsConstructorCallback>(
234 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
237 JSObjectPtr JavaScriptInterface::createObject(JSGlobalContextRef context,
238 const JSObjectDeclarationPtr& declaration)
240 typedef JSObjectDeclaration::Options JO;
242 if( declaration->getOptions())
244 switch (declaration->getOptions()->getType())
246 case JO::ClassType::Function:
247 return makeJSFunctionObject(
249 declaration->getName(),
250 declaration->getOptions()->getFunctionImpl());
252 case JO::ClassType::Class:
253 if (declaration->getInterfaceName().empty()) {
254 return makeJSClassObject(
256 declaration->getClassTemplate());
258 return makeJSObjectBasedOnInterface(
260 declaration->getInterfaceName());
263 case JO::ClassType::Interface:
264 return makeJSInterface(
266 /* product class template */
267 declaration->getClassTemplate(),
268 declaration->getConstructorCallback());
271 LogError("Invalid class type. Making empty JS object.");
272 return JSObjectPtr(new JSObject(
273 JSObjectMake(context, NULL, NULL)));
276 LogDebug("No declaration options");
277 return JSObjectPtr(new JSObject(
280 static_cast<JSClassRef>(
281 const_cast<JSObjectDeclaration::ClassTemplate>(
282 declaration->getClassTemplate())),
287 JSObjectPtr JavaScriptInterface::getGlobalObject(JSGlobalContextRef context)
290 return JSObjectPtr(new JSObject(static_cast<JSObject::RealObject>(
291 JSContextGetGlobalObject(static_cast<JSGlobalContextRef>(context)))));
294 JSObjectPtr JavaScriptInterface::copyObjectToIframe(
295 JSGlobalContextRef context,
296 const JSObjectPtr& iframe,
297 const std::string& name)
299 LogError("Copy object to iframe: " << name);
301 JSGlobalContextRef jsGlobalContext =
302 static_cast<JSGlobalContextRef>(context);
304 JSObjectRef globalObject = JSContextGetGlobalObject(jsGlobalContext);
306 JSValueRef requestedObject = getPropertyObj(jsGlobalContext,
309 CHECK_JSVALUE_IS_UNDEFINED_RETURN(jsGlobalContext,
313 JSStringRef requestedObjectStr =
314 JSStringCreateWithUTF8CString(name.c_str());
316 JSObjectSetProperty(jsGlobalContext,
317 static_cast<JSObjectRef>(iframe->getObject()),
320 kJSPropertyAttributeReadOnly,
323 JSStringRelease(requestedObjectStr);
326 new JSObject(const_cast<OpaqueJSValue*>(requestedObject)));
329 JavaScriptInterface::ObjectsListPtr
330 JavaScriptInterface::getIframesList(JSGlobalContextRef ctx) const
332 JSGlobalContextRef context = static_cast<JSGlobalContextRef>(ctx);
334 LogDebug("get global object");
335 JSObjectRef globalObject = JSContextGetGlobalObject(context);
337 ObjectsListPtr retList = getIframesList(context, globalObject);
342 JavaScriptInterface::ObjectsListPtr
343 JavaScriptInterface::getIframesList(JSContextRef context,
344 JSObjectRef globalObject) const
346 JSValueRef frames = getPropertyObj(context, globalObject, "frames");
347 CHECK_JSVALUE_IS_UNDEFINED_RETURN(context, frames, ObjectsListPtr());
349 JSObjectRef frames_o = JSValueToObject(context, frames, NULL);
350 CHECK_JSOBJECT_IS_NULL_RETURN(frames_o, ObjectsListPtr());
352 JSValueRef len = getPropertyObj(context, frames_o, "length");
353 CHECK_JSVALUE_IS_UNDEFINED_RETURN(context, len, ObjectsListPtr());
355 size_t count = JSValueToNumber(context, len, NULL);
356 LogDebug("frames_o.length = " << count);
358 ObjectsListPtr retList = ObjectsListPtr(new ObjectsList());
360 for (size_t i = 0; i < count; ++i) {
361 std::stringstream ss;
363 JSValueRef frame = getPropertyObj(context,
366 if (JSValueIsUndefined(context, frame)) {
367 LogError("Selected frame is null: frame[" << i << "]");
370 JSObjectRef frame_obj = JSValueToObject(context, frame, NULL);
372 LogError("frame_obj is NULL.");
375 retList->push_back(JSObjectPtr(new JSObject(frame_obj)));
376 ObjectsListPtr childList = getIframesList(context, frame_obj);
378 retList->merge(*childList);
379 LogDebug("Frame Value Pointer: " << frame);
380 LogDebug("Frame Object Pointer: " << frame_obj);
386 JSObjectPtr JavaScriptInterface::getJSObjectProperty(JSGlobalContextRef ctx,
387 const JSObjectPtr& frame,
388 const std::string& name) const
390 JSObjectRef frame_js = static_cast<JSObjectRef>(frame->getObject());
392 JSValueRef property = getPropertyObj(ctx, frame_js, name.c_str());
394 JSObjectRef objProp = JSValueToObject(ctx, property, NULL);
396 return JSObjectPtr(new JSObject(objProp));
399 void JavaScriptInterface::removeIframes(JSGlobalContextRef context)
401 const char* deleteIframesScript =
402 "frame_set = document.getElementsByTagName('iframe');"
403 "len = frame_set.length;"
404 "for(i=0; i< len; i++)"
405 " frame_set[0].parentNode.removeChild(frame_set[0]); ";
407 JSGlobalContextRef ctx = static_cast<JSGlobalContextRef>(context);
409 JSStringRef script_src = JSStringCreateWithUTF8CString(deleteIframesScript);
411 JSEvaluateScript(ctx, script_src, 0, 0, 0, 0);
413 JSStringRelease(script_src);
416 void JavaScriptInterface::invokeGarbageCollector(JSGlobalContextRef context)
418 LogDebug("Garbage collection #1");
419 JSGarbageCollect(context);
420 LogDebug("Garbage collection #2");
421 JSGarbageCollect(context);
422 LogDebug("Garbage collection #3");
423 JSGarbageCollect(context);
424 LogDebug("Garbage collection #4");
425 JSGarbageCollect(context);