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)
78 JSStringRef str = JSValueToStringCopy(ctx, value, NULL);
79 result = toString(str);
84 JSValueRef getProperty(JSContextRef ctx, JSValueRef value, const char* name)
86 Assert(ctx && value && name);
87 JSValueRef result = NULL;
88 JSObjectRef obj = JSValueToObject(ctx, value, NULL);
90 JSStringRef str = JSStringCreateWithUTF8CString(name);
91 result = JSObjectGetProperty(ctx, obj, str, NULL);
97 JSValueRef getPropertyObj(JSContextRef ctx, JSObjectRef obj, const char* name)
99 Assert(ctx && obj && name);
100 JSStringRef str = JSStringCreateWithUTF8CString(name);
101 JSValueRef result = JSObjectGetProperty(ctx, obj, str, NULL);
102 JSStringRelease(str);
106 JSObjectRef getJSGlobalObject(JSGlobalContextRef context)
108 return JSContextGetGlobalObject(context);
112 typedef JSValueRef (*JSCFunction)(
113 JSContextRef context,
115 JSObjectRef thisObject,
116 size_t argumentCount,
117 const JSValueRef arguments[],
118 JSValueRef* exception);
120 void JavaScriptInterface::setObjectProperty(JSGlobalContextRef context,
121 const JSObjectPtr& parentObject,
122 const std::string &propertyName,
123 const JSObjectPtr& propertyObject)
125 LogInfo("Webkit:setting property --" << propertyName << "--");
128 JSStringRef name = JSStringCreateWithUTF8CString(propertyName.c_str());
131 static_cast<JSGlobalContextRef>(context),
132 static_cast<JSObjectRef>(parentObject->getObject()), name,
133 static_cast<JSObjectRef>(propertyObject->getObject()),
134 kJSPropertyAttributeReadOnly, 0);
136 JSStringRelease(name);
139 void JavaScriptInterface::removeObjectProperty(JSGlobalContextRef context,
140 const JSObjectPtr& parentObject,
141 const std::string &propertyName)
144 //nothing to do -> no context
147 LogDebug("Deleting property --" << propertyName << "--");
149 JSStringRef name = JSStringCreateWithUTF8CString(propertyName.c_str());
150 JSObjectDeleteProperty(
151 static_cast<JSGlobalContextRef>(context),
152 static_cast<JSObjectRef>(parentObject->getObject()), name, 0);
154 JSStringRelease(name);
157 JavaScriptInterface::PropertiesList JavaScriptInterface::
158 getObjectPropertiesList(
159 JSGlobalContextRef context,
160 const JSObjectPtr& object) const
162 PropertiesList result;
163 JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(
164 static_cast<JSGlobalContextRef>(context),
165 static_cast<JSObjectRef>(object->getObject()));
166 std::size_t count = JSPropertyNameArrayGetCount(properties);
167 result.reserve(count);
168 LogDebug("propesties count " << count);
169 for (std::size_t i = 0; i < count; ++i) {
170 JSStringRef property = JSPropertyNameArrayGetNameAtIndex(properties, i);
171 result.push_back(toString(property));
173 JSPropertyNameArrayRelease(properties);
177 JSObjectPtr JavaScriptInterface::makeJSFunctionObject(
178 JSGlobalContextRef context,
179 const std::string &name,
180 js_function_impl functionImplementation) const
182 LogDebug("Create JS function");
183 JSStringRef jsFunName = JSStringCreateWithUTF8CString(name.c_str());
185 JSObjectRef object = JSObjectMakeFunctionWithCallback(
188 reinterpret_cast<JSObjectCallAsFunctionCallback>(
189 functionImplementation));
191 JSStringRelease(jsFunName);
192 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
195 JSObjectPtr JavaScriptInterface::makeJSClassObject(
196 JSGlobalContextRef context,
197 JSObjectDeclaration::ConstClassTemplate classTemplate) const
199 LogDebug("Create JS object");
200 JSObjectRef object = JSObjectMake(
202 static_cast<JSClassRef>(
203 const_cast<JSObjectDeclaration::ClassTemplate>(classTemplate)),
205 return JSObjectPtr(new JSObject(object));
208 JSObjectPtr JavaScriptInterface::makeJSObjectBasedOnInterface(
209 JSGlobalContextRef context,
210 const std::string &interfaceName) const
212 LogDebug("Create JS object base on interface: " << interfaceName);
213 LogDebug("Context: " << context);
215 JSObjectPtr jsInterfaceObj = getJSObjectProperty(context,
219 JSObjectRef object = JSObjectCallAsConstructor(context,
220 static_cast<JSObjectRef>(
225 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
228 JSObjectPtr JavaScriptInterface::makeJSInterface(
229 JSGlobalContextRef context,
230 JSObjectDeclaration::ConstClassTemplate classTemplate,
231 JSObjectDeclaration::ConstructorCallback constructorCallback) const
233 LogDebug("Create JS interface. Context: " << context);
234 JSObjectRef object = JSObjectMakeConstructor(context,
235 static_cast<JSClassRef>(
237 JSObjectDeclaration::
241 JSObjectCallAsConstructorCallback>(
244 return JSObjectPtr(new JSObject(static_cast<void*>(object)));
247 JSObjectPtr JavaScriptInterface::createObject(
248 JSGlobalContextRef context,
249 const JSObjectDeclarationPtr&
252 typedef JSObjectDeclaration::Options JO;
254 if (declaration->getOptions()) {
255 switch (declaration->getOptions()->getType()) {
256 case JO::ClassType::Function:
257 return makeJSFunctionObject(
259 declaration->getName(),
260 declaration->getOptions()->getFunctionImpl());
262 case JO::ClassType::Class:
263 if (declaration->getInterfaceName().empty()) {
264 return makeJSClassObject(
266 declaration->getClassTemplate());
268 return makeJSObjectBasedOnInterface(
270 declaration->getInterfaceName());
273 case JO::ClassType::Interface:
274 return makeJSInterface(
276 /* product class template */
277 declaration->getClassTemplate(),
278 declaration->getConstructorCallback());
281 LogError("Invalid class type. Making empty JS object.");
282 return JSObjectPtr(new JSObject(
283 JSObjectMake(context, NULL, NULL)));
286 LogDebug("No declaration options");
287 return JSObjectPtr(new JSObject(
290 static_cast<JSClassRef>(
291 const_cast<JSObjectDeclaration::
293 declaration->getClassTemplate())),
298 JSObjectPtr JavaScriptInterface::getGlobalObject(JSGlobalContextRef context)
301 return JSObjectPtr(new JSObject(static_cast<JSObject::RealObject>(
302 JSContextGetGlobalObject(static_cast<
307 JSObjectPtr JavaScriptInterface::copyObjectToIframe(
308 JSGlobalContextRef context,
309 const JSObjectPtr& iframe,
310 const std::string& name)
312 LogError("Copy object to iframe: " << name);
314 JSGlobalContextRef jsGlobalContext =
315 static_cast<JSGlobalContextRef>(context);
317 JSObjectRef globalObject = JSContextGetGlobalObject(jsGlobalContext);
319 JSValueRef requestedObject = getPropertyObj(jsGlobalContext,
322 CHECK_JSVALUE_IS_UNDEFINED_RETURN(jsGlobalContext,
326 JSStringRef requestedObjectStr =
327 JSStringCreateWithUTF8CString(name.c_str());
329 JSObjectSetProperty(jsGlobalContext,
330 static_cast<JSObjectRef>(iframe->getObject()),
333 kJSPropertyAttributeReadOnly,
336 JSStringRelease(requestedObjectStr);
339 new JSObject(const_cast<OpaqueJSValue*>(requestedObject)));
342 JavaScriptInterface::ObjectsListPtr
343 JavaScriptInterface::getIframesList(JSGlobalContextRef ctx) const
345 JSGlobalContextRef context = static_cast<JSGlobalContextRef>(ctx);
347 LogDebug("get global object");
348 JSObjectRef globalObject = JSContextGetGlobalObject(context);
350 ObjectsListPtr retList = getIframesList(context, globalObject);
355 JavaScriptInterface::ObjectsListPtr
356 JavaScriptInterface::getIframesList(JSContextRef context,
357 JSObjectRef globalObject) const
359 JSValueRef frames = getPropertyObj(context, globalObject, "frames");
360 CHECK_JSVALUE_IS_UNDEFINED_RETURN(context, frames, ObjectsListPtr());
362 JSObjectRef frames_o = JSValueToObject(context, frames, NULL);
363 CHECK_JSOBJECT_IS_NULL_RETURN(frames_o, ObjectsListPtr());
365 JSValueRef len = getPropertyObj(context, frames_o, "length");
366 CHECK_JSVALUE_IS_UNDEFINED_RETURN(context, len, ObjectsListPtr());
368 size_t count = JSValueToNumber(context, len, NULL);
369 LogDebug("frames_o.length = " << count);
371 ObjectsListPtr retList = ObjectsListPtr(new ObjectsList());
373 for (size_t i = 0; i < count; ++i) {
374 std::stringstream ss;
376 JSValueRef frame = getPropertyObj(context,
379 if (JSValueIsUndefined(context, frame)) {
380 LogError("Selected frame is null: frame[" << i << "]");
383 JSObjectRef frame_obj = JSValueToObject(context, frame, NULL);
385 LogError("frame_obj is NULL.");
388 retList->push_back(JSObjectPtr(new JSObject(frame_obj)));
389 ObjectsListPtr childList = getIframesList(context, frame_obj);
391 retList->merge(*childList);
392 LogDebug("Frame Value Pointer: " << frame);
393 LogDebug("Frame Object Pointer: " << frame_obj);
399 JSObjectPtr JavaScriptInterface::getJSObjectProperty(JSGlobalContextRef ctx,
400 const JSObjectPtr& frame,
401 const std::string& name)
404 JSObjectRef frame_js = static_cast<JSObjectRef>(frame->getObject());
406 JSValueRef property = getPropertyObj(ctx, frame_js, name.c_str());
408 JSObjectRef objProp = JSValueToObject(ctx, property, NULL);
410 return JSObjectPtr(new JSObject(objProp));
413 void JavaScriptInterface::removeIframes(JSGlobalContextRef context)
415 const char* deleteIframesScript =
416 "frame_set = document.getElementsByTagName('iframe');"
417 "len = frame_set.length;"
418 "for(i=0; i< len; i++)"
419 " frame_set[0].parentNode.removeChild(frame_set[0]); ";
421 JSGlobalContextRef ctx = static_cast<JSGlobalContextRef>(context);
423 JSStringRef script_src = JSStringCreateWithUTF8CString(deleteIframesScript);
425 JSEvaluateScript(ctx, script_src, 0, 0, 0, 0);
427 JSStringRelease(script_src);
430 void JavaScriptInterface::invokeGarbageCollector(JSGlobalContextRef context)
432 LogDebug("Garbage collection #1");
433 JSGarbageCollect(context);
434 LogDebug("Garbage collection #2");
435 JSGarbageCollect(context);
436 LogDebug("Garbage collection #3");
437 JSGarbageCollect(context);
438 LogDebug("Garbage collection #4");
439 JSGarbageCollect(context);