f9c4d6eb9022f380971ee010d7df1f37b36333d2
[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 hView, maps_plugin_map_view_ready_cb pCbFunc)
60 {
61         if (!hView)
62                 return HERE_ERROR_INVALID_PARAMETER;
63
64         __idler = ecore_idler_add(__idlerCb, (void*)hView);
65
66         here_error_e error = HERE_ERROR_NONE;
67         int error2 = MAPS_ERROR_NONE;
68
69         do {
70                 error2 = maps_view_get_viewport(hView, &__img);
71                 if (error2 != MAPS_ERROR_NONE) break;
72
73                 error2 = maps_view_get_screen_location(hView, &__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(hView);
80                 if (error != HERE_ERROR_NONE) break;
81
82                 error = __initMap(hView, pCbFunc);
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 hView)
126 {
127         if (!hView || !__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, hView);
159         __isInitialized = true;
160
161         return HERE_ERROR_NONE;
162 }
163
164 here_error_e HereView::__initMap(maps_view_h hView,  maps_plugin_map_view_ready_cb pCbFunc)
165 {
166         if (!hView)
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 = pCbFunc;
174
175         __map->SetReadyMapSignal((GeoTiledMap::ReadyMapSignalFunctor)__readyMapCb, (void *)hView);
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 hView)
185 {
186         if (!hView)
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 hView)
254 {
255         if (!hView)
256                 return;
257
258         /* When the theme is changed, clear cache */
259         maps_view_type_e map_type;
260         maps_view_get_type(hView, &map_type);
261
262         bool buildings_enabled = false;
263         maps_view_get_buildings_enabled(hView, &buildings_enabled);
264
265         bool traffic_enabled = false;
266         maps_view_get_traffic_enabled(hView, &traffic_enabled);
267
268         bool public_transit_enabled = false;
269         maps_view_get_public_transit_enabled(hView, &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 hView, const maps_coordinates_h mapsCoord, double dZoom, double dAngle)
286 {
287         if (!hView || !mapsCoord)
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(hView);
295
296         /* resize window */
297         int x, y, w, h;
298         maps_view_get_screen_location(hView, &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         {
304                 __x = x;
305                 __y = y;
306                 __w = w;
307                 __h = h;
308
309                 __api->glViewport(0, 0, __w, __h);
310                 __map->SetMapSize(Dimension(__w,__h));
311                 __initOpenGLSurface(hView);
312         }
313
314         /* callback */
315         GeoTiledMap::UpdateMapSignalFunctor callback = std::tr1::bind(&__renderingCb, __img);
316         __map->SetUpdateMapSignal(callback);
317
318         /* zoom level */
319         if (__map->GetZoomLevel() != dZoom)
320         {
321                 __zoom = dZoom;
322                 __map->SetZoomLevel(dZoom, false);
323         }
324
325         /* angle */
326         if (__angle != dAngle) {
327                 __angle = dAngle;
328                 __map->SetAngle(dAngle);
329         }
330
331         /* center */
332         double lat, lng;
333         maps_coordinates_get_latitude(mapsCoord, &lat);
334         maps_coordinates_get_longitude(mapsCoord, &lng);
335
336         GeoCoordinates geoCoord(lat, lng);
337         __lat = lat;
338         __lng = lng;
339         __map->SetCenter(geoCoord);
340
341         return HERE_ERROR_NONE;
342 }
343
344 here_error_e HereView::RenderMapByArea(maps_view_h hView, const maps_area_h hArea, double dZoom, double dAngle)
345 {
346         if (!hView || !hArea)
347                 return HERE_ERROR_INVALID_PARAMETER;
348
349         if (!__isInitialized || !__map)
350                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
351
352         return HERE_ERROR_NONE;
353 }
354
355 here_error_e HereView::MoveCenter(maps_view_h hView, int delta_x, int delta_y)
356 {
357         if (!hView)
358                 return HERE_ERROR_INVALID_PARAMETER;
359
360         if (!__isInitialized || !__map)
361                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
362
363         if (delta_x == 0 && delta_y == 0)
364                 return HERE_ERROR_NONE;
365
366         __map->Pan(delta_x, delta_y);
367
368         return HERE_ERROR_NONE;
369 }
370
371 here_error_e HereView::GetCenter(maps_view_h hView, maps_coordinates_h *center)
372 {
373         if (!hView || !center)
374                 return HERE_ERROR_INVALID_PARAMETER;
375
376         if (!__isInitialized || !__map)
377                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
378
379         GeoCoordinates geoCoord = __map->GetCenter();
380         if (*center == NULL) {
381                 maps_coordinates_create(geoCoord.GetLatitude(), geoCoord.GetLongitude(), center);
382         } else {
383                 maps_coordinates_set_latitude(*center, geoCoord.GetLatitude());
384                 maps_coordinates_set_longitude(*center, geoCoord.GetLongitude());
385         }
386
387         return HERE_ERROR_NONE;
388 }
389
390 here_error_e HereView::SetScalebar(maps_view_h hView, bool enable)
391 {
392         if (!hView)
393                 return HERE_ERROR_INVALID_PARAMETER;
394
395         if (!__isInitialized || !__map)
396                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
397
398         __map->SetScalebar(enable);
399
400         return HERE_ERROR_NONE;
401 }
402
403 here_error_e HereView::GetScalebar(maps_view_h hView, bool *enabled)
404 {
405         if (!hView || !enabled)
406                 return HERE_ERROR_INVALID_PARAMETER;
407
408         if (!__isInitialized || !__map)
409                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
410
411         *enabled = __map->GetScalebar();
412         return HERE_ERROR_NONE;
413 }
414
415 here_error_e HereView::DrawMap(maps_view_h hView, Evas* pCanvas, int x, int y, int nWidth, int nHeight)
416 {
417         if (!hView || !pCanvas || nWidth <= 0 || nHeight <= 0)
418                 return HERE_ERROR_INVALID_PARAMETER;
419
420         if (!__isInitialized || !__map || !__map->GetRootPixmap() || !__api || __w <= 0 || __h <= 0)
421                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
422
423         unsigned char* srcimg_data = (unsigned char*)malloc(__w * __h * 4);
424         if (!srcimg_data)
425                 return HERE_ERROR_OUT_OF_MEMORY;
426
427         Evas_Object *dstimg = evas_object_image_filled_add(pCanvas);
428         if (!dstimg) {
429                 g_free(srcimg_data);
430                 return HERE_ERROR_INVALID_OPERATION;
431         }
432
433         unsigned char *dstimg_data = (unsigned char *)evas_object_image_data_get(dstimg, EINA_TRUE);
434         if (!dstimg_data) {
435                 g_free(srcimg_data);
436                 return HERE_ERROR_INVALID_OPERATION;
437         }
438
439         int w = nWidth;
440         int h = nHeight;
441
442         if (__w < w) w = __w;
443         if (__h < h) h = __h;
444
445         __api->glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, srcimg_data);
446
447         try {
448                 for(int i = 0; i < h; i++)
449                         memcpy(dstimg_data+(i*w), srcimg_data+(i * w + x), w * 4);
450         }
451         catch(std::exception &e) {
452                 MAPS_LOGD("Exception caught: %s", e.what());
453         }
454         g_free(srcimg_data);
455
456         return HERE_ERROR_NONE;
457 }
458
459 here_error_e HereView::ScreenToGeolocation(maps_view_h hView, int x, int y, maps_coordinates_h *mapsCoord)
460 {
461         if (!hView || !mapsCoord)
462                 return HERE_ERROR_INVALID_PARAMETER;
463
464         if (!__isInitialized || !__map)
465                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
466
467         Tizen::Maps::Point mapsPoint(x, y);
468         GeoCoordinates hereCoord = __map->ScreenPositionToCoordinate(mapsPoint);
469         double lat = hereCoord.GetLatitude();
470         double lng = hereCoord.GetLongitude();
471
472         int error = maps_coordinates_create(lat, lng, mapsCoord);
473         if (error != MAPS_ERROR_NONE)
474                 return (here_error_e)ConvertToHereError(error);
475
476         return HERE_ERROR_NONE;
477 }
478
479 here_error_e HereView::GeolocationToScreen(maps_view_h hView, const maps_coordinates_h mapsCoord, int *x, int *y)
480 {
481         if (!hView || !x || !y)
482                 return HERE_ERROR_INVALID_PARAMETER;
483
484         if (!__isInitialized || !__map)
485                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
486
487         double lat, lng;
488         maps_coordinates_get_latitude(mapsCoord, &lat);
489         maps_coordinates_get_longitude(mapsCoord, &lng);
490         GeoCoordinates hereCoord(lat, lng);
491         Tizen::Maps::Point mapsPoint = __map->CoordinateToScreenPosition(hereCoord);
492
493         *x = mapsPoint.x;
494         *y = mapsPoint.y;
495
496         return HERE_ERROR_NONE;
497 }
498
499 here_error_e HereView::GetMinZoomLevel(maps_view_h hView, int *nMinZoomLevel)
500 {
501         if (!hView || !nMinZoomLevel)
502                 return HERE_ERROR_INVALID_PARAMETER;
503
504         if (!__isInitialized || !__map)
505                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
506
507         *nMinZoomLevel = (int)__map->GetMinimumZoomLevel();
508
509         return HERE_ERROR_NONE;
510 }
511
512 here_error_e HereView::GetMaxZoomLevel(maps_view_h hView, int *nMaxZoomLevel)
513 {
514         if (!hView || !nMaxZoomLevel)
515                 return HERE_ERROR_INVALID_PARAMETER;
516
517         if (!__isInitialized || !__map)
518                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
519
520         *nMaxZoomLevel = (int)__map->GetMaximumZoomLevel();
521
522         return HERE_ERROR_NONE;
523 }
524
525 here_error_e HereView::OnViewObject(maps_view_h hView, const maps_view_object_h object, maps_view_object_operation_e operation)
526 {
527         if (!hView || !object ||
528                 operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE)
529                 return HERE_ERROR_INVALID_PARAMETER;
530
531         if (!__isInitialized || !__map)
532                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
533
534         if (__map->GetRootPixmap())
535                 __processViewObject(hView, object, operation);
536         else
537                 __pendingObjects.push_back(std::make_pair(object, operation));
538
539         return HERE_ERROR_NONE;
540 }
541
542 Eina_Bool HereView::__idlerCb(void *data)
543 {
544         HereView *hv = NULL;
545         int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&hv);
546         if (maps_error != MAPS_ERROR_NONE || !hv) return true;
547         if (!hv->__map || !hv->__map->GetRootPixmap()) return true;
548
549         while (hv->__pendingObjects.size()) {
550                 PendingObject pending = hv->__pendingObjects.front();
551                 hv->__pendingObjects.pop_front();
552                 maps_view_object_h object = pending.first;
553                 maps_view_object_operation_e operation = pending.second;
554
555                 __processViewObject(data, object, operation);
556         }
557         return true;
558 }
559
560 void HereView::__processViewObject(maps_view_h hView, const maps_view_object_h object, maps_view_object_operation_e operation)
561 {
562         HereView *hv = NULL;
563         int maps_error = maps_view_get_maps_plugin_view_handle(hView, (void**)&hv);
564         if (maps_error != MAPS_ERROR_NONE || !hv) return;
565
566         maps_view_object_type_e type;
567         maps_view_object_get_type(object, &type);
568
569         if (type < MAPS_VIEW_OBJECT_POLYLINE || type > MAPS_VIEW_OBJECT_MARKER) return;
570         if (operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE) return;
571
572         const char *oper_str[20] = { "ADD", "SET_VISIBLE", "MOVE", "CHANGE", "REMOVE"};
573         const char *type_str[20] = { "POLYLINE", "POLYGON", "MARKER", "ROUTE", "UNKNOWN"};
574
575         MAPS_LOGD("type=%s, operation=%s, object=%p",
576                 (type >= MAPS_VIEW_OBJECT_POLYLINE && type <= MAPS_VIEW_OBJECT_MARKER) ? type_str[type] : "?",
577                 (operation >= MAPS_VIEW_OBJECT_ADD && operation <= MAPS_VIEW_OBJECT_REMOVE) ? oper_str[operation] : "?",
578                 object);
579
580         switch(operation)
581         {
582         case MAPS_VIEW_OBJECT_ADD:                              hv->__visualObjects.add(object); break;
583         case MAPS_VIEW_OBJECT_SET_VISIBLE:              hv->__visualObjects.setVisible(object); break;
584         case MAPS_VIEW_OBJECT_CHANGE:                   hv->__visualObjects.update(object); break;
585         case MAPS_VIEW_OBJECT_REMOVE:                   hv->__visualObjects.remove(object); break;
586         default:                        break;
587         }
588 }
589
590 HERE_PLUGIN_END_NAMESPACE