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