Terminate HereView when closing HereManager
[platform/core/location/maps-plugin-here.git] / src / here_view.cpp
1 /*
2  * Copyright (c) 2014 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 #include "here_view.h"
18 #include <Elementary.h>
19
20 using namespace HERE_PLUGIN_NAMESPACE_PREFIX;
21
22 static const char SIG_LOADED[] = "loaded";
23
24
25 HERE_PLUGIN_BEGIN_NAMESPACE
26
27 HereView::HereView()
28 {
29         __map = NULL;
30
31         __img = NULL;
32         __ctx = NULL;
33         __sfc = NULL;
34         __cfg = NULL;
35         __gl = NULL;
36         __api = NULL;
37
38         __isInitialized = false;
39         __isShutdown = false;
40
41         __x = 0;
42         __y = 0;
43         __w = 0;
44         __h = 0;
45
46         __idler = NULL;
47         __redraw = false;
48         __readyCb = NULL;
49 }
50
51 HereView::~HereView()
52 {
53 }
54
55 void HereView::TerminateService(void)
56 {
57         if (!__isShutdown) {
58                 MAPS_LOGD("close HereView");
59                 close(NULL);
60         }
61         delete this;
62 }
63
64 here_error_e HereView::init(maps_view_h view, maps_plugin_map_view_ready_cb callback)
65 {
66         if (!view)
67                 return HERE_ERROR_INVALID_PARAMETER;
68
69         __idler = ecore_idler_add(__idlerCb, (void*)view);
70
71         here_error_e error = HERE_ERROR_NONE;
72         int error2 = MAPS_ERROR_NONE;
73
74         do {
75                 error2 = maps_view_get_viewport(view, &__img);
76                 if (error2 != MAPS_ERROR_NONE) break;
77
78                 error2 = maps_view_get_screen_location(view, &__x, &__y, &__w, &__h);
79                 if (error2 != MAPS_ERROR_NONE) break;
80
81                 error = initOpenGL();
82                 if (error != HERE_ERROR_NONE) break;
83
84                 error = initOpenGLSurface(view);
85                 if (error != HERE_ERROR_NONE) break;
86
87                 error = initMap(view, callback);
88         } while (0);
89
90         if (error == HERE_ERROR_NONE && error2 != MAPS_ERROR_NONE)
91                 error = (here_error_e)ConvertToHereError(error2);
92
93         return error;
94 }
95
96 here_error_e HereView::initOpenGL()
97 {
98         __cfg = evas_gl_config_new();
99         if (!__cfg) {
100                 MAPS_LOGE("evas_gl_config_new() failed");
101                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
102         }
103
104         __cfg->color_format = EVAS_GL_RGBA_8888;    // Surface Color Format
105         __cfg->depth_bits   = EVAS_GL_DEPTH_NONE;   // Surface Depth Format
106         __cfg->stencil_bits = EVAS_GL_STENCIL_NONE; // Surface Stencil Format
107         __cfg->options_bits = EVAS_GL_OPTIONS_DIRECT; // Configuration options (here, no extra options)
108
109         __gl = evas_gl_new(evas_object_evas_get(__img));
110         if (!__gl) {
111                 MAPS_LOGE("evas_gl_new() failed");
112                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
113         }
114
115         __api = evas_gl_api_get(__gl);
116         if (!__api) {
117                 MAPS_LOGE("evas_gl_api_get() failed");
118                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
119         }
120
121         __ctx = evas_gl_context_create(__gl, NULL);
122         if (!__ctx) {
123                 MAPS_LOGE("evas_gl_context_create() failed");
124                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
125         }
126
127         return HERE_ERROR_NONE;
128 }
129
130 here_error_e HereView::initOpenGLSurface(maps_view_h view)
131 {
132         if (!view || !__gl || !__cfg || !__img || !__ctx)
133                 return HERE_ERROR_INVALID_PARAMETER;
134
135         evas_object_image_pixels_get_callback_set(__img, NULL, NULL);
136
137         if (__sfc) {
138                 evas_object_image_native_surface_set(__img, NULL);
139                 evas_gl_surface_destroy(__gl, __sfc);
140         }
141
142         __w = MAX(__w, 1);
143         __h = MAX(__h, 1);
144
145         evas_object_image_size_set(__img, __w, __h);
146
147         Evas_Native_Surface ns;
148         __sfc = evas_gl_surface_create(__gl, __cfg, __w, __h);
149         if (!__sfc) {
150                 MAPS_LOGE("evas_gl_surface_create() failed");
151                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
152         }
153
154         if (!evas_gl_native_surface_get(__gl, __sfc, &ns)) {
155                 evas_gl_make_current(__gl, NULL, NULL);
156                 evas_gl_surface_destroy(__gl, __sfc);
157                 __sfc = NULL;
158                 MAPS_LOGE("evas_gl_native_surface_get() faile");
159                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
160         }
161
162         evas_object_image_native_surface_set(__img, &ns);
163         evas_object_image_pixels_get_callback_set(__img, __pixelGetCb, view);
164         __isInitialized = true;
165
166         return HERE_ERROR_NONE;
167 }
168
169 here_error_e HereView::initMap(maps_view_h view,  maps_plugin_map_view_ready_cb callback)
170 {
171         if (!view)
172                 return HERE_ERROR_INVALID_PARAMETER;
173
174         __map = new (std::nothrow) GeoTiledMap();
175         if (!__map)
176                 return HERE_ERROR_OUT_OF_MEMORY;
177
178         __readyCb = callback;
179
180         __map->SetReadyMapSignal((GeoTiledMap::ReadyMapSignalFunctor)__readyMapCb, (void *)view);
181         __map->SetEvasGlApi(__api);
182         __map->SetMapSize(Dimension(__w, __h));
183
184         __visualObjects.set(__map, evas_object_evas_get(__img));
185
186         return HERE_ERROR_NONE;
187 }
188
189 here_error_e HereView::close(maps_view_h view)
190 {
191         MAPS_LOGD("close");
192
193         __isInitialized = false;
194         __isShutdown = true;
195
196         __visualObjects.set(NULL, NULL);
197
198         if (__img)
199                 evas_object_image_pixels_get_callback_set(__img, NULL, NULL);
200
201         if (__idler) {
202                 ecore_idler_del(__idler);
203                 __idler = NULL;
204         }
205
206         if (__map) {
207                 __map->SetUpdateMapSignal(NULL);
208                 delete __map;
209         }
210
211         /* clear Open GL */
212         if (__gl) {
213                 if (__sfc && __ctx)
214                         evas_gl_make_current(__gl, __sfc, __ctx);
215
216                 if (__sfc) {
217                         evas_object_image_native_surface_set(__img, NULL);
218                         evas_gl_surface_destroy(__gl, __sfc);
219                 }
220
221                 if (__ctx)
222                         evas_gl_context_destroy(__gl, __ctx);
223
224                 evas_gl_free(__gl);
225                 __gl = NULL;
226         }
227
228         if (__cfg)
229                 evas_gl_config_free(__cfg);
230
231         return HERE_ERROR_NONE;
232 }
233
234 void HereView::__readyMapCb(void *data)
235 {
236         HereView *hv = NULL;
237         int maps_error = maps_view_get_maps_plugin_view_handle((maps_view_h)data, (void**)&hv);
238         if (maps_error != MAPS_ERROR_NONE || !hv) return;
239
240         if (hv->__readyCb)
241                 hv->__readyCb(data);
242 }
243
244 void HereView::__pixelGetCb(void *data, Evas_Object *obj)
245 {
246         HereView *hv = NULL;
247         int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&hv);
248         if (maps_error != MAPS_ERROR_NONE || !hv ||
249                 !hv->__map || !hv->__gl || !hv->__sfc || !hv->__ctx) return;
250
251         evas_gl_make_current(hv->__gl, hv->__sfc, hv->__ctx);
252         hv->__map->PaintMap(hv->__w, hv->__h);
253 }
254
255 void HereView::__renderingCb(void *data)
256 {
257         if (!data) return;
258         evas_object_image_pixels_dirty_set((Evas_Object*)data, EINA_TRUE);
259 }
260
261 void HereView::setMapType(maps_view_h view)
262 {
263         if (!view)
264                 return;
265
266         /* When the theme is changed, clear cache */
267         maps_view_type_e map_type;
268         maps_view_get_type(view, &map_type);
269
270         bool buildings_enabled = false;
271         maps_view_get_buildings_enabled(view, &buildings_enabled);
272
273         bool traffic_enabled = false;
274         maps_view_get_traffic_enabled(view, &traffic_enabled);
275
276         bool public_transit_enabled = false;
277         maps_view_get_public_transit_enabled(view, &public_transit_enabled);
278
279         GeoTiledMap::MapType hereMapType = HereUtils::Convert(map_type, buildings_enabled,
280                                                 traffic_enabled, public_transit_enabled);
281
282         if (hereMapType != __map->GetMapType())
283         {
284                 MAPS_LOGD("Clear cache, because map type is changed.");
285                 __map->ClearCache();
286 #ifdef TIZEN_SUPPORT_TILE_FILE_CACHE
287                 __map->ClearTileFileCache();
288 #endif
289                 __map->SetMapType(hereMapType);
290         }
291 }
292
293 here_error_e HereView::renderMap(maps_view_h view, const maps_coordinates_h coord, double zoom, double angle)
294 {
295         if (!view || !coord)
296                 return HERE_ERROR_INVALID_PARAMETER;
297
298         if (!__isInitialized || !__map || !__api)
299                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
300
301         /* set map type */
302         setMapType(view);
303
304         /* resize window */
305         int x, y, w, h;
306         maps_view_get_screen_location(view, &x, &y, &w, &h);
307         __w = MAX(__w, 1);
308         __h = MAX(__h, 1);
309
310         if (x != __x || y != __y || w != __w || h != __h) {
311                 __x = x;
312                 __y = y;
313                 __w = w;
314                 __h = h;
315
316                 __api->glViewport(0, 0, __w, __h);
317                 __map->SetMapSize(Dimension(__w, __h));
318                 initOpenGLSurface(view);
319         }
320
321         /* callback */
322         GeoTiledMap::UpdateMapSignalFunctor callback = std::tr1::bind(&__renderingCb, __img);
323         __map->SetUpdateMapSignal(callback);
324
325         /* zoom level */
326         if (__map->GetZoomLevel() != zoom) {
327                 __map->SetZoomLevel(zoom, false);
328         }
329
330         /* angle */
331         if (__map->GetAngle() != angle) {
332                 __map->SetAngle(angle);
333         }
334
335         /* center */
336         double lat, lng;
337         maps_coordinates_get_latitude(coord, &lat);
338         maps_coordinates_get_longitude(coord, &lng);
339
340         GeoCoordinates geoCoord(lat, lng);
341         __map->SetCenter(geoCoord);
342
343         return HERE_ERROR_NONE;
344 }
345
346 here_error_e HereView::moveCenter(maps_view_h view, int delta_x, int delta_y)
347 {
348         if (!view)
349                 return HERE_ERROR_INVALID_PARAMETER;
350
351         if (!__isInitialized || !__map)
352                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
353
354         if (delta_x == 0 && delta_y == 0)
355                 return HERE_ERROR_NONE;
356
357         __map->Pan(delta_x, delta_y);
358
359         return HERE_ERROR_NONE;
360 }
361
362 here_error_e HereView::getCenter(maps_view_h view, maps_coordinates_h *center)
363 {
364         if (!view || !center)
365                 return HERE_ERROR_INVALID_PARAMETER;
366
367         if (!__isInitialized || !__map)
368                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
369
370         GeoCoordinates geoCoord = __map->GetCenter();
371         if (*center == NULL) {
372                 maps_coordinates_create(geoCoord.GetLatitude(), geoCoord.GetLongitude(), center);
373         } else {
374                 maps_coordinates_set_latitude(*center, geoCoord.GetLatitude());
375                 maps_coordinates_set_longitude(*center, geoCoord.GetLongitude());
376         }
377
378         return HERE_ERROR_NONE;
379 }
380
381 here_error_e HereView::setScalebarEnabled(maps_view_h view, bool enable)
382 {
383         if (!view)
384                 return HERE_ERROR_INVALID_PARAMETER;
385
386         if (!__isInitialized || !__map)
387                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
388
389         __map->SetScalebar(enable);
390
391         return HERE_ERROR_NONE;
392 }
393
394 here_error_e HereView::getScalebarEnabled(maps_view_h view, bool *enabled)
395 {
396         if (!view || !enabled)
397                 return HERE_ERROR_INVALID_PARAMETER;
398
399         if (!__isInitialized || !__map)
400                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
401
402         *enabled = __map->GetScalebar();
403         return HERE_ERROR_NONE;
404 }
405
406 here_error_e HereView::convertScreenToGeolocation(maps_view_h view, int x, int y, maps_coordinates_h *coord)
407 {
408         if (!view || !coord)
409                 return HERE_ERROR_INVALID_PARAMETER;
410
411         if (!__isInitialized || !__map)
412                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
413
414         Tizen::Maps::Point point(x, y);
415         GeoCoordinates geoCoord = __map->ScreenPositionToCoordinate(point);
416         double lat = geoCoord.GetLatitude();
417         double lng = geoCoord.GetLongitude();
418
419         int error = maps_coordinates_create(lat, lng, coord);
420         if (error != MAPS_ERROR_NONE)
421                 return (here_error_e)ConvertToHereError(error);
422
423         return HERE_ERROR_NONE;
424 }
425
426 here_error_e HereView::convertGeolocationToScreen(maps_view_h view, const maps_coordinates_h coord, int *x, int *y)
427 {
428         if (!view || !x || !y)
429                 return HERE_ERROR_INVALID_PARAMETER;
430
431         if (!__isInitialized || !__map)
432                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
433
434         double lat, lng;
435         maps_coordinates_get_latitude(coord, &lat);
436         maps_coordinates_get_longitude(coord, &lng);
437         GeoCoordinates geoCoord(lat, lng);
438         Tizen::Maps::Point point = __map->CoordinateToScreenPosition(geoCoord);
439
440         *x = point.x;
441         *y = point.y;
442
443         return HERE_ERROR_NONE;
444 }
445
446 here_error_e HereView::getMinZoomLevel(maps_view_h view, int *zoom)
447 {
448         if (!view || !zoom)
449                 return HERE_ERROR_INVALID_PARAMETER;
450
451         if (!__isInitialized || !__map)
452                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
453
454         *zoom = (int)__map->GetMinimumZoomLevel();
455
456         return HERE_ERROR_NONE;
457 }
458
459 here_error_e HereView::getMaxZoomLevel(maps_view_h view, int *zoom)
460 {
461         if (!view || !zoom)
462                 return HERE_ERROR_INVALID_PARAMETER;
463
464         if (!__isInitialized || !__map)
465                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
466
467         *zoom = (int)__map->GetMaximumZoomLevel();
468
469         return HERE_ERROR_NONE;
470 }
471
472 here_error_e HereView::onViewObject(maps_view_h view, const maps_view_object_h object, maps_view_object_operation_e operation)
473 {
474         if (!view || !object ||
475                 operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE)
476                 return HERE_ERROR_INVALID_PARAMETER;
477
478         if (!__isInitialized || !__map)
479                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
480
481         if (__map->GetRootPixmap())
482                 __processViewObject(view, object, operation);
483         else
484                 __pendingObjects.push_back(std::make_pair(object, operation));
485
486         return HERE_ERROR_NONE;
487 }
488
489 Eina_Bool HereView::__idlerCb(void *data)
490 {
491         HereView *hv = NULL;
492         int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&hv);
493         if (maps_error != MAPS_ERROR_NONE || !hv) return ECORE_CALLBACK_CANCEL;
494         if (hv->__isShutdown) return ECORE_CALLBACK_CANCEL;
495         if (!hv->__map || !hv->__map->GetRootPixmap()) return ECORE_CALLBACK_RENEW;
496
497         while (hv->__pendingObjects.size()) {
498                 PendingObject pending = hv->__pendingObjects.front();
499                 hv->__pendingObjects.pop_front();
500                 maps_view_object_h object = pending.first;
501                 maps_view_object_operation_e operation = pending.second;
502
503                 __processViewObject(data, object, operation);
504         }
505         return ECORE_CALLBACK_RENEW;
506 }
507
508 void HereView::__processViewObject(maps_view_h view, const maps_view_object_h object, maps_view_object_operation_e operation)
509 {
510         HereView *hv = NULL;
511         int maps_error = maps_view_get_maps_plugin_view_handle(view, (void**)&hv);
512         if (maps_error != MAPS_ERROR_NONE || !hv) return;
513
514         maps_view_object_type_e type;
515         maps_view_object_get_type(object, &type);
516
517         if (type < MAPS_VIEW_OBJECT_POLYLINE || type > MAPS_VIEW_OBJECT_MARKER) return;
518         if (operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE) return;
519
520         const char *oper_str[20] = { "ADD", "SET_VISIBLE", "MOVE", "CHANGE", "REMOVE"};
521         const char *type_str[20] = { "POLYLINE", "POLYGON", "MARKER", "ROUTE", "UNKNOWN"};
522
523         MAPS_LOGD("type=%s, operation=%s, object=%p",
524                 (type >= MAPS_VIEW_OBJECT_POLYLINE && type <= MAPS_VIEW_OBJECT_MARKER) ? type_str[type] : "?",
525                 (operation >= MAPS_VIEW_OBJECT_ADD && operation <= MAPS_VIEW_OBJECT_REMOVE) ? oper_str[operation] : "?",
526                 object);
527
528         switch(operation)
529         {
530         case MAPS_VIEW_OBJECT_ADD:                              hv->__visualObjects.add(object); break;
531         case MAPS_VIEW_OBJECT_SET_VISIBLE:              hv->__visualObjects.setVisible(object); break;
532         case MAPS_VIEW_OBJECT_CHANGE:                   hv->__visualObjects.update(object); break;
533         case MAPS_VIEW_OBJECT_REMOVE:                   hv->__visualObjects.remove(object); break;
534         default:                        break;
535         }
536 }
537
538 here_error_e HereView::captureSnapshot(maps_view_h view, void **data, int *width, int *height,
539         maps_view_colorspace_type_e *cs)
540 {
541         if (!__isInitialized || !__map || __w <= 0 || __h <= 0)
542                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
543
544         int sizeOfLine = (__w * 4);
545         unsigned char *readData = (unsigned char*)malloc(sizeOfLine * __h);
546         if (!readData)
547                 return HERE_ERROR_OUT_OF_MEMORY;
548
549         *data = (void*)malloc(sizeOfLine * __h);
550         if (!*data) {
551                 free(readData);
552                 return HERE_ERROR_OUT_OF_MEMORY;
553         }
554
555         __pixelGetCb(view, NULL);
556         __api->glReadPixels(0, 0, __w, __h, GL_RGBA, GL_UNSIGNED_BYTE, readData);
557         for(int i = 0; i < __h; i++)
558                 memcpy((unsigned char*)*data + sizeOfLine * i, readData + sizeOfLine * (__h - i - 1), sizeOfLine);
559         free(readData);
560
561         *width = __w;
562         *height = __h;
563         *cs = MAPS_VIEW_COLORSPACE_RGBA8888;
564
565         return HERE_ERROR_NONE;
566 }
567
568 here_error_e HereView::getViewScale(maps_view_h view, double *scale)
569 {
570         if (!view || !scale)
571                 return HERE_ERROR_INVALID_PARAMETER;
572
573         if (!__isInitialized || !__map)
574                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
575
576         *scale = __map->GetScale();
577
578         return HERE_ERROR_NONE;
579 }
580
581 here_error_e HereView::setViewScale(maps_view_h view, double scale)
582 {
583         if (!view)
584                 return HERE_ERROR_INVALID_PARAMETER;
585
586         if (!__isInitialized || !__map)
587                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
588
589         __map->SetScale(scale);
590
591         return HERE_ERROR_NONE;
592 }
593
594 HERE_PLUGIN_END_NAMESPACE