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