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