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