1ecad156acc31642873a2d8106d2cc4e6b32fd41
[platform/framework/web/wrt-plugins-common.git] / src / plugin-loading / explorer.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file    explorer.cpp
18  * @author  Grzegorz Krawczyk (g.krawczyk@samgsung.com)
19  * @author  Yunchan Cho (yunchan.cho@samgsung.com)
20  * @version
21  * @brief
22  */
23
24 #include <algorithm>
25 #include <dpl/foreach.h>
26 #include <dpl/log/log.h>
27 #include "explorer.h"
28 #include "plugin_property_support.h"
29
30 // JS overlay
31 #include <js_overlay_support.h>
32 #include <js_overlay_types.h>
33
34 namespace {
35 //const char* SEPARATOR = ".";
36 const std::string GLOBAL_OBJECT_NAME = "GLOBAL_OBJECT";
37 }
38
39 using namespace std;
40 using namespace PluginModule;
41 using namespace WrtPlugins::W3C;
42
43 Explorer::Explorer(JSGlobalContextRef context) :
44     m_context(context)
45 {
46     if (!context) {
47         LogError("Context is NULL");
48         return;
49     }
50
51     m_globalObject =
52         JavaScriptInterfaceSingleton::Instance().getGlobalObject(context);
53
54     LogDebug("Register main frame");
55     //register main frame;
56     m_iframeSupport.registerIframe(m_globalObject);
57
58     m_propertySupport.reset(new WindowPropertySupport(m_context));
59 }
60
61 Explorer::~Explorer()
62 {
63 }
64
65 JSObjectPtr Explorer::getJSObjectProperty(const std::string& propertyName,
66                                           JSObjectPtr object)
67 {
68     LogDebug("Get object property " << propertyName);
69     return JavaScriptInterfaceSingleton::Instance().getJSObjectProperty(
70                m_context, object, propertyName);
71 }
72
73 JSObjectPtr Explorer::getProperty(
74     const string& requestedProperty,
75     JSObjectPtr providedObject)
76 {
77     LogDebug("Requested Property: " << requestedProperty);
78
79     if (!providedObject) {
80         LogError("Provided object is empty");
81         return JSObjectPtr();
82     }
83
84     std::string currentObjectName;
85     std::string currentPropertyRequested = requestedProperty;
86     JSObjectPtr currentObject = providedObject;
87
88     while (true) {
89         auto pos = currentPropertyRequested.find(".");
90         if (pos == string::npos) {
91             return getJSObjectProperty(currentPropertyRequested, currentObject);
92         }
93
94         //check if requested object has child
95         currentObjectName = currentPropertyRequested.substr(0, pos);
96
97         if (currentPropertyRequested.size() <= pos + 1) {
98             LogError("Wrong name of requested property");
99             return JSObjectPtr();
100         }
101         currentPropertyRequested = currentPropertyRequested.substr(pos + 1);
102
103         currentObject = getJSObjectProperty(currentObjectName, currentObject);
104         if (!currentObject) {
105             LogError("Failed to get property: " << currentObjectName);
106             return JSObjectPtr();
107         }
108     }
109 }
110
111 bool Explorer::registerObject(const JSObjectDeclarationPtr& declaration,
112                               JSGlobalContextRef context)
113 {
114     LogDebug("Register to global object");
115
116     bool retValue;
117
118     if (declaration->getParentName() == GLOBAL_OBJECT_NAME) {
119         LogDebug("Connect to Global object");
120         retValue = register_(declaration, m_globalObject, context);
121     } else { //PIM support
122         LogDebug("Connect to NOT global object");
123         //it should be master object name
124         string masterName = declaration->getParentName();
125         auto pos = masterName.find(".");
126         if (string::npos != pos) {
127             LogError("ParentName not allowed");
128             return false;
129         }
130         auto masterObject = getJSObjectProperty(masterName, m_globalObject);
131         if (masterObject->getObject() == 0) {
132             return false;
133         }
134         retValue = registerObject(declaration,
135                                   masterName,
136                                   masterObject,
137                                   context);
138     }
139
140     if (declaration->checkIframesSupported()) {
141         LogDebug("Iframe supported");
142         m_iframeSupport.registerDeclaration(declaration);
143         //        m_iframeSupport.invokeCallbackForMainFrame(m_context,
144         //                                                   declaration,
145         //                                                   newObject);
146     } else {
147         LogDebug("Iframe NOT supported");
148     }
149
150     return retValue;
151 }
152
153 bool Explorer::registerObject(const JSObjectDeclarationPtr& declaration,
154                               const std::string& providedObjectName,
155                               JSObjectPtr providedObject,
156                               JSGlobalContextRef context)
157 {
158     LogDebug(
159         "Register object. Provided object name: '" << providedObjectName
160                                                    <<
161         "', registration of: '" << declaration->getName() << "'");
162
163     std::string fullParentName = declaration->getParentName();
164     LogDebug("Parent name: " << declaration->getParentName());
165
166     if (fullParentName == providedObjectName) {
167         LogDebug("Provided object match equaly to requested parent");
168         return register_(declaration, providedObject, context);
169     }
170
171     //check if object exists in fullParentName
172     auto pos = fullParentName.find(providedObjectName);
173     if (pos == string::npos) {
174         LogError(
175             "Object: " << declaration->getName()
176                        << " should be child of: " <<
177             declaration->getParentName()
178                        << " but you provided object: " <<
179             providedObjectName);
180
181         return false;
182     }
183
184     if (fullParentName.size() <= pos + providedObjectName.size() + 1) {
185         LogError("Invalid object name");
186         return false;
187     }
188
189     auto currentRequesteProperty =
190         fullParentName.substr(pos + providedObjectName.size() + 1);
191
192     JSObjectPtr jsObject = getProperty(
193             currentRequesteProperty, providedObject);
194
195     if (!jsObject->getObject()) {
196         LogError(
197             "Object: '" << declaration->getName()
198                         << "' should be child of: '" <<
199             declaration->getParentName()
200                         << "'. you provided object: '" <<
201             providedObjectName
202                         << "' but object is null");
203
204         return false;
205     }
206
207     return register_(declaration, jsObject, context);
208 }
209
210 bool Explorer::register_(const JSObjectDeclarationPtr& declaration,
211                          JSObjectPtr parent,
212                          JSGlobalContextRef context)
213 {
214     LogInfo("Registration object: " << declaration->getParentName() <<
215             "<-" << declaration->getName());
216
217     Assert(parent && "parent object is NULL");
218
219     typedef JSObjectDeclaration::Options JO;
220
221     JSGlobalContextRef gContext = (context == NULL) ? m_context : context;
222     JSObjectPtr newObject;
223
224     JSObjectPtr objectInstance = JavaScriptInterfaceSingleton::Instance().
225             createObject(gContext, declaration);
226
227     //function creation
228     if (declaration->getOptions() &&
229         declaration->getOptions()->getType() == JO::ClassType::Function)
230     {
231         LogDebug("Loading function object " << declaration->getName());
232
233         auto type = declaration->getOptions()->getIframeOverlay();
234         if (JO::IFrameOverlay::OverlayedBeforeOriginal == type) {
235             LogDebug("Create overlayed function");
236             JSObjectPtr original =
237                 JavaScriptInterfaceSingleton::Instance().
238                     getJSObjectProperty(gContext,
239                                         parent,
240                                         declaration->getName());
241             newObject = JSOverlaySupport::
242                     createWrappedFunction(gContext,
243                                           original,
244                                           objectInstance,
245                                           declaration->getName());
246         } else {
247             LogDebug("create normal function");
248             newObject = objectInstance;
249         }
250     } else { //object creation
251         newObject = objectInstance;
252     }
253
254     JavaScriptInterfaceSingleton::Instance().setObjectProperty(
255         gContext,
256         parent,
257         declaration->getName(),
258         newObject);
259
260     //notice
261     if (declaration->getOptions() &&
262         (declaration->getOptions()->getIframeNotice() ==
263          JO::IFrameNotice::AlwaysNotice))
264     {
265         declaration->getOptions()->invokeCallback(gContext,
266                                                   parent->getObject(),
267                                                   objectInstance->getObject());
268     }
269
270     return true;
271 }
272
273 void Explorer::registerObjectIntoIframe(
274     const JSObjectDeclarationPtr& declaration,
275     JSObjectPtr frameObject,
276     JSGlobalContextRef context)
277 {
278     if (declaration->getParentName() == GLOBAL_OBJECT_NAME) {
279         LogDebug("Connect to Global object of IFRAME");
280         register_(declaration, frameObject, context);
281         return;
282     }
283
284     //PIM SUPPORT
285     {
286         LogWarning("Connect to NOT global object of IFRAME");
287         //it should be master object name
288         string masterName = declaration->getParentName();
289         auto pos = masterName.find(".");
290         if (string::npos != pos) {
291             LogError("ParentName not allowed");
292             return;
293         }
294         auto masterObject = getJSObjectProperty(masterName, frameObject);
295         if (!masterObject->getObject()) {
296             LogError("Object not exist in frame");
297             return;
298         }
299         register_(declaration, masterObject, context);
300     }
301 }
302
303 void Explorer::loadFrame(JSGlobalContextRef context)
304 {
305     LogDebug("Frame attached");
306
307     JSObjectPtr frameObject =
308         JavaScriptInterfaceSingleton::Instance().getGlobalObject(context);
309
310     LogDebug("Register main frame");
311     //register main frame;
312
313     if (frameObject->getObject() == m_globalObject->getObject()) {
314         // Main page was already loaded from constructor
315         LogDebug("Main page loaded");
316         return;
317     }
318
319     m_iframeSupport.registerIframe(frameObject);
320
321     auto iframeObjects = m_iframeSupport.getIframeObjects();
322
323     FOREACH(object, iframeObjects)
324     {
325         LogDebug("Register object: " << (*object)->getName() );
326
327         registerObjectIntoIframe(*object, frameObject, context);
328     }
329 }
330
331 void Explorer::unloadFrame(JSGlobalContextRef context)
332 {
333     LogDebug("Frame detached");
334
335     JSObjectPtr frameObject =
336         JavaScriptInterfaceSingleton::Instance().getGlobalObject(context);
337
338     m_iframeSupport.unregisterIframe(frameObject);
339 }
340
341 void Explorer::removePluginsFromIframes()
342 {
343     LogDebug("Remove plugins from iframes");
344
345     if (m_iframeSupport.hasIframes()) {
346         LogDebug("Removing iframes");
347         JavaScriptInterfaceSingleton::Instance().removeIframes(m_context);
348     }
349 }
350
351 void Explorer::deregisterObject(const JSObjectDeclarationPtr& declaration)
352 {
353     LogDebug("Deregister object " << declaration->getName());
354
355     if (GLOBAL_OBJECT_NAME != declaration->getParentName()) {
356         LogWarning("Ignored remove property " << declaration->getName());
357         return;
358     }
359
360     JavaScriptInterfaceSingleton::Instance().
361         removeObjectProperty(m_context,
362                              m_globalObject,
363                              declaration->getName());
364 }
365
366 void Explorer::cleanIframesData()
367 {
368     LogDebug("Clean iframes data");
369     m_iframeSupport.clean();
370 }
371
372 void Explorer::callEventListeners(CustomEventType eventType, void* data)
373 {
374 #if 0 // deprecated
375     using namespace WrtPlugins::Tizen;
376     // get iframe objects from javascript global context
377     JavaScriptInterface::ObjectsListPtr frameLists =
378         JavaScriptInterfaceSingleton::Instance().getIframesList(m_context);
379
380     // get main frame object from javascript global context
381     JSObjectRef mainFrame = JSContextGetGlobalObject(m_context);
382     frameLists->push_back(JSObjectPtr(new JSObject(mainFrame)));
383
384     if (eventType == ServiceCustomEvent) {
385         using namespace WrtDeviceApis::TizenServiceEvent::Api;
386         // set user data of js callback function for 'appservice' js event
387         ITizenServiceEventPtr event = ITizenServiceEventPtr(
388                 new TizenServiceEvent());
389         event->setScale(m_propertySupport->getScale());
390         event->setBundle(m_propertySupport->getBundle());
391
392         // call js callback function for 'appservice' js event on each frame
393         FOREACH(it, *frameLists)
394         {
395             JSObjectRef frame = static_cast<JSObjectRef>((*it).Get()->getObject());
396
397             auto eventPriv =
398                 new JSTizenServiceEventPrivateObject(m_context, event);
399             JSObjectRef eventObject =
400                 JSObjectMake(m_context,
401                              JSTizenServiceEvent::getClassRef(), eventPriv);
402
403             AddEventListenerSupport::CallCustomEventListenersFromIFrame(
404                 frame, eventType, eventObject);
405         }
406     } else if (eventType == SoftKeyboardChangeCustomEvent) {
407         using namespace WrtDeviceApis::SoftKeyboardChangeEvent::Api;
408         if (!data) {
409             LogDebug("no ime size");
410             return;
411         }
412
413         // set user data of js callback function for 'softkeyboardchange' js
414         // event
415         SoftKeyboardChangeArgs* args =
416             static_cast<SoftKeyboardChangeArgs *>(data);
417         ISoftKeyboardChangeEventPtr event =
418             ISoftKeyboardChangeEventPtr(
419                 new SoftKeyboardChangeEvent(
420                     args->state,
421                     args->width,
422                     args->height));
423         LogInfo("softkeyboard event's state: " << args->state);
424
425         // call js callback function for 'softkeyboardchange' js event on each
426         // frame
427         FOREACH(it, *frameLists)
428         {
429             JSObjectRef frame = static_cast<JSObjectRef>((*it).Get()->getObject());
430
431             auto eventPriv =
432                 new JSSoftKeyboardChangeEventPrivateObject(m_context, event);
433             JSObjectRef eventObject =
434                 JSObjectMake(
435                     m_context,
436                     JSSoftKeyboardChangeEvent::getClassRef(),
437                     eventPriv);
438
439             AddEventListenerSupport::CallCustomEventListenersFromIFrame(
440                 frame, eventType, eventObject);
441         }
442     } else {
443         LogInfo("Not supported custom event type");
444         return;
445     }
446 #endif
447 }
448
449 WindowPropertySupport* Explorer::getWindowPropertySupport()
450 {
451     return m_propertySupport.get();
452 }