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